fix(publish): dispatch experimental builds instead of publishing from a PR - #204
Merged
Merged
Conversation
… a PR npm's trusted publishing does not authenticate a run triggered by pull_request_target. Everything else in that run works - the tarball is read, the version stamps correctly, provenance is signed and logged to Sigstore - and only the registry write is refused, with a 404 on the PUT that reads as "no such package" and means "these credentials are not accepted". The identical code dispatched on main published all three packages first try. See npm/cli#8739. So publish.yml loses its pull_request_target trigger, and experimental-dispatch.yml turns the label into a dispatch of it. The run that reaches npm is now always a workflow_dispatch on the default branch. GITHUB_TOKEN can do this: workflow_dispatch is a documented exception to the rule that a GITHUB_TOKEN-triggered event starts no new run. The bridge stays on pull_request_target for the original reason - pull_request would run the PR branch's copy of the guard - and the usual footgun does not apply because it checks out nothing. Also fixes a latent bug the dispatch test exposed: the version was stamped from github.sha, which is the tip of main, not the commit checked out. Dispatching against any other branch would have built that branch and stamped it with main's sha, naming a commit that was never built. The sha now comes from git rev-parse HEAD in the checkout. Strapi publishes straight from a pull_request, which works because it authenticates with a stored NPM_TOKEN rather than OIDC, and its publish job has no environment gate. That is the trade being declined here. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause, proven
npm's trusted publishing does not authenticate a run triggered by
pull_request_target.Everything else in that run worked — tarball read, version stamped correctly,
provenance signed and logged to Sigstore — and only the registry write was
refused:
which reads as "no such package" and means "these credentials are not accepted".
The identical code, dispatched on
main, published all three packages firsttry (run 31761996762):
latestuntouched at 5.0.1. Matches npm/cli#8739.Ruled out first, each verified rather than assumed: trusted publisher config
(saved, correct), environment name (blank — correct for three modes), npm
version (11.16.0 vs 11.5.1 floor), and
repository.url(exact match on allthree packages).
Fix
publish.ymlloses itspull_request_targettrigger.experimental-dispatch.ymlturns the label into a dispatch of it, so the run that reaches npm is always a
workflow_dispatchon the default branch.GITHUB_TOKENis sufficient —workflow_dispatchandrepository_dispatcharethe documented exceptions
to the rule that a
GITHUB_TOKEN-triggered event starts no new run. No PAT.Unchanged from your point of view: add the label, get a build. The bridge
passes the PR's exact head sha,
publish.ymlcomments the install command backon the PR, and the label is removed so a second build is a second deliberate
labelling.
The bridge stays on
pull_request_targetfor the original reason —pull_requestwould run the PR branch's copy of the guard below — and the usual footgun does
not apply, because it checks out nothing at all.
Latent bug the dispatch test exposed
The experimental version was stamped from
github.sha. This workflow alwaysruns from the default branch, so that is the tip of
main— not the commitchecked out. Dispatching against any other branch would have built that branch
and stamped it with main's sha, naming a commit that was never built. It only
looked right in the test because
target_branchwasmain.The sha now comes from
git rev-parse HEADin the checkout.Why not Strapi's branch dropdown
Strapi publishes straight from a
pull_requestand lets you pick any branch in"Use workflow from". They can: they authenticate with a stored
NPM_TOKEN, andtheir publish job has no environment gate.
Here,
npm-experimentalhas a deployment branch policy allowing onlymain, soselecting a feature branch would be blocked before the job runs. Loosening it
would mean the publish job executes that branch's
publish.yml— and sincenpm discards the ref, that branch could strip the version-shape assertion and
publish to
latest. That is a review bypass straight to thelatesttag.Note
Touches workflows, so it needs a maintainer to merge — and
pull_request_targetruns the default branch's copy, so the label will not work until this is on
main.🤖 Generated with Claude Code