You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(npmprofile): support building a caller-specified source ref for dispatch retries #81
js-ts-npm-package-slsa3.yml always builds the caller's github.ref: the build job performs a plain actions/checkout (no ref:) and the identity binding consumes REF/REVISION straight from the caller's event context. There is no input to override the built source revision.
This blocks the standard "retry a failed release with a fixed pipeline" scenario for workflow_dispatch callers:
The fix lands on the caller's main (re-pin of the reusable workflow), but the release tag still contains the old caller workflow file and the old pin.
Dispatching from the tag uses the tag's workflow file (old pin, same failure). Dispatching from main uses the fixed pipeline but builds main HEAD instead of the tag content, and the provenance identity binds to refs/heads/main rather than the signed release tag.
Why this matters
The release trust model (vers-js ADR-0051/0054) anchors on a maintainer-signed tag: the published artifact must provably derive from the signed revision. With no way to name the built ref, a dispatch retry either cannot run (caller-side guard fails closed) or must weaken the provenance claim to an unsigned, movable branch head. The only fully canonical workaround today is deleting and recreating the signed tag on the fixed commit, which requires temporarily relaxing tag-protection rulesets.
Prior art (expected semantics)
The previous hand-rolled vers-js pipeline expressed exactly the desired semantics and used them in production for the v0.1.1 publish: the workflow file came from the dispatch ref (including post-tag fixes, e.g. commit 81d2bba), but every job checked out ref: inputs.release_tag, so the built tarball came from the signed tag commit (cfd032d). Logic from the dispatch ref, content from the signed tag.
Requested behavior
Add an optional input to js-ts-npm-package-slsa3.yml (name TBD, e.g. source-ref):
When set, the build job checks out that ref instead of defaulting to github.sha.
Build metadata, the signed SLSA v1 predicate, and the publish convergence inputs record the built ref and its resolved commit SHA as the source revision (the value the provenance attests).
run_invocation continues to record the actual invocation context (dispatch ref, event name, run id) for audit, so "workflow file came from X, built content came from Y" stays explicit and verifiable.
Design considerations (non-binding)
Constraint choice matters for the threat model: an unconstrained source-ref lets a dispatcher build any branch and call it a release. Options: restrict to refs/tags/* (matches the release-retry use case), or leave unconstrained and rely on honest provenance plus verification policy. The former composes better with caller-side guards.
Resolution should fail closed if the ref does not resolve to a commit (and, if restricted, if it is not a tag).
Digest-verified handoffs should carry the resolved SHA so provenance-sign/publish cannot disagree with build about what was built.
Acceptance sketch
A caller dispatching from main with source-ref: refs/tags/vX.Y.Z produces a provenance Statement whose source revision is the tag's commit SHA, while run_invocation.ref remains refs/heads/main.
Tag-push flows (input unset) behave exactly as today.
Problem
js-ts-npm-package-slsa3.ymlalways builds the caller'sgithub.ref: the build job performs a plainactions/checkout(noref:) and the identity binding consumesREF/REVISIONstraight from the caller's event context. There is no input to override the built source revision.This blocks the standard "retry a failed release with a fixed pipeline" scenario for
workflow_dispatchcallers:31622651874, failed on the settings-only pnpm workspace selection bug fixed in fix(npmprofile): Support pnpm settings-only root packages #80).main(re-pin of the reusable workflow), but the release tag still contains the old caller workflow file and the old pin.mainuses the fixed pipeline but buildsmainHEAD instead of the tag content, and the provenance identity binds torefs/heads/mainrather than the signed release tag.Why this matters
The release trust model (vers-js ADR-0051/0054) anchors on a maintainer-signed tag: the published artifact must provably derive from the signed revision. With no way to name the built ref, a dispatch retry either cannot run (caller-side guard fails closed) or must weaken the provenance claim to an unsigned, movable branch head. The only fully canonical workaround today is deleting and recreating the signed tag on the fixed commit, which requires temporarily relaxing tag-protection rulesets.
Prior art (expected semantics)
The previous hand-rolled vers-js pipeline expressed exactly the desired semantics and used them in production for the v0.1.1 publish: the workflow file came from the dispatch ref (including post-tag fixes, e.g. commit
81d2bba), but every job checked outref: inputs.release_tag, so the built tarball came from the signed tag commit (cfd032d). Logic from the dispatch ref, content from the signed tag.Requested behavior
Add an optional input to
js-ts-npm-package-slsa3.yml(name TBD, e.g.source-ref):github.sha.run_invocationcontinues to record the actual invocation context (dispatch ref, event name, run id) for audit, so "workflow file came from X, built content came from Y" stays explicit and verifiable.Design considerations (non-binding)
source-reflets a dispatcher build any branch and call it a release. Options: restrict torefs/tags/*(matches the release-retry use case), or leave unconstrained and rely on honest provenance plus verification policy. The former composes better with caller-side guards.provenance-sign/publishcannot disagree withbuildabout what was built.Acceptance sketch
mainwithsource-ref: refs/tags/vX.Y.Zproduces a provenance Statement whose source revision is the tag's commit SHA, whilerun_invocation.refremainsrefs/heads/main.Context