//go:build linux && rootrunner package host import ( "bytes" "context" "encoding/base64" "encoding/json" "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/hostfloor" "github.com/carlosframework/platform/internal/release" ) // Fix round 1, I2, as real root: a box with a root participation census // (leo's kind) and an unarmed guard, updated from v1.3.0 to v1.4.0 by the // real apply on the census branch, then armed for guard-arm by // install-channel --policy on that same branch. The release before is // replaced, carlos.prev's record names the release, the identity is kept, // and the root moves floor's judgement ran over the new carlos.prev. func TestRootInstallChannelPolicyCensusBox(t *testing.T) { scratch := generationRootRunnerDir(t) t.Setenv("TMPDIR", scratch) f := &channelFixture{applyFixture: newApplyFixture(t, "stable", "v1.3.0")} for _, dir := range []string{f.a.optDir, f.a.dataDir, f.a.etcDir} { for path := dir; path != scratch && path != "/" && path != filepath.Dir(scratch); path = filepath.Dir(path) { if err := os.Chmod(path, 0755); err != nil { t.Fatal(err) } } } t.Setenv("CARLOS_RELEASE_PUBKEY", base64.StdEncoding.EncodeToString(f.pub)) t.Setenv("CARLOS_DEPLOYMENT_BUCKET", "bucket") id := rootFloorIdentity{Deployment: "bucket", Box: "box", Enrollment: "en"} f.a.rootMoves = func() (rootFloorIdentity, bool, error) { return id, true, nil } old := []byte("#!/bin/sh\necho carlos v1.3.0\n") rootFloorSignRunnerBytes(t, f.a.optDir, systemBinaryPath(f.a.optDir), "v1.3.0", old, f.priv) f.body = []byte("#!/bin/sh\necho carlos v1.4.0\n") applyChannelUpdate(t, f, "v1.4.0", f.body, true) if cur, prev := f.slots(t); !bytes.Equal(cur, f.body) || !bytes.Equal(prev, old) { t.Fatalf("the census update left %q and %q", cur, prev) } f.in = channelInstall{a: f.a, bucket: "bucket", fetchTo: func(ctx context.Context, s release.Store, key, dst, sha string) error { f.fetches++ return release.FetchToFile(ctx, s, key, dst, systemArtifactLimit, sha) }, own: func(string) error { return nil }} f.in.policy = signedPolicy(t, f.priv, "bucket", hostfloor.Floor{Min: 1, MinRelease: "v1.4.0"}) f.in.identity = f.identityOf(t, "v1.4.0") got, err := f.in.run(context.Background()) if err != nil || !got.Replaced { t.Fatalf("install-channel --policy on a census box: %+v %v", got, err) } if cur, prev := f.slots(t); !bytes.Equal(cur, f.body) || !bytes.Equal(prev, f.body) || !prevRecorded(f.a.optDir, "v1.4.0") || f.fetches != 0 { t.Fatalf("slots %q %q", cur, prev) } key, _ := release.IdentityKey("v1.4.0") published, _, err := f.store.Get(context.Background(), key) if err != nil { t.Fatal(err) } if held, err := os.ReadFile(channelIdentityPath(f.a.optDir)); err != nil || !bytes.Equal(held, published) { t.Fatal("identity", err) } floors, err := openRootMovesFloors(f.a.optDir, id, false) if err != nil { t.Fatal("the census box's root floor state", err) } defer floors.close() raw, err := floors.public.Read("prev.json") if err != nil { t.Fatal("the root moves floor did not judge the new carlos.prev", err) } var verdict rootFloorVerdict if err := json.Unmarshal(raw, &verdict); err != nil || verdict.Identity != id || verdict.PrevAbsent || verdict.Prev.Version != "v1.4.0" || verdict.Prev.Digest != hostfloor.Digest(f.body) { t.Fatalf("the judgement is not of the replaced carlos.prev (v1.4.0): %s %v", raw, err) } if again, err := f.in.run(context.Background()); err != nil || !again.Already { t.Fatalf("rerun %+v %v", again, err) } t.Log("PASS install-channel --policy on a census box: root moves branch, mandatory record, identity kept") }