| index 0601dcafe..b0ec5b9a1 100644 |
| --- a/internal/release/materializeheld_claim_test.go |
| +++ b/internal/release/materializeheld_claim_test.go |
| @@ -5,6 +5,7 @@ import ( |
| "errors" |
| "os" |
| "strings" |
| + "syscall" |
| "testing" |
| |
| "github.com/carlosframework/platform/internal/hostwrite" |
| @@ -143,3 +144,111 @@ func heldClaimNothingStaged(t *testing.T, rec *heldRecordingStore, work *heldCla |
| t.Fatalf("live/<host> names %q", got) |
| } |
| } |
| + |
| +// TestStageHeldVerifiedStagesWithoutPublishing (moves after claim Plan 12, |
| +// Task 7; Paul's T7 ruling of 2026-10-12): under the claim, T7 stages the |
| +// pinned release into the shared version store and verifies it, §4.1's |
| +// authorization and D3's admit before the stage and D3's bind on the staged |
| +// bytes after it, and never touches live/<host>: the publication is the |
| +// landing's, at configured, under its held-release selection. |
| +func TestStageHeldVerifiedStagesWithoutPublishing(t *testing.T) { |
| + t.Run("staged, live untouched", func(t *testing.T) { |
| + ctx, s, opt := heldFixture(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + m, err := StageHeldVerified(ctx, s, heldPub, nr(t), opt, heldRoute(), "v1", offGate(t)) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if m == nil || m.Version != "v1" { |
| + t.Fatalf("manifest %+v", m) |
| + } |
| + if _, err := os.Stat(VersionPath(opt, "bab", "v1", "console")); err != nil { |
| + t.Fatalf("v1 was not staged: %v", err) |
| + } |
| + if _, err := os.Lstat(LiveLink(opt, heldTestHost)); !os.IsNotExist(err) { |
| + t.Fatalf("live/<host> was written: %v", err) |
| + } |
| + // Again: the stage is idempotent, and still publishes nothing. |
| + if _, err := StageHeldVerified(ctx, s, heldPub, nr(t), opt, heldRoute(), "v1", offGate(t)); err != nil { |
| + t.Fatal(err) |
| + } |
| + if _, err := os.Lstat(LiveLink(opt, heldTestHost)); !os.IsNotExist(err) { |
| + t.Fatalf("live/<host> was written: %v", err) |
| + } |
| + }) |
| + t.Run("proven, live left on the earlier build", func(t *testing.T) { |
| + e := newHeldProofEnv(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + e.require(t, "console") |
| + e.prove(t, e.pinnedSHA) |
| + if _, err := StageHeldVerified(e.ctx, e.store, heldPub, nr(t), e.opt, heldRoute(), "v1", e.gate); err != nil { |
| + t.Fatal(err) |
| + } |
| + if _, err := os.Stat(VersionPath(e.opt, "bab", "v1", "console")); err != nil || e.live() != "v0" { |
| + t.Fatalf("staged %v, live %q; want v1 staged and v0 live", err, e.live()) |
| + } |
| + }) |
| + t.Run("not proven", func(t *testing.T) { |
| + e := newHeldProofEnv(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + e.require(t, "console") |
| + if _, err := StageHeldVerified(e.ctx, e.store, heldPub, nr(t), e.opt, heldRoute(), "v1", e.gate); !errors.Is(err, ErrHeldNotProven) { |
| + t.Fatalf("an unproven release: %v", err) |
| + } |
| + if _, err := os.Stat(VersionPath(e.opt, "bab", "v1", "console")); err == nil || e.live() != "v0" { |
| + t.Fatalf("an unproven release was staged (%v) or live moved (%q)", err, e.live()) |
| + } |
| + }) |
| + t.Run("the staged bytes are not the proven ones", func(t *testing.T) { |
| + e := newHeldProofEnv(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + e.require(t, "console") |
| + e.prove(t, e.pinnedSHA) |
| + stale := []byte("not the shipped bytes") |
| + down := e.staleCopyDown(t, stale) |
| + if _, err := StageHeldVerified(e.ctx, down, heldPub, nr(t), e.opt, heldRoute(), "v1", e.gate); !errors.Is(err, ErrHeldNotProven) || e.live() != "v0" { |
| + t.Fatalf("other staged bytes: %v, live %q", err, e.live()) |
| + } |
| + r, _ := ReadRefusal(HeldRefusalBase(e.bake), heldTestHost) |
| + if r == nil || r.Kind != RefusalNotProven || r.MoveOp != heldRoute().HoldOp || !strings.Contains(r.Reason, etagOf(stale)) { |
| + t.Fatalf("refusal = %+v, want the move's not-proven record naming the staged hash", r) |
| + } |
| + }) |
| + t.Run("not authorized", 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")) |
| + if _, err := StageHeldVerified(ctx, s, heldPub, nr(t), opt, heldRoute(), "v3", offGate(t)); !errors.Is(err, ErrHeldNotAuthorized) { |
| + t.Fatalf("a never-promoted build: %v", err) |
| + } |
| + if _, err := os.Stat(VersionPath(opt, "bab", "v3", "console")); err == nil { |
| + t.Fatal("an unauthorized build was staged") |
| + } |
| + }) |
| + t.Run("blocked", func(t *testing.T) { |
| + ctx, s, opt := heldFixture(t) |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + orig := materializeHeldStage |
| + t.Cleanup(func() { materializeHeldStage = orig }) |
| + materializeHeldStage = func(context.Context, Store, string, string, string, string, string, string) (*Manifest, error) { |
| + return nil, &os.PathError{Op: "mkdir", Path: opt, Err: syscall.EROFS} |
| + } |
| + if _, err := StageHeldVerified(ctx, s, heldPub, nr(t), opt, heldRoute(), "v1", offGate(t)); !errors.Is(err, ErrStageBlocked) { |
| + t.Fatalf("a read-only version store: %v", err) |
| + } |
| + }) |
| + t.Run("refusals", func(t *testing.T) { |
| + ctx, s, opt := heldFixture(t) |
| + if _, err := StageHeldVerified(ctx, s, heldPub, nr(t), opt, heldRoute(), "v1", nil); !errors.Is(err, errHeldNoProofGate) { |
| + t.Fatalf("no gate: %v", err) |
| + } |
| + noOp := heldRoute() |
| + noOp.HoldOp = "" |
| + if _, err := StageHeldVerified(ctx, s, heldPub, nr(t), opt, noOp, "v1", offGate(t)); err == nil { |
| + t.Fatal("a row no move holds was staged") |
| + } |
| + if _, err := os.Stat(VersionPath(opt, "bab", "v1", "console")); err == nil { |
| + t.Fatal("a refused stage staged v1") |
| + } |
| + }) |
| +} |