Skip to content

fix(release): let OIDC authenticate the npm publish - #51

Merged
markm39 merged 1 commit into
mainfrom
fix/npm-oidc-authtoken
Aug 15, 2026
Merged

fix(release): let OIDC authenticate the npm publish#51
markm39 merged 1 commit into
mainfrom
fix/npm-oidc-authtoken

Conversation

@markm39

@markm39 markm39 commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Problem

0.3.3 never reached npm. CI passed, the package built and packed correctly (303 kB, 363 files, shasum fbd4b7d8…), and then the publish died at the upload:

npm error code E404
npm error 404 Not Found - PUT https://registry.npmjs.org/@mathnotes%2fmobile-ink

latest on npm is still 0.3.2, and there is no v0.3.3 tag or GitHub release because the release step runs after publish.

The job authenticates via OIDC trusted publishing and deliberately sets no NODE_AUTH_TOKEN — but it passed registry-url to setup-node, which writes //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} into .npmrc. With the variable unset, that expands to an empty string. npm reads the line as "credentials are already configured", skips the OIDC token exchange entirely, and publishes anonymously. The registry rejects it as E404 rather than 403, to avoid confirming whether the package exists. See npm/documentation#1960.

Change

  • Drop registry-url from setup-node, so the conflicting .npmrc is never created. npm already defaults to registry.npmjs.org, and nothing else in the repo depends on the pin — there is no checked-in .npmrc, and scripts/npm-registry.mjs reaches the registry over plain fetch with its own default rather than through npm config.
  • Pin the registry on npm publish itself instead. The publish target stays explicit at the one step where targeting matters, without configuring auth.
  • Add a guard before publish that fails the job if any _authToken is configured. An anonymous publish surfaces as a bare E404 that points nowhere near its cause, so the invariant is asserted rather than assumed — if a future setup-node change or a re-added registry-url reintroduces the credential, the job fails loudly at that step.

Verification

  • Guard exercised in all three states: no .npmrc → pass, .npmrc without a token → pass, .npmrc with the placeholder → fail with the diagnostic.
  • Workflow YAML parses; step order confirmed.
  • Local CI: typecheck clean, 62 tests across 10 suites, test:release 4/4, build clean.
  • npm pack --dry-run reproduces shasum fbd4b7d8bd07e2511e1b00a8f0adb46ed30f493c, byte-identical to the tarball the failed run produced. Only the auth path changes.

Notes

The trusted publisher has been configured on npmjs.org for mathnotes-app/mobile-ink, workflow publish.yml, environment npm. Merging this to main runs CI, which fires Publish; package.json is still at 0.3.3, so check-npm-version.mjs will see it absent from the registry and publish it, then tag v0.3.3.

Separately, and not addressed here: npm ci runs dependency lifecycle scripts in a job holding id-token: write and contents: write. --ignore-scripts there would be worth a follow-up once the build is verified without them.

The publish job authenticates with npm via OIDC trusted publishing and sets
no NODE_AUTH_TOKEN, but it passed registry-url to setup-node. That makes
setup-node write "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" into
.npmrc, where the unset variable expands to an empty string. npm reads that
as credentials already being configured, skips the OIDC token exchange, and
publishes anonymously, which the registry rejects with E404. 0.3.3 built and
packed correctly but never reached npm.

Drop registry-url so the file is never written; npm already defaults to
registry.npmjs.org. Pin the registry on the publish command instead, so the
target stays explicit at the step that matters without configuring auth.

Add a guard before publish that fails the job if any _authToken is configured,
so this silently reverting to an anonymous publish becomes a loud failure at
the exact assumption that broke.

Refs npm/documentation#1960
@markm39
markm39 merged commit 73935f8 into main Aug 15, 2026
1 check passed
@markm39
markm39 deleted the fix/npm-oidc-authtoken branch August 15, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant