ci: move the GitHub Packages credential out of the project .npmrc - #5
Merged
Merged
Conversation
The repo-root .npmrc carried the credential as an env placeholder:
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
pnpm 10 stopped expanding environment variables in registry credentials that
come from a project .npmrc — the file is committed, so a hostile registry line
could exfiltrate the token. The placeholder is honoured by the pinned pnpm
9.15.0 and ignored by anything newer, which is a trap: local installs warn on
every command today, and the day `packageManager` moves to pnpm 10 the
credential silently resolves to nothing and CI fails with a bare 401 that names
no cause.
The registry mapping stays in the project .npmrc, which is what it is for. The
credential moves to a source pnpm still trusts at every version:
- CI writes the NODE_AUTH_TOKEN secret into the runner's ~/.npmrc in an
explicit step before install.
- Locally it is a one-time `pnpm config set ... --global`, replacing the
per-shell `export $(grep ... .env.local)` that pnpm 10+ would ignore
anyway.
The secret is now scoped to the auth step rather than the whole job, so it is
absent from the environment during `pnpm install` — where dependency lifecycle
scripts run — and during the test and build steps. No job needed it elsewhere.
.env.example previously advertised NODE_AUTH_TOKEN as a variable to set; it now
says why the credential does not belong in that file at all, so the next person
does not re-add a line that cannot work.
Verified: `pnpm install --frozen-lockfile` succeeds with the credential absent
from the project .npmrc and emits no warning; the workflow parses and all three
jobs place the auth step immediately before their install.
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.
Moves the GitHub Packages credential out of the committed
.npmrcand into a source pnpm trusts at every version. Split out of #4 so a CI-auth regression can be reverted on its own.The trap
The repo-root
.npmrccarried the credential as an env placeholder:pnpm 10 stopped expanding environment variables in registry credentials read from a project
.npmrc— that file is committed, so a hostile registry line could exfiltrate the token. The result is a version-dependent split:packageManager)So the line works in CI, warns on every local command (Homebrew pnpm 11 shells out to the pinned 9.15.0, and the outer binary parses
.npmrcfirst), and the daypackageManagermoves to pnpm 10 it silently stops authenticating. The failure mode then is a bare401from the registry that names no cause.Confirmed the credential is genuinely required — the registry returns
HTTP 401unauthenticated, and CI has no other credential source.The change
The scope→registry mapping stays in the project
.npmrc; that's what it's for. Only the credential moves.NODE_AUTH_TOKENsecret into the runner's~/.npmrcin an explicit step before install, in all three jobs.pnpm config set "//npm.pkg.github.com/:_authToken" <PAT> --global, replacing the per-shellexport $(grep ... .env.local)that pnpm 10+ would ignore anyway. Verified this writes to~/.npmrc.Secret scoping
NODE_AUTH_TOKENmoves from job-levelenvto the auth step alone. It's now absent from the environment duringpnpm install— where dependency lifecycle scripts run — and during the test and build steps. No other step needed it.Docs
.env.examplepreviously advertisedNODE_AUTH_TOKENas a value to fill in. It now explains why the credential doesn't belong in that file, so the next person doesn't re-add a line that cannot work. README gains an "Authenticate to GitHub Packages" step;AGENTS.mdrecords the pnpm 10 rule as the reason.Verification
pnpm install --frozen-lockfilesucceeds with the credential absent from the project.npmrc, and the warning is gone..npmrccarrying no credential.