From a1fa56dfa7c6492c99fcd7432d5f175c605d7359 Mon Sep 17 00:00:00 2001 From: Paul Mulligan Date: Mon, 15 Jun 2026 19:10:10 -0400 Subject: [PATCH 1/3] ci: publish to npm via trusted publishing (OIDC) Switch the manual npm publish workflow from a long-lived NPM_TOKEN secret to npm Trusted Publishing: - Remove NODE_AUTH_TOKEN from the publish step so npm authenticates via the GitHub Actions OIDC token (id-token: write is already granted) against the trusted publisher configured on each package at npmjs.com. - Upgrade the runner's npm to latest before publishing; Trusted Publishing needs npm >= 11.5.1 and Node 20 ships npm 10.x. - Update the header comment to document the new auth model. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish-npm.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 678347b..6eb1d63 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -8,10 +8,11 @@ name: Publish to npm # current version already exists, so re-running release-please is a no-op), and # - recovering from a failed release publish without waiting for the next release. # -# Requires the NPM_TOKEN secret to be an npm token that can publish the package -# (and create it on first publish) and bypasses 2FA — a granular token with -# "All packages" + read/write, or an account-scoped token. Publishes with -# provenance (needs id-token). +# Auth uses npm Trusted Publishing (OIDC) — there is no NPM_TOKEN secret. A +# trusted publisher matching this repo + workflow filename must be configured +# on each package at npmjs.com. Requires id-token: write and npm >= 11.5.1, so +# we upgrade the runner's bundled npm before publishing. Provenance is +# generated automatically. on: workflow_dispatch: inputs: @@ -56,6 +57,10 @@ jobs: cache: pnpm cache-dependency-path: ${{ inputs.package }}/pnpm-lock.yaml + # Trusted Publishing (OIDC) needs npm >= 11.5.1; Node 20 ships npm 10.x. + - name: Upgrade npm for trusted publishing + run: npm install -g npm@latest + - name: Install run: pnpm install --frozen-lockfile @@ -63,6 +68,4 @@ jobs: run: pnpm build - name: Publish - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: npm publish --provenance --access public --tag "${{ inputs.dist-tag }}" From 462c359fcd91ba22a4efb8763a427518dd6a62a7 Mon Sep 17 00:00:00 2001 From: Paul Mulligan Date: Mon, 15 Jun 2026 19:18:48 -0400 Subject: [PATCH 2/3] ci: drop registry-url so npm uses OIDC trusted publishing actions/setup-node with registry-url writes an .npmrc containing a placeholder _authToken (XXXXX-XXXXX-XXXXX-XXXXX). npm sees a configured token and attempts token auth with that garbage value instead of performing the OIDC trusted-publishing exchange, producing a 404 on publish. Removing registry-url leaves no auth token configured, so npm falls through to OIDC. The default registry is already registry.npmjs.org. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish-npm.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 6eb1d63..accbded 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -50,10 +50,13 @@ jobs: with: version: 9 + # No registry-url: passing it makes setup-node write an .npmrc with a + # placeholder _authToken, and npm then does (failing) token auth instead + # of the OIDC trusted-publishing exchange. The default registry is already + # registry.npmjs.org, which is also where provenance must be published. - uses: actions/setup-node@v4 with: node-version: 20 - registry-url: https://registry.npmjs.org cache: pnpm cache-dependency-path: ${{ inputs.package }}/pnpm-lock.yaml From 2cebdacb562e20f52e82802e618c625c50c93e4c Mon Sep 17 00:00:00 2001 From: Paul Mulligan Date: Mon, 15 Jun 2026 19:23:00 -0400 Subject: [PATCH 3/3] ci: restore registry-url; required for OIDC trusted publishing Reverts the registry-url removal. The npm docs confirm registry-url is required for trusted publishing: it points npm at the registry to mint the OIDC token against. Without it npm performs no OIDC exchange and fails with ENEEDAUTH. The placeholder _authToken setup-node writes is ignored by npm in favour of OIDC whenever a matching trusted publisher exists for the package. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish-npm.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index accbded..0130294 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -50,13 +50,14 @@ jobs: with: version: 9 - # No registry-url: passing it makes setup-node write an .npmrc with a - # placeholder _authToken, and npm then does (failing) token auth instead - # of the OIDC trusted-publishing exchange. The default registry is already - # registry.npmjs.org, which is also where provenance must be published. + # registry-url is required for OIDC trusted publishing: it points npm at + # the registry to mint the short-lived token against. setup-node also + # writes a placeholder _authToken, which npm ignores in favour of OIDC as + # long as a matching trusted publisher is configured for this package. - uses: actions/setup-node@v4 with: node-version: 20 + registry-url: https://registry.npmjs.org cache: pnpm cache-dependency-path: ${{ inputs.package }}/pnpm-lock.yaml