fix: harden publish for trusted publishing + stranded tags#101
Open
theoephraim wants to merge 2 commits into
Open
fix: harden publish for trusted publishing + stranded tags#101theoephraim wants to merge 2 commits into
theoephraim wants to merge 2 commits into
Conversation
added 2 commits
June 3, 2026 22:32
Two related fixes for failures hit when publishing brand-new packages from GitHub Actions with npm trusted publishing (OIDC): 1. Detect the new-package + OIDC-only auth case before any side effects. Trusted publishing cannot bootstrap a package that doesn't exist on npm yet — the trusted publisher config has to be created on npmjs.com first, which requires the package to already exist. We now check the registry before creating GH draft releases or running `npm publish`, and emit a clear error telling the user to publish a 0.0.0 placeholder. Only fires when OIDC is the sole auth path (no NPM_TOKEN/NODE_AUTH_TOKEN, no .npmrc auth) to avoid false positives for users who enable id-token: write for provenance attestations alongside token auth. 2. Replace blanket `git push --tags` with per-tag force push. `gh release create --draft --target SHA` creates the tag on the remote at draft time; if a prior publish failed and HEAD has since moved, the remote tag is stale and `git push --tags` rejects with "already exists". We now iterate `releasePlan.releases` minus failed and force-push each tag individually. Packages whose targets all already succeeded in prior runs are stripped upstream by the `alreadyPublished` filter, so their tags stay put — the GitHub release continues to point at the SHA the artifact was actually published from.
|
The changes in this PR will be included in the next version bump.
|
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.


Summary
Two related fixes for publish failures hit when releasing brand-new packages from GitHub Actions with npm trusted publishing (OIDC). Reported by a downstream project (varlock) where publishing
@varlock/kubernetes-plugin@0.1.0failed because the package didn't exist on npm yet, leaving a stranded GH draft release + remote tag that then broke the retry'sgit push --tags.1. Detect new-package + OIDC-only auth before any side effects
Trusted publishing can't bootstrap a package that doesn't exist on npm — the trusted publisher config has to be created on npmjs.com first, which requires the package to already exist. We now check the registry up front and emit a specific, actionable error directing the user to publish a
0.0.0placeholder first.The check is gated on
willUseOidcExclusively(OIDC env detected AND noNPM_TOKEN/NODE_AUTH_TOKENAND no.npmrcauth) to avoid false positives for users who enableid-token: writefor provenance attestations alongside token auth. Runs beforegh release createandnpm publish, so a failing check leaves no stranded state. On--dry-runit warns instead of erroring.2. Per-tag force push replaces blanket
git push --tagsgh release create --draft --target SHAcreates the tag on the remote at draft-creation time. If a prior publish failed and HEAD has since moved, the remote tag is stale andgit push --tagsrejects with "already exists". The fix iteratesreleasePlan.releasesminusresult.failedand force-pushes each tag individually.Preserves the existing anySucceeded-aware semantics used for local tag movement: packages whose targets all succeeded in a prior run are stripped upstream by the
alreadyPublishedfilter, so their tags stay at the SHA the artifact was actually published from — the GitHub release continues to point at the right commit. Mixed-success scenarios (e.g. package A published from SHA1 in run 1, package B retried from SHA2 in run 2) end up correct: A's tag is left at SHA1, only B's tag is force-pushed to SHA2.Test plan
bun run checkpasses (lint + format + typecheck)bun run test— 258/258 pass0.0.0placeholder succeeds and pushes tags without rejection