package host import ( "context" "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/moves" "github.com/carlosframework/platform/internal/rootstate" ) // The disk implementation and privileged suite repeat this matrix using checked // rootstate descriptors. This suite keeps every write boundary runnable in CI. func TestPlan14RootFloorCrashOrdering(t *testing.T) { for _, after := range []bool{false, true} { for fail := 1; fail <= 5; fail++ { private := &rollbackMemory{files: map[string][]byte{}} public := &rollbackMemory{files: map[string][]byte{}} f := rootMovesFloors{private: private, public: public, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}} a := moves.Floor{Min: 1, MinRelease: "v1.0.0"} b := moves.Floor{Min: 2, MinRelease: "v2.0.0"} if err := f.reconstruct(context.Background(), rootFloorReconstruction{Identity: f.identity, Floor: &a, Source: "complete root history", Digest: floorTestDigest, Authorization: floorTestAuthorization(t, f)}); err != nil { t.Fatal(err) } n := 0 wrap := func(s rootstate.Store) rootstate.Store { return &floorFaultStore{Store: s, n: &n, fail: fail, after: after} } broken := f broken.private, broken.public = wrap(private), wrap(public) if err := broken.refresh(context.Background(), &b, nil, nil); err == nil { t.Fatalf("boundary %d after=%v succeeded", fail, after) } // No failed transaction may advertise its new accepted generation. if p, err := f.projection(); err == nil && p.Floor != nil && *p.Floor == b { t.Fatalf("boundary %d after=%v acknowledged B", fail, after) } // A visible stricter selector must not be overwritten by a weaker retry. bound, _ := f.bound() if bound != nil && *bound == b { if err := f.refresh(context.Background(), &a, nil, nil); err == nil { t.Fatal("regression accepted after interrupted rise") } } if err := f.refresh(context.Background(), &b, nil, nil); err != nil { t.Fatalf("retry %d/%v: %v", fail, after, err) } p, err := f.projection() if err != nil || p.Floor == nil || *p.Floor != b { t.Fatal("retry did not durably accept B", p, err) } } } } const floorTestDigest = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" type floorFaultStore struct { rootstate.Store n *int fail int after bool } func (s *floorFaultStore) Write(name string, raw []byte) error { *s.n++ if *s.n == s.fail && !s.after { return os.ErrInvalid } err := s.Store.Write(name, raw) if *s.n == s.fail && s.after { return os.ErrInvalid } return err } func TestPlan14RootFloorReconstructionAuthority(t *testing.T) { a := moves.Floor{Min: 1, MinRelease: "v1.0.0"} b := moves.Floor{Min: 2, MinRelease: "v2.0.0"} for _, tc := range []string{"unknown", "legacy", "corrupt", "deleted", "regressed", "stronger legacy", "never armed", "wrong identity"} { t.Run(tc, func(t *testing.T) { f := rootMovesFloors{private: &rollbackMemory{files: map[string][]byte{}}, public: &rollbackMemory{files: map[string][]byte{}}, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}} if tc == "unknown" || tc == "legacy" { var legacy []*moves.Floor if tc == "legacy" { legacy = []*moves.Floor{&b} } if f.refresh(t.Context(), &a, legacy, nil) != nil { t.Fatal("unknown history blocked refresh") } if _, err := f.projection(); err == nil { t.Fatal("unknown history advertised") } if tc == "legacy" { got, _ := f.bound() if got == nil || *got != a { t.Fatal("uncapped legacy deny", got) } } return } r := rootFloorReconstruction{Identity: f.identity, Floor: &b, Source: "complete history", Digest: floorTestDigest, Authorization: floorTestAuthorization(t, f)} if tc == "never armed" { r.Floor = nil r.NeverArmed = true } if tc == "wrong identity" { r.Identity.Enrollment = "other" if f.reconstruct(t.Context(), r) == nil { t.Fatal("foreign reconstruction") } return } if err := f.reconstruct(t.Context(), r); err != nil { t.Fatal(err) } var remote *moves.Floor var legacy []*moves.Floor var legacyErr error switch tc { case "corrupt": remote = &a legacyErr = os.ErrInvalid case "regressed": remote = &a case "stronger legacy": legacy = []*moves.Floor{{Min: 3, MinRelease: "v1.0.0"}} remote = &b case "never armed": remote = &a } err := f.refresh(t.Context(), remote, legacy, legacyErr) bad := tc == "corrupt" || tc == "regressed" if (err != nil) != bad { t.Fatal(err) } if bad { if _, err := f.projection(); err == nil { t.Fatal("quarantine advertised") } } if tc == "deleted" { got, e := f.bound() if e != nil || got == nil || *got != b { t.Fatal(got, e) } } if tc == "never armed" { p, e := f.projection() if e != nil || p.Floor == nil || *p.Floor != a { t.Fatal(p, e) } } }) } } func TestPlan14RootFloorLegacyIsDenyOnly(t *testing.T) { for _, body := range []string{`{"min":2,"min_release":"v2.0.0"} {}`, `{"min":2,"min_release":"v2.0.0","reset":true}`, `broken`} { dd := t.TempDir() dir := filepath.Join(dd, ".moves") if err := os.Mkdir(dir, 0755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "floor.json"), []byte(body), 0644); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "floor.min-release"), []byte("v3.0.0\n"), 0644); err != nil { t.Fatal(err) } legacy, err := rootFloorLegacy(dd) if err == nil { t.Fatal("malformed mirror was not quarantined", body) } max := (*moves.Floor)(nil) for _, fl := range legacy { max = floorMaximum(max, fl) } if max == nil || max.MinRelease != "v3.0.0" { t.Fatal("usable deny disappeared", max) } } } func floorTestAuthorization(t *testing.T, f rootMovesFloors) *rootFloorAuthorization { t.Helper() token, err := f.authorizeReconstruction(t.Context()) if err != nil { t.Fatal(err) } return token } func TestPlan14RootFloorReconstructionToken(t *testing.T) { f := rootMovesFloors{private: &rollbackMemory{files: map[string][]byte{}}, public: &rollbackMemory{files: map[string][]byte{}}, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}} token := floorTestAuthorization(t, f) for _, kind := range []string{"missing", "box", "generation", "nonce"} { changed := *token r := rootFloorReconstruction{Identity: f.identity, NeverArmed: true, Source: "root history", Digest: floorTestDigest, Authorization: &changed} switch kind { case "missing": r.Authorization = nil case "box": changed.Identity.Box = "other" case "generation": changed.Generation++ case "nonce": changed.Nonce = floorTestDigest } if f.reconstruct(t.Context(), r) == nil { t.Fatal("accepted", kind) } } if err := f.reconstruct(t.Context(), rootFloorReconstruction{Identity: f.identity, NeverArmed: true, Source: "root history", Digest: floorTestDigest, Authorization: token}); err != nil { t.Fatal(err) } } func TestPlan14RootFloorUnknownHistoryRetainsDenies(t *testing.T) { f := rootMovesFloors{private: &rollbackMemory{files: map[string][]byte{}}, public: &rollbackMemory{files: map[string][]byte{}}, identity: rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"}} good := rootFloorBinary{Version: "v3.0.0", Protocol: 0, Digest: floorTestDigest} j := rootFloorJudge{floors: f, current: "current", prev: "prev", binary: func(string) (rootFloorBinary, error) { return good, nil }} selectCurrent := func() { t.Helper() got, err := rootFloorBootCandidate(t.Context(), j, false, nil, nil) if err != nil || got != "current" { t.Fatal("unknown signed candidate refused", got, err) } } selectCurrent() good.Protocol = 2 bound := moves.Floor{Min: 2, MinRelease: "v2.0.0"} if err := f.refresh(t.Context(), nil, []*moves.Floor{&bound}, os.ErrNotExist); err != nil { t.Fatal(err) } if _, err := f.projection(); err == nil { t.Fatal("unknown became accepted") } selectCurrent() good.Version = "v1.0.0" selectCurrent() good.Version = "v3.0.0" if err := f.private.Write(rootFloorAccepted, []byte("corrupt")); err != nil { t.Fatal(err) } selectCurrent() good.Version = "v1.0.0" selectCurrent() } func TestPlan14RootFloorPublicDenySurvivesPrivateLoss(t *testing.T) { id := rootFloorIdentity{Deployment: "deploy", Box: "box", Enrollment: "en"} public := &rollbackMemory{files: map[string][]byte{}} f := rootMovesFloors{public: public, identity: id} floor := moves.Floor{Min: 2, MinRelease: "v2.0.0"} if err := public.Write(rootFloorSelector, rootFloorLine(&floor)); err != nil { t.Fatal(err) } got, err := f.localBound() if err != nil || got == nil || *got != floor { t.Fatal("public deny lost", got, err) } }