Skip to content

Publication contract checks the signed publisher exists, but not that it is the ONLY writer of the mutable tag #2942

Description

@devantler

🤖 Generated by the Agentic Engineer

Evidence

validateCDWiring establishes that the shared deploy action still invokes the nested publisher as an
enforced step:

requireEnforcedStep(
    map[string]any{"steps": runs["steps"]}, usesAction(nestedPublisherAction), …)

That is an existence check. It proves a checked publisher is present and enforced; it does not
prove it is the only step that writes the mutable production tag. Appending a step that runs
workload push …:latest directly, after the nested publisher, leaves the validator passing.

Reported by Codex on #2939 (P2, main.go:255), which states it reproduced the append. Confirmed by
reading the check: there is no enumeration of other writers anywhere in the function.

Why it matters

The contract exists so the digest reconciliation consumes is the signed and attested one. A second
writer to the same mutable tag can replace that digest immediately before reconciliation — the signed
artifact is published, and then something else overwrites the tag it is published under. The ordering
guarantee #2939 establishes holds, and is then bypassed at a different point.

Not reachable by an outside contributor — it needs a workflow or composite-action edit — so this is
defence-in-depth of a gate that already exists, not a live exposure.

Expected behaviour

Publication of the mutable production tag is constrained to the checked action, or any other step
that writes it is explicitly rejected.

Acceptance criteria

  1. A step other than the checked publisher that writes the mutable production tag fails the check.
  2. The rule covers the shared composite action and the workflow that calls it.
  3. The shipped configuration passes unchanged.
  4. One ablation per rule, each failing a disjoint test, each build-checked.

Size

Small–medium. Reuses the existing step-walking helpers; the new part is enumerating writers rather
than finding one.

Deliberately not folded into #2939: that PR is at review round 11 on a single concern (ordering on
the direct-push route), and this is a distinct property (exclusivity). Third spin-off from that
review, after #2940 and #2941.

Part of #2627

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Status
✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions