carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5 "os"
6 "path/filepath"
7 "testing"
8
9 "github.com/carlosframework/platform/internal/moves"
10 "github.com/carlosframework/platform/internal/rootstate"
11)
12
13// The disk implementation and privileged suite repeat this matrix using checked
14// rootstate descriptors. This suite keeps every write boundary runnable in CI.
15func TestPlan14RootFloorCrashOrdering(t *testing.T) {
16 for _, after := range []bool{false, true} {
17 for fail := 1; fail <= 5; fail++ {
18 private := &rollbackMemory{files: map[string][]byte{}}
19 public := &rollbackMemory{files: map[string][]byte{}}
20 f := rootMovesFloors{private: private, public: public, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}}
21 a := moves.Floor{Min: 1, MinRelease: "v1.0.0"}
22 b := moves.Floor{Min: 2, MinRelease: "v2.0.0"}
23 if err := f.reconstruct(context.Background(), rootFloorReconstruction{Identity: f.identity, Floor: &a, Source: "complete root history", Digest: floorTestDigest, Authorization: floorTestAuthorization(t, f)}); err != nil {
24 t.Fatal(err)
25 }
26 n := 0
27 wrap := func(s rootstate.Store) rootstate.Store {
28 return &floorFaultStore{Store: s, n: &n, fail: fail, after: after}
29 }
30 broken := f
31 broken.private, broken.public = wrap(private), wrap(public)
32 if err := broken.refresh(context.Background(), &b, nil, nil); err == nil {
33 t.Fatalf("boundary %d after=%v succeeded", fail, after)
34 }
35 // No failed transaction may advertise its new accepted generation.
36 if p, err := f.projection(); err == nil && p.Floor != nil && *p.Floor == b {
37 t.Fatalf("boundary %d after=%v acknowledged B", fail, after)
38 }
39 // A visible stricter selector must not be overwritten by a weaker retry.
40 bound, _ := f.bound()
41 if bound != nil && *bound == b {
42 if err := f.refresh(context.Background(), &a, nil, nil); err == nil {
43 t.Fatal("regression accepted after interrupted rise")
44 }
45 }
46 if err := f.refresh(context.Background(), &b, nil, nil); err != nil {
47 t.Fatalf("retry %d/%v: %v", fail, after, err)
48 }
49 p, err := f.projection()
50 if err != nil || p.Floor == nil || *p.Floor != b {
51 t.Fatal("retry did not durably accept B", p, err)
52 }
53 }
54 }
55}
56
57const floorTestDigest = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
58
59type floorFaultStore struct {
60 rootstate.Store
61 n *int
62 fail int
63 after bool
64}
65
66func (s *floorFaultStore) Write(name string, raw []byte) error {
67 *s.n++
68 if *s.n == s.fail && !s.after {
69 return os.ErrInvalid
70 }
71 err := s.Store.Write(name, raw)
72 if *s.n == s.fail && s.after {
73 return os.ErrInvalid
74 }
75 return err
76}
77
78func TestPlan14RootFloorReconstructionAuthority(t *testing.T) {
79 a := moves.Floor{Min: 1, MinRelease: "v1.0.0"}
80 b := moves.Floor{Min: 2, MinRelease: "v2.0.0"}
81 for _, tc := range []string{"unknown", "legacy", "corrupt", "deleted", "regressed", "stronger legacy", "never armed", "wrong identity"} {
82 t.Run(tc, func(t *testing.T) {
83 f := rootMovesFloors{private: &rollbackMemory{files: map[string][]byte{}}, public: &rollbackMemory{files: map[string][]byte{}}, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}}
84 if tc == "unknown" || tc == "legacy" {
85 var legacy []*moves.Floor
86 if tc == "legacy" {
87 legacy = []*moves.Floor{&b}
88 }
89 if f.refresh(t.Context(), &a, legacy, nil) != nil {
90 t.Fatal("unknown history blocked refresh")
91 }
92 if _, err := f.projection(); err == nil {
93 t.Fatal("unknown history advertised")
94 }
95 if tc == "legacy" {
96 got, _ := f.bound()
97 if got == nil || *got != a {
98 t.Fatal("uncapped legacy deny", got)
99 }
100 }
101 return
102 }
103 r := rootFloorReconstruction{Identity: f.identity, Floor: &b, Source: "complete history", Digest: floorTestDigest, Authorization: floorTestAuthorization(t, f)}
104 if tc == "never armed" {
105 r.Floor = nil
106 r.NeverArmed = true
107 }
108 if tc == "wrong identity" {
109 r.Identity.Enrollment = "other"
110 if f.reconstruct(t.Context(), r) == nil {
111 t.Fatal("foreign reconstruction")
112 }
113 return
114 }
115 if err := f.reconstruct(t.Context(), r); err != nil {
116 t.Fatal(err)
117 }
118 var remote *moves.Floor
119 var legacy []*moves.Floor
120 var legacyErr error
121 switch tc {
122 case "corrupt":
123 remote = &a
124 legacyErr = os.ErrInvalid
125 case "regressed":
126 remote = &a
127 case "stronger legacy":
128 legacy = []*moves.Floor{{Min: 3, MinRelease: "v1.0.0"}}
129 remote = &b
130 case "never armed":
131 remote = &a
132 }
133 err := f.refresh(t.Context(), remote, legacy, legacyErr)
134 bad := tc == "corrupt" || tc == "regressed"
135 if (err != nil) != bad {
136 t.Fatal(err)
137 }
138 if bad {
139 if _, err := f.projection(); err == nil {
140 t.Fatal("quarantine advertised")
141 }
142 }
143 if tc == "deleted" {
144 got, e := f.bound()
145 if e != nil || got == nil || *got != b {
146 t.Fatal(got, e)
147 }
148 }
149 if tc == "never armed" {
150 p, e := f.projection()
151 if e != nil || p.Floor == nil || *p.Floor != a {
152 t.Fatal(p, e)
153 }
154 }
155 })
156 }
157}
158
159func TestPlan14RootFloorLegacyIsDenyOnly(t *testing.T) {
160 for _, body := range []string{`{"min":2,"min_release":"v2.0.0"} {}`, `{"min":2,"min_release":"v2.0.0","reset":true}`, `broken`} {
161 dd := t.TempDir()
162 dir := filepath.Join(dd, ".moves")
163 if err := os.Mkdir(dir, 0755); err != nil {
164 t.Fatal(err)
165 }
166 if err := os.WriteFile(filepath.Join(dir, "floor.json"), []byte(body), 0644); err != nil {
167 t.Fatal(err)
168 }
169 if err := os.WriteFile(filepath.Join(dir, "floor.min-release"), []byte("v3.0.0\n"), 0644); err != nil {
170 t.Fatal(err)
171 }
172 legacy, err := rootFloorLegacy(dd)
173 if err == nil {
174 t.Fatal("malformed mirror was not quarantined", body)
175 }
176 max := (*moves.Floor)(nil)
177 for _, fl := range legacy {
178 max = floorMaximum(max, fl)
179 }
180 if max == nil || max.MinRelease != "v3.0.0" {
181 t.Fatal("usable deny disappeared", max)
182 }
183 }
184}
185
186func floorTestAuthorization(t *testing.T, f rootMovesFloors) *rootFloorAuthorization {
187 t.Helper()
188 token, err := f.authorizeReconstruction(t.Context())
189 if err != nil {
190 t.Fatal(err)
191 }
192 return token
193}
194
195func TestPlan14RootFloorReconstructionToken(t *testing.T) {
196 f := rootMovesFloors{private: &rollbackMemory{files: map[string][]byte{}}, public: &rollbackMemory{files: map[string][]byte{}}, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}}
197 token := floorTestAuthorization(t, f)
198 for _, kind := range []string{"missing", "box", "generation", "nonce"} {
199 changed := *token
200 r := rootFloorReconstruction{Identity: f.identity, NeverArmed: true, Source: "root history", Digest: floorTestDigest, Authorization: &changed}
201 switch kind {
202 case "missing":
203 r.Authorization = nil
204 case "box":
205 changed.Identity.Box = "other"
206 case "generation":
207 changed.Generation++
208 case "nonce":
209 changed.Nonce = floorTestDigest
210 }
211 if f.reconstruct(t.Context(), r) == nil {
212 t.Fatal("accepted", kind)
213 }
214 }
215 if err := f.reconstruct(t.Context(), rootFloorReconstruction{Identity: f.identity, NeverArmed: true, Source: "root history", Digest: floorTestDigest, Authorization: token}); err != nil {
216 t.Fatal(err)
217 }
218}
219
220func TestPlan14RootFloorUnknownHistoryRetainsDenies(t *testing.T) {
221 f := rootMovesFloors{private: &rollbackMemory{files: map[string][]byte{}}, public: &rollbackMemory{files: map[string][]byte{}}, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}}
222 good := rootFloorBinary{Version: "v3.0.0", Protocol: 0, Digest: floorTestDigest}
223 j := rootFloorJudge{floors: f, current: "current", prev: "prev", binary: func(string) (rootFloorBinary, error) { return good, nil }}
224 selectCurrent := func() {
225 t.Helper()
226 got, err := rootFloorBootCandidate(t.Context(), j, false, nil, nil)
227 if err != nil || got != "current" {
228 t.Fatal("unknown signed candidate refused", got, err)
229 }
230 }
231 selectCurrent()
232 good.Protocol = 2
233 bound := moves.Floor{Min: 2, MinRelease: "v2.0.0"}
234 if err := f.refresh(t.Context(), nil, []*moves.Floor{&bound}, os.ErrNotExist); err != nil {
235 t.Fatal(err)
236 }
237 if _, err := f.projection(); err == nil {
238 t.Fatal("unknown became accepted")
239 }
240 selectCurrent()
241 good.Version = "v1.0.0"
242 selectCurrent()
243 good.Version = "v3.0.0"
244 if err := f.private.Write(rootFloorAccepted, []byte("corrupt")); err != nil {
245 t.Fatal(err)
246 }
247 selectCurrent()
248 good.Version = "v1.0.0"
249 selectCurrent()
250}
251
252func TestPlan14RootFloorPublicDenySurvivesPrivateLoss(t *testing.T) {
253 id := rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}
254 public := &rollbackMemory{files: map[string][]byte{}}
255 f := rootMovesFloors{public: public, identity: id}
256 floor := moves.Floor{Min: 2, MinRelease: "v2.0.0"}
257 if err := public.Write(rootFloorSelector, rootFloorLine(&floor)); err != nil {
258 t.Fatal(err)
259 }
260 got, err := f.localBound()
261 if err != nil || got == nil || *got != floor {
262 t.Fatal("public deny lost", got, err)
263 }
264}
265