Repository navigation
ci: use github oidc for npm publishing - #231
Conversation
Switch the release workflow to npm trusted publishing instead of relying on an ambient npm credential: - set registry-url so npm can derive the OIDC audience - update npm, since the exchange needs >= 11.5.1 and 'npm stage publish' needs >= 11.7.0, newer than the npm bundled with some Node LTS lines - move permissions to the job so id-token: write is not granted file-wide - declare the npm environment, to be matched on the trusted publisher - pass a publish script, without which the action never published at all Also set changesets access to public: it is forwarded as 'npm publish --access restricted', which does not apply to an unscoped public package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #231 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 3 3
Lines 18 18
Branches 2 2
=========================================
Hits 18 18 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Important One thing to settle before merge, which I called out in the PR body: the trusted publisher has to be created on npm for coffee-loader with repository webpack/coffee-loader, workflow release.yml, environment npm. Until that exists the exchange has nothing to match against. |
|
I've enabled OIDC at npm, we just need to merge and test ourselves. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughChangesets package access changes from restricted to public. The release workflow sets workflow-level permissions to empty and grants the release job Priority: ➖ Normal Merge Risk: 🟡 Moderate · up to
|
| "fixed": [], | ||
| "linked": [], | ||
| "access": "restricted", | ||
| "access": "public", |
There was a problem hiding this comment.
This shouldn't have any effects on security because we have scoped access on npm which can't be overridden.
Summary
The release workflow declared
id-token: writewith a comment saying "Required for OIDC", but nothing in it actually published through OIDC, so the permission and thenpmPATH shim added in #226 were both unreachable. This wires up npm trusted publishing properly.Two things were blocking a publish entirely:
publishinput onchangesets/action. The action computeshasPublishScript = !!core.getInput("publish"), so with it unset every push tomainlanded in the!hasChangesets && !hasPublishScriptbranch and logged "Not publishing because no publish script found." The release PR could be opened and merged, but nothing was ever published. Passingpublish: npx changeset publishis also what lets the.github/shims/npmrewrite fire, since@changesets/clispawnsnpm publish <dir>internally."access": "restricted"in.changeset/config.json(thechangeset initdefault) is forwarded verbatim asnpm publish --access restricted.coffee-loaderis unscoped and public, so that is the wrong value; set topublic.The rest makes the OIDC exchange itself work:
registry-urlonsetup-node, so npm can derive the audience — it requests the ID token withaudience=npm:<registry hostname>.npm install -g npm@latest. The token exchange needs npm >= 11.5.1 andnpm stage publishneeds >= 11.7.0.lts/*currently resolves to Node 24.21 (npm 11.19.0) so this happens to work today, but Node 22 ships npm 10.9.9, which has no OIDC support at all — iflts/*ever moves, the release breaks for a non-obvious reason.permissionsmoved from the workflow to the job, withpermissions: {}at the top.id-token: writemints publish tokens, so it shouldn't be granted file-wide by default to any job added later.environment: npm, to be matched by the environment on the trusted publisher.No
NPM_TOKENis involved anywhere;changesets/actionv1.9.0 detectsACTIONS_ID_TOKEN_REQUEST_{URL,TOKEN}and skips its.npmrctoken generation, and npm auto-enables provenance for trusted-publishing claims so no--provenanceflag is needed.Before merging, the trusted publisher has to exist on npm for
coffee-loader, with repositorywebpack/coffee-loader, workflow filenamerelease.ymland environmentnpm. The claim must match exactly — if the environment field is left blank there while the job declares one, the exchange is rejected. Note the publisher is keyed on the workflow filename, so renamingrelease.ymllater breaks publishing.What kind of change does this PR introduce?
ci — plus a one-value config fix in
.changeset/config.json.Did you add tests for your changes?
No. This is release pipeline configuration; there is nothing the Jest suite can exercise.
prettier,cspelland commitlint pass, and the YAML parses. The OIDC exchange can only really be verified by the first publish after the trusted publisher is configured on the npm side.Does this PR introduce a breaking change?
No. Nothing in the published package changes —
filesisdistonly, and neither modified file is shipped. No changeset is included for that reason.If relevant, what needs to be documented once your changes are merged or what have you already documented?
Nothing user-facing. The non-obvious constraints are in comments in the workflow itself: why npm is upgraded, and that
environment: npmhas to match the trusted publisher. Worth knowing for maintainers: releases no longer depend on an npm token, and the npm-side trusted publisher config is now part of the release path.Use of AI
Claude Code (Opus 5) was used for this change. It read
@changesets/cli,changesets/actionand the npm CLI sources to establish the specifics cited above — that the action silently skips publishing without apublishinput, thatnpm stage publishextendsPublishand so inherits the OIDC path, and which npm versions ship with each Node LTS line — then drafted the workflow edits. I reviewed the diff and the reasoning behind each change before submitting, and can answer questions about any of it in review.🤖 Generated with Claude Code
Summary by CodeRabbit