ci(publish): single Trusted Publisher entrypoint + reusable workflows - #367
Merged
Conversation
npm Trusted Publishing allows exactly ONE configuration per
package (verified against npm docs 2026-08-03). The previous
design assumed three entries could be registered (release.yml /
hotfix.yml / canary.yml) — this is not possible.
Refactor to a single entrypoint pattern:
publish.yml
The Trusted Publisher. Registered on npmjs.com with
workflow filename = 'publish.yml', environment = 'release'.
Dispatches to reusable workflows based on event type.
Triggers:
- push to main -> release path
- push tag vX.Y.Z -> hotfix path
- pull_request to staging -> canary path
Declares id-token: write (the only file that does).
_publish-release.yml
Reusable workflow (workflow_call trigger). Performs the stable
release: anti-republish guard, build, test, smoke test,
changeset publish --provenance --tag latest, tag creation,
GitHub Release.
_publish-hotfix.yml
Reusable workflow for tag-driven hotfix path. Verifies that
package.json version matches the tag, anti-republish guard,
build, test, smoke test, publish --tag latest, GitHub Release.
_publish-canary.yml
Reusable workflow for per-PR snapshot publishes. Detects
pending changesets (skip cleanly when none), snapshots, publishes
to dist-tag 'canary', comments on PR.
Design notes:
- Single environment ('release') covers all three flows.
npm validates the entrypoint (publish.yml), not the
reusable workflows.
- Reusable workflows declare permissions but do NOT request
id-token themselves — that is inherited from the entrypoint.
- File naming: leading underscore ('_publish-*') signals that
the file is not standalone; only publish.yml can be triggered
by an event.
- workflow_dispatch inputs (the old release.yml 'reason' field)
are removed; hotfix is now exclusively tag-driven per the
pipeline design.
Removes:
- .github/workflows/release.yml (replaced by _publish-release.yml)
- .github/workflows/hotfix.yml (replaced by _publish-hotfix.yml)
- .github/workflows/canary.yml (replaced by _publish-canary.yml)
No behavioral change for end users; the publish path is
unchanged in shape, only the underlying files are reorganized.
Aligns the runbook with the publish.yml entrypoint refactor implemented in 9beadbb / b0f3c0b. §1 Environments: - Drop the 'hotfix' and 'canary' environment sections. The single 'release' environment now covers all three publish paths (release / hotfix / canary), dispatched via reusable workflows. - Optionally allow v* tags to be deployable to 'release'. §5 Trusted Publisher: - Replace the multi-entry (release.yml + hotfix.yml + canary.yml) guidance with a single entry pointing to publish.yml. - Cite npm docs 2026-08-03 ('one trusted publisher per package') and the Paige Niedringhaus reusable-workflow article. - Revocation note: if a previous entry exists, revoke it first via npm trust CLI or the npmjs.com UI. - Verification: confirm exactly one entry on npmjs.com. §6 Workflow permissions: - Update reference from 'release.yml' to 'publish.yml' for the id-token: write override. §7.2 Code Owners: - Update file references from release.yml to publish.yml and the reusable workflows. §8 Verification Checklist: - Replace 'feat/release-pipeline' with 'feat/publish-entrypoint'. - Replace 'release.yml' with 'publish.yml' as the file that must exist in main. §9 Rollback: - Add npm trust CLI command for revocation. No code changes.
This was referenced Aug 3, 2026
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
Refactors the publish pipeline to use a single Trusted Publisher entrypoint (
publish.yml) dispatching to three reusable workflows. This is the canonical 2026 pattern for npm Trusted Publishing, since npm allows exactly one Trusted Publisher configuration per package.The Problem
Verified against the npm docs (2026-08-03): "Each package can only have one trusted publisher configured at a time."
The current pipeline (after #365 and #366) registers three publish workflows —
release.yml,hotfix.yml,canary.yml— each attempting to publish via OIDC. With the 1-per-package limit, only one of the three can be registered as a Trusted Publisher, leaving the other two without OIDC trust and unable to publish.The Solution: Entrypoint + Reusable Workflows
Pattern documented by Paige Niedringhaus and used in production by Vite, Cloudflare SDK, and others. npm validates the entrypoint (
publish.yml), not the reusable workflows it dispatches to.Files
.github/workflows/publish.yml(new) — The Trusted Publisher entrypoint. Registered on npmjs.com with workflow filename =publish.yml, environment =release. Routes events to the right reusable workflow:pushtomain→ release pathpushtagvX.Y.Zonmain→ hotfix pathpull_requesttostaging→ canary pathid-token: write(the only file that does)..github/workflows/_publish-release.yml(renamed fromrelease.yml) — Reusable workflow (workflow_calltrigger). Performs the stable release: anti-republish guard, build, test, smoke test,changeset publish --provenance --tag latest, tag creation, GitHub Release..github/workflows/_publish-hotfix.yml(renamed fromhotfix.yml) — Reusable workflow. Tag-driven hotfix path. Verifies thatpackage.jsonversion matches the tag, anti-republish guard, build, test, smoke test, publish, GitHub Release..github/workflows/_publish-canary.yml(renamed fromcanary.yml) — Reusable workflow. Per-PR snapshot publishes. Detects pending changesets (skip cleanly when none), snapshots, publishes to dist-tagcanary, comments on PR.Removed
.github/workflows/release.yml.github/workflows/hotfix.yml.github/workflows/canary.ymlRunbook Update
docs/engineering/plans/release-pipeline-github-ui-setup.mdis updated to:hotfixandcanaryGitHub Environment sections. The singlereleaseenvironment covers all three paths.publish.yml. Cite npm docs and the reusable-workflow pattern article.release.ymltopublish.yml.Why this is the senior choice
nightly.yml), it's a new reusable workflow + a 5-line dispatch block inpublish.yml. No npm registration change.id-token: writefrom the entrypoint. Each publish still requires a fresh OIDC token, no long-lived secrets.Test plan
pnpm turbo type-checkpasses.pnpm turbo lintpasses.stagingafter merge:_publish-canary.ymlruns (via the entrypoint dispatch).Version PackagesPR merged intomain:_publish-release.ymlruns and attempts Trusted Publishing.main:_publish-hotfix.ymlruns and attempts Trusted Publishing.Risk
Low. No publish has happened yet (Trusted Publisher not registered on npmjs.com), so no production impact. All three publish paths remain reachable through the entrypoint. The workflows are reorganized but functionally equivalent to their standalone counterparts.
Rollback
Restore the three original files (
release.yml,hotfix.yml,canary.yml) from git history. The dispatch inpublish.ymlreferences the new reusable paths, so revertingpublish.ymlalone is not sufficient — restore all four files.🤖 Generated with Claude Code