settings-2: reconcile with main (held-stage authorization on the claim path)
Main's MaterializeHeldUnder (moves Plan 3 Task 5) is a new held staging entry point. The merge routes it through stageHeld, so HeldAuthorized answers first and the stage binds its digest. This pins it: a never-promoted build is ErrHeldNotAuthorized and a replayed record over other bytes is ErrManifestDigest, with no artifact read, nothing staged, no selection entered and live/<host> untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+74
−0
internal/release/materializeheld_claim_test.go+74 −0
CI passed — run details
diff --git a/internal/release/materializeheld_claim_test.go b/internal/release/materializeheld_claim_test.go| index 2119b14d4..0601dcafe 100644 |
| --- a/internal/release/materializeheld_claim_test.go |
| +++ b/internal/release/materializeheld_claim_test.go |
| @@ -3,6 +3,8 @@ package release |
| import ( |
| "context" |
| "errors" |
| + "os" |
| + "strings" |
| "testing" |
| "github.com/carlosframework/platform/internal/hostwrite" |
| @@ -69,3 +71,75 @@ func TestMaterializeHeldUnderRefusals(t *testing.T) { |
| t.Fatal("a row no move holds was staged") |
| } |
| } |
| + |
| +// Settings spec rev 11 §4.3a on the claim path: MaterializeHeldUnder stages |
| +// only a build a promotion record or a ratchet-admitted pointer authorizes, |
| +// bound to that digest. A build nothing authorizes, or a replayed record over |
| +// other bytes under the same name, is refused before an artifact byte is read |
| +// or written: nothing staged, no selection entered, live/<host> untouched. |
| +func TestMaterializeHeldUnderStagesOnlyAnAuthorizedBuild(t *testing.T) { |
| + t.Run("nothing authorizes it", func(t *testing.T) { |
| + ctx, s, opt := heldFixture(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + shipRelease(t, s, "bab", "console", "v3", adoptPlatform, []byte("shipped, never promoted")) |
| + rec := &heldRecordingStore{Store: s} |
| + work := &heldClaimWork{} |
| + if _, err := MaterializeHeldUnder(ctx, rec, heldPub, nr(t), opt, heldRoute(), "v3", offGate(t), work, nil); !errors.Is(err, ErrHeldNotAuthorized) { |
| + t.Fatalf("MaterializeHeldUnder of a never-promoted build = %v; want ErrHeldNotAuthorized", err) |
| + } |
| + heldClaimNothingStaged(t, rec, work, opt, "v3", false) |
| + }) |
| + t.Run("a replayed record over other bytes", func(t *testing.T) { |
| + ctx, s, opt := heldFixture(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + saved, _, err := s.Get(ctx, PromotionRecordKey("bab", "console", "v1")) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := DeleteVersion(ctx, s, "bab", "console", "v1"); err != nil { |
| + t.Fatal(err) |
| + } |
| + shipRelease(t, s, "bab", "console", "v1", adoptPlatform, []byte("nobody promoted these")) |
| + if _, err := s.Put(ctx, PromotionRecordKey("bab", "console", "v1"), saved, ""); err != nil { |
| + t.Fatal(err) |
| + } |
| + rec := &heldRecordingStore{Store: s} |
| + work := &heldClaimWork{} |
| + if _, err := MaterializeHeldUnder(ctx, rec, heldPub, nr(t), opt, heldRoute(), "v1", offGate(t), work, nil); !errors.Is(err, ErrManifestDigest) { |
| + t.Fatalf("MaterializeHeldUnder under a replayed record = %v; want ErrManifestDigest", err) |
| + } |
| + heldClaimNothingStaged(t, rec, work, opt, "v1", true) |
| + }) |
| +} |
| + |
| +// heldClaimNothingStaged fails the test if a claim-path held stage of version |
| +// read its artifact, staged it, entered the selection or pointed live/<host>. |
| +// manifestRead says whether the stage was allowed to read the manifest (to |
| +// check a digest) before refusing. |
| +func heldClaimNothingStaged(t *testing.T, rec *heldRecordingStore, work *heldClaimWork, opt, version string, manifestRead bool) { |
| + t.Helper() |
| + rel := ReleasesPrefix("bab", "console") + version + "/" |
| + manifest := ManifestKey("bab", "console", version) |
| + rec.mu.Lock() |
| + for _, c := range rec.calls { |
| + key, ok := strings.CutPrefix(c, "get ") |
| + if !ok || !strings.HasPrefix(key, rel) { |
| + continue |
| + } |
| + if manifestRead && key == manifest { |
| + continue |
| + } |
| + rec.mu.Unlock() |
| + t.Fatalf("the refused held stage read %s", key) |
| + } |
| + rec.mu.Unlock() |
| + if _, err := os.Stat(VersionPath(opt, "bab", version, "console")); err == nil { |
| + t.Fatalf("%s was staged", version) |
| + } |
| + if len(work.ids) != 0 { |
| + t.Fatalf("the refused held stage entered the selection under %v", work.ids) |
| + } |
| + if got, _ := LiveVersion(opt, heldTestHost); got != "" { |
| + t.Fatalf("live/<host> names %q", got) |
| + } |
| +} |