Repository navigation
ci: promote over Trusted Publishing, and close the release there - #237
Merged
Merged
Conversation
Promotion was the last workflow holding an NPM_TOKEN, and it had gone stale unnoticed: publishing moved to Trusted Publishing, which does not read the secret, so nothing exercised it until 2.7.0 needed the tag moved and the registry answered 401. npm authorizes dist-tag over OIDC from 11.21.0 (npm/cli#10038), so the job now upgrades npm and asserts the version rather than failing later inside the registry call. The grant is separate from publish and off by default, so the dist-tag failure path names the setting to enable. Linear and Slack ran only from a `latest` publish, which the beta-then-promote flow never reaches, so promoting left the release open. They run here too. The checkout read `github.event.pull_request.head.sha`, empty on a dispatch, and `npm ci` installed dependencies that `npm dist-tag` does not use. The `latest` guard accepted `refs/tags/release/*`, which release-it cannot produce: it tags `v${version}`. Only the branch arm could ever match, and the tag of a release failing the guard reads as a mistake. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y4EZAEvxLfXuMeNz5ZgCMz
|
| Topic | Details | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Trusted promotion | Authenticate promotion through npm Trusted Publishing, remove unnecessary checkout and dependency installation, and provide actionable errors for missing dist-tag permissions.Modified files (2)
Latest Contributors(2)
| |||||||||
| Release completion | Complete Linear releases and post Slack announcements after promotion or direct latest publishing, while restricting latest-channel validation to supported release/* branches.Modified files (3)
Latest Contributors(2)
|
The job that promotes holds `id-token: write`, so anything running in it can mint an npm credential for this package. `npm install -g npm@latest` resolved that at release time to whatever the registry served, unreviewed. Pinned to 12.2.0, which clears the 12.x floor npm/cli#10038 set for dist-tag over OIDC. `--ignore-scripts` costs nothing today — the npm package declares no install scripts — and bounds a release that adds one. The version assertion is gone: it guarded `latest` resolving below the floor, which a pin cannot do. The Linear and Slack steps move to a job without `id-token`. Neither needs it, both resolve a mutable tag, and `complete` reads no checkout: the action scans commits only for `sync`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y4EZAEvxLfXuMeNz5ZgCMz
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.
Promoting 2.7.0 to
latestfailed with401 Unauthorized - PUT /-/package/@currents%2fmcp/dist-tags/latest. Promotion was the last workflow still holding anNPM_TOKEN: publishing moved to Trusted Publishing, which never reads that secret, so nothing exercised it until the tag had to move. After this, no workflow in the repo referencesNPM_TOKEN.Promote authenticates over OIDC
npm authorizes
dist-tagover OIDC from 11.21.0 (npm/cli#10038, merged 2026-09-30). The runner's bundled npm is older, so the job upgrades npm and then asserts the version, failing with a readable message rather than inside the registry call.This needs a setting on npm that a workflow cannot set. Trusted publishing grants dist-tag separately from publish, and the grant is off by default, including for existing configurations (GitHub changelog) — so the configuration that published the 2.7.0 beta will still refuse the tag until Allow npm dist-tag is enabled on it. That is already done for
@currents/mcp. The dist-tag failure path names the setting, so the next person who hits it on another package is not debugging a bare 401.Promoting closes the release
The Linear-complete and Slack steps only ran from a
latestpublish. The documented flow is publishbeta→ test → promote, which never reaches that path, so promoting left the release open in Linear and silent in Slack — as it did for 2.7.0. They now run from promote as well. Both paths keep them: a version reacheslatestby one route or the other, never both.Two latent bugs found while in here
github.event.pull_request.head.sha, which is empty on aworkflow_dispatch, so it silently took the default branch. Harmless fordist-tag, which reads no tree, but it is copied frompublish.yamlwhere it matters. Thenpm cistep installed dependenciesnpm dist-tagdoes not use, and is dropped.latestchannel guard acceptedrefs/tags/release/*, whichrelease-itcannot produce —.release-it.jsonsetstagName: "v${version}". Only the branch arm could ever match, so running Publish from thev2.7.0tag failed a guard that looked like it should have passed. The guard now names branches only and says why a tag does not match.Not changed
.github/workflows/*.yamldoes not satisfy Prettier today and the repo'sformatscript covers onlysrcandskills, so I left formatting alone rather than mix a reformat into this diff.Verification
YAML parses and the step list is as intended; the version comparison was checked for equal, higher and lower npm versions. The OIDC exchange itself only exercises on a real dispatch — the first run of promote after this merges is the test.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Y4EZAEvxLfXuMeNz5ZgCMz
Generated by Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.