package hostactors import ( "context" "crypto/ed25519" "encoding/json" "strings" "testing" "time" "github.com/carlosframework/platform/internal/release" ) func TestPlan9BindCensusKeyRequiresPublishedFloorAndActiveEnrollment(t *testing.T) { for _, tc := range []string{"published-active", "unpublished", "preparing", "floor-mismatch", "quarantined", "retired", "fenced", "fence-unreadable", "stale-observed", "forged-observed"} { t.Run(tc, func(t *testing.T) { ctx := context.Background() w, _ := plan9Fixture(t, func(r *Roster) { r.Activations = map[string]Reservation{} switch tc { case "unpublished": r.Publication, r.FloorSHA256 = "", "" case "preparing": r.Publication = "preparing" case "floor-mismatch": r.FloorSHA256 = strings.Repeat("f", 64) case "quarantined": plan9Quarantine(r, "b", "loss-b") case "retired": plan9Quarantine(r, "b", "loss-b") b := r.Boxes["b"] b.State = "retired" r.Boxes["b"] = b } }) base := w.d.Store switch tc { case "fenced": w.fence(t, "b", "w", w.now.Add(-time.Minute), "terminated") case "fence-unreadable": w.d.Store = brokenFenceStore{w.d.Store} } before, err := w.d.Read(ctx) if err != nil { t.Fatal(err) } pub, key, err := ed25519.GenerateKey(nil) if err != nil { t.Fatal(err) } binding := CensusKeyBinding{Bucket: "bucket", Box: "b", Enrollment: before.Roster.Boxes["b"].Enrollment, PublicKey: pub} raw, err := json.Marshal(binding) if err != nil { t.Fatal(err) } input := before switch tc { case "stale-observed": // A concurrent writer moved the roster after the caller read it. next := Clone(before.Roster) next.RequestLimitNS = 120000000000 if _, err := w.d.Replace(ctx, w.sg, before, next); err != nil { t.Fatal(err) } case "forged-observed": // The caller's copy claims b is active while the signed roster // says otherwise; only the signed roster decides. o, err := w.d.Read(ctx) if err != nil { t.Fatal(err) } r := Clone(o.Roster) plan9Quarantine(&r, "b", "loss-b") signed, err := release.SignRootEnvelope(w.sg, r) if err != nil { t.Fatal(err) } etag, err := w.d.Store.Put(ctx, Key, signed, o.ETag) if err != nil { t.Fatal(err) } input = Observed{Roster: before.Roster, ETag: etag} } got, err := w.d.BindCensusKey(ctx, w.sg, input, binding, ed25519.Sign(key, raw)) if tc == "published-active" { if err != nil || !ed25519.PublicKey(got.Roster.Boxes["b"].CensusPublicKey).Equal(pub) { t.Fatalf("bind = %v", err) } return } if err == nil { t.Fatalf("%s: census key bound", tc) } after, readErr := (Directory{Store: base, PublicKey: w.d.PublicKey, Bucket: "bucket"}).Read(ctx) if readErr != nil { t.Fatal(readErr) } if len(after.Roster.Boxes["b"].CensusPublicKey) != 0 { t.Fatalf("%s: census key written despite refusal", tc) } }) } }