Skip to content

chore(npm): pnpm 11+ ignores the env-var token in every repo's committed .npmrc #324

Description

@BryanFRD

Every repo in the org commits a .npmrc whose GitHub Packages token is an environment variable:

@ferrlabs:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
always-auth=true

pnpm 11 and later refuse to expand that variable, on the grounds that a committed file could leak the secret to an attacker-controlled registry:

[WARN] Ignored project-level auth setting "//npm.pkg.github.com/:_authToken" in
"/home/runner/_work/FerrLens-Cloud/FerrLens-Cloud/.npmrc": environment variables are not
expanded in registry credentials that come from a project .npmrc, because that file is
committed to the repository and could leak the secret to an attacker-controlled registry.

Found while getting FerrLens-Cloud onto pnpm 12 (FerrLabs/FerrLens-Cloud#451).

CI is not affected, and it is worth being precise about why

reusable-ci-node.yml passes registry-url and scope to actions/setup-node, which writes a user-level npmrc and points pnpm at it:

NPM_CONFIG_USERCONFIG: /home/runner/_work/_temp/.npmrc

pnpm still expands variables from a user-level config, so the token arrives through that path and resolution completes. The committed project .npmrc is redundant in CI and contributes only two warning lines per install.

So this is not a CI outage, and nothing is on fire.

What does break: local development

A developer who exports NODE_AUTH_TOKEN and relies on the committed .npmrc has no user-level config to fall back on. Under pnpm 11+ their token is silently dropped, and the first cold-store fetch of a private @ferrlabs/* package 401s. The failure is confusing because the warning is easy to scroll past and the .npmrc looks correct.

Today the blast radius is small because most people have a warm pnpm store. It grows the moment someone clones fresh, clears the store, or onboards.

Scope

All nine repos carry the identical committed file:

FerrLens-Cloud     FerrFlow-Cloud     FerrVault-Cloud
FerrTrack-Cloud    FerrGrowth-Cloud   FerrAgents
FerrLabs-Cloud     FerrGames-Cloud    UI

The trigger is pnpm 11+, so it lands per repo as each one takes the bump. FerrLens is first (#451); the rest follow.

Options

  1. Keep the registry mapping in the project file, move the credential out. @ferrlabs:registry=... is not a secret and belongs in the repo; only the _authToken line is the problem. Document pnpm config set "//npm.pkg.github.com/:_authToken" <token> as the one-time developer setup, and drop the line from all nine .npmrc files. This is what pnpm's own message recommends and it removes the warning from CI too.
  2. Leave it and accept the warnings. Defensible only until someone hits the cold-store 401; the diagnosis cost is the real price.

Option 1 also removes a small footgun that predates pnpm 11: a committed file that looks like it carries a credential invites someone to paste a literal token into it one day.

Suggested work

  • Add the pnpm config set step to the contributor setup docs.
  • Strip the _authToken line from the nine .npmrc files, keeping the registry mapping.
  • Confirm reusable-ci-node.yml needs no change (it does not — setup-node already supplies the credential), and note that in the workflow so the next reader does not re-add it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions