Skip to content

fix(ci): pass NPM_TOKEN to the publish steps, not just NODE_AUTH_TOKEN - #15

Merged
qmarcelle merged 1 commit into
mainfrom
fix/publish-npm-token-env
Jul 27, 2026
Merged

fix(ci): pass NPM_TOKEN to the publish steps, not just NODE_AUTH_TOKEN#15
qmarcelle merged 1 commit into
mainfrom
fix/publish-npm-token-env

Conversation

@qmarcelle

Copy link
Copy Markdown
Contributor

Summary

The cli-v0.5.0 release failed at the credential check with 401 Unauthorized from npm whoami. That looks like a revoked or mistyped token. It was neither — the token is fine and this workflow was wrong.

This repository's .npmrc reads:

//registry.npmjs.org/:_authToken=${NPM_TOKEN}

npm's project config outranks the userconfig that setup-node writes, so for any command run from the repository root the repo .npmrc wins — and it wants NPM_TOKEN, a name the workflow never set. It set only NODE_AUTH_TOKEN.

The part that makes this misdiagnose so cleanly: npm does not fall back to the userconfig when the variable is missing. It sends the literal, unexpanded text as the bearer token. Confirmed against a local registry that echoes the Authorization header:

NPM_TOKEN unset  ->  AUTH_HEADER: "Bearer ${NPM_TOKEN}"
NPM_TOKEN set    ->  AUTH_HEADER: "Bearer REAL_TOKEN_VALUE"

From the registry's side the first is indistinguishable from a garbage credential — hence the 401, and hence an error that points at the secret instead of at the workflow.

Changes

  • Both publish steps now set NPM_TOKEN alongside NODE_AUTH_TOKEN. Kept step-scoped rather than job-scoped, so the publish token is not exposed to pnpm -r test.
  • verify-npm-publish-access.mjs now checks NPM_TOKEN is present and expanded before touching the registry. A recurrence names the cause instead of returning an authentication error that sends you to revoke a perfectly good token.

Verification

  • Root cause reproduced and fix confirmed against a local registry echoing the auth header (output above)
  • Both new guard paths exit 1 with an accurate message — unset, and present-but-unexpanded
  • pnpm run check:architecture
  • Workflow YAML parses; on.push.tags trigger intact
  • pnpm -r test etc. — not re-run; no application code changed (workflow env and one release script)

Notes

Nothing was published by the failed run: @workspacejson/cli still 404s, so 0.5.0 is not burned.

After merge the cli-v0.5.0 tag must be recreated, not just re-run. Tag-triggered workflows execute the workflow file as of the tagged commit, so re-running the existing tag would replay the broken version. Delete the tag, re-tag at the new main head, push.

The invalid cli-v0.5.1 tag has already been deleted locally and on the remote.

The 0.5.0 release failed at the credential check with `401 Unauthorized` from
`npm whoami`. That reads as a revoked or mistyped token. It was neither — the
token is fine and the workflow was wrong.

This repository's `.npmrc` reads
`//registry.npmjs.org/:_authToken=${NPM_TOKEN}`, and npm's project config
outranks the userconfig that `setup-node` writes. So for any command run from
the repository root the repo `.npmrc` wins, and it wants NPM_TOKEN — a name the
workflow never set, because it set only NODE_AUTH_TOKEN.

Critically, npm does not fall back to the userconfig when the variable is
missing. It sends the literal, unexpanded text as the bearer token. Confirmed
against a local registry that echoes the Authorization header:

    NPM_TOKEN unset  ->  AUTH_HEADER: "Bearer ${NPM_TOKEN}"
    NPM_TOKEN set    ->  AUTH_HEADER: "Bearer REAL_TOKEN_VALUE"

The first is indistinguishable, from the registry's side, from a garbage
credential — hence the 401 and the misleading diagnosis.

Both publish steps now set NPM_TOKEN alongside NODE_AUTH_TOKEN. They stay
step-scoped rather than job-scoped so the token is not exposed to `pnpm -r test`.

verify-npm-publish-access.mjs now checks NPM_TOKEN is present and expanded before
calling the registry, so a recurrence names the cause instead of surfacing an
authentication error that sends you looking at the token.

Verified: both guard paths exit 1 with an accurate message, architecture guard
passes, workflow YAML parses with the trigger intact.
Copilot AI review requested due to automatic review settings July 27, 2026 01:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@qmarcelle
qmarcelle merged commit 3b878c9 into main Jul 27, 2026
3 checks passed
@qmarcelle
qmarcelle deleted the fix/publish-npm-token-env branch July 27, 2026 03:40
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.

2 participants