fix(plugin-npm-cli): enable OIDC publish on CircleCI#7122
Merged
arcanis merged 1 commit intoyarnpkg:masterfrom May 5, 2026
Merged
fix(plugin-npm-cli): enable OIDC publish on CircleCI#7122arcanis merged 1 commit intoyarnpkg:masterfrom
arcanis merged 1 commit intoyarnpkg:masterfrom
Conversation
PR yarnpkg#7075 added CircleCI support to `getOidcToken()` but the gating expression in `npm publish` was not updated, so the OIDC code path is still skipped on CircleCI even though `NPM_ID_TOKEN` is available.
3 tasks
joshuayoes
added a commit
to infinitered/reactotron
that referenced
this pull request
May 1, 2026
## Please verify the following: - [x] `yarn build-and-test:local` passes - [ ] I have added tests for any new features, if relevant - [x] `README.md` (or relevant documentation) has been updated with your changes ## Describe your PR Migrates the reactotron CI publish pipeline from classic `NPM_TOKEN` auth to **npm Trusted Publishing via CircleCI OIDC**. npm GA'd CircleCI support on [2026-04-06](https://github.blog/changelog/2026-04-06-npm-trusted-publishing-now-supports-circleci/); this PR wires us up. The pipeline has been broken since npm revoked classic tokens on 2025-12-09 and #1602 left the renamed `reactotron-npm-context` with an empty `NPM_TOKEN`. Rather than mint a granular replacement (capped at 90 days) and rotate forever, OIDC eliminates the human-managed token entirely. ### Changes - `.circleci/config.yml` (`release_package` job) β replaces the `npm whoami` + `~/.npmrc` token write with a "Mint npm OIDC token" step using `circleci run oidc get --claims '{"aud":"npm:registry.npmjs.org"}'`. - `scripts/release.artifacts.mjs` β accepts either `NPM_TOKEN` or `NPM_ID_TOKEN`, and performs the npm OIDC token exchange directly (`POST /-/npm/v1/oidc/token/exchange/package/<ident>`). This in-script exchange is a workaround for [yarnpkg/berry#7122](yarnpkg/berry#7122): Yarn 4.14.1's `getOidcToken` helper handles CircleCI, but the `allowOidc` gate in `publish.ts` only flips on for `GITHUB_ACTIONS` / `GITLAB_CI`. Once 7122 lands and we bump Yarn, the script-level exchange block can be deleted. - Yarn `4.1.1 β 4.14.1` (4.14 brought the CircleCI OIDC support that 7122 finishes wiring up). - `.yarnrc.yml` β keeps `npmAuthToken: "${NPM_TOKEN-}"` as a soft fallback during cutover. Empty string is falsy in Yarn's auth chain, so it's a no-op when OIDC is in play. Removed in a follow-up PR after first prod publish. - `docs/contributing/releasing.md` β new "OIDC publish flow" section covering the CI flow, how to add a trusted publisher when shipping a new package, and the upstream Yarn workaround. ### Pilot validation Pilot package: `eslint-plugin-reactotron@0.1.10-beta.0`. Pushed tag from branch `test/oidc-pilot-eslint`, published under the `beta` dist-tag (semver prerelease β invisible to `^`/`~`/`*` ranges). Pipeline succeeded; package published. The npm registry metadata for the pilot version records: ```json "_npmUser": { "name": "CircleCI", "email": "npm-oidc-no-reply@github.com", "trustedPublisher": { "id": "circleci", "oidcConfigId": "oidc:71dbce82-a25e-4b17-a0e3-78908cc0e805" } } ``` This is the smoking-gun proof the publish ran via the trusted publisher path, not legacy token auth. `_npmVersion: null` and `_nodeVersion: null` (set when the publisher is OIDC) corroborate. - npm: https://www.npmjs.com/package/eslint-plugin-reactotron/v/0.1.10-beta.0 - GitHub release: https://github.com/infinitered/reactotron/releases/tag/eslint-plugin-reactotron%400.1.10-beta.0 - CircleCI pipeline: https://app.circleci.com/pipelines/gh/infinitered/reactotron/2762 ### Pre-merge prerequisites - β Trusted publisher configured on all 11 npm packages (same Org / Project / Pipeline Definition / Context / VCS Origin tuple, validated by the pilot's successful publish). - β "Publishing access" tightened to **"Require two-factor authentication and disallow tokens (recommended)"** on all 11 packages. Per npm's inline note, this is fully OIDC-compatible β short-lived OIDC publish tokens are a separate auth path. Out of scope: `reactotron-app` (Electron app, GitHub release artifacts only), `reactotron-mcp` (`"private": true`). ### Follow-up PRs After **first successful production OIDC publish**: - Remove `npmAuthToken: "${NPM_TOKEN-}"` from `.yarnrc.yml`. - Tighten `release.artifacts.mjs` to require only `NPM_ID_TOKEN`. - Clear `NPM_TOKEN` from CircleCI context (currently absent; belt-and-suspenders). After **yarnpkg/berry#7122 lands and we bump Yarn**: - Delete the OIDC exchange block in `scripts/release.artifacts.mjs` β Yarn handles the exchange directly via `yarn npm publish`. - Simplify the OIDC docs section. ### Notes - The chore commit only touches infra files (`.circleci/`, `.yarnrc.yml`, root `package.json`, `yarn.lock`, `scripts/release.artifacts.mjs`, `docs/`, `.yarn/releases/`). No `lib/*` or `apps/*` workspaces affected β 0 release tags created on merge β no auto-publish triggered. First real OIDC publish happens on the next legitimate code change inside a `lib/*` workspace. π€ Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <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.
What's the problem this PR addresses?
yarn npm publishskips the OIDC code path on CircleCI, even though #7075 was supposed to add CircleCI support. That PR updatedgetOidcToken()inpackages/plugin-npm/sources/npmHttpUtils.tsto readNPM_ID_TOKENwhenprocess.env.CIRCLECIis set, but the gating expression inpackages/plugin-npm-cli/sources/commands/npm/publish.tsthat decides whether to passallowOidc: truetonpmHttpUtils.putwas not updated:So on CircleCI,
allowOidcis alwaysfalse,getOidcToken()is never called, and the publish either fails (no other auth) or falls back to a long-lived token. This contradicts the stated intent of #7075 ("CircleCI was recently added as a supported npm trusted publisher provider, but Yarn's OIDC implementation only supports GitHub Actions and GitLab CI").Reproduction: a CircleCI release pipeline that mints an OIDC token via
circleci run oidc get --claims '{"aud":"npm:registry.npmjs.org"}', exports it asNPM_ID_TOKEN, then runsyarn npm publishagainst a package configured for trusted publishing. Expected: yarn exchanges the id-token for a single-use publish token. Actual: yarn never attempts the exchange, because theallowOidcgate excludes CircleCI.Refs #7074, #7075.
How did you fix it?
Added
process.env.CIRCLECIto the disjunction, mirroring the branch that #7075 already added ingetOidcToken():This keeps the gate consistent with the providers
getOidcToken()actually handles, and matches the same one-line shape as the GitLab fix in #6938.No new tests: the change is an additional disjunct in a Boolean gate; there were no tests covering the GitHub Actions or GitLab CI cases of this expression either, and #7075 / #6938 were merged without tests for the same reason.
Checklist