Skip to content

fix: respect project .npmrc without requiring registry-url#54

Merged
fengmk2 merged 5 commits intomainfrom
fix/respect-project-npmrc
Apr 22, 2026
Merged

fix: respect project .npmrc without requiring registry-url#54
fengmk2 merged 5 commits intomainfrom
fix/respect-project-npmrc

Conversation

@fengmk2
Copy link
Copy Markdown
Member

@fengmk2 fengmk2 commented Apr 22, 2026

Summary

When the workflow doesn't pass registry-url, honor the project .npmrc and make NODE_AUTH_TOKEN "just work" — so the repo's .npmrc can stay minimal and the workflow doesn't have to duplicate registry config.

Three things happen in the no-registry-url branch:

  1. Auto-generate _authToken for declared registries. If NODE_AUTH_TOKEN is set in env and the project .npmrc declares a registry (e.g. @myorg:registry=https://npm.pkg.github.com) without a matching _authToken entry, write //<host>/:_authToken=${NODE_AUTH_TOKEN} to $RUNNER_TEMP/.npmrc and point NPM_CONFIG_USERCONFIG at it. This mirrors the setup-node + pnpm/action-setup experience without requiring registry-url in the workflow.
  2. Respect existing _authToken entries. If the repo .npmrc already has an _authToken line for that registry (case-insensitive), it's left alone — no supplemental file is written.
  3. Propagate ${VAR} references via GITHUB_ENV. Any env vars referenced in the project .npmrc (e.g. ${NODE_AUTH_TOKEN}, ${NPM_TOKEN}) that are set in process.env are re-exported so they persist to the vp install subprocess and subsequent steps. Runner-managed namespaces (RUNNER_*, GITHUB_*) are blocked by prefix with GITHUB_TOKEN on an explicit allowlist, so a .npmrc referencing ${GITHUB_REF} or similar can't clobber runner-provided values for downstream steps.

Registry values containing ${VAR} (e.g. registry=${CUSTOM_REGISTRY}) are skipped for auth-key synthesis — npm/pnpm don't expand env vars inside .npmrc keys, so the synthesized _authToken line would be unreachable. The referenced var is still collected for env propagation.

The existing registry-url path is unchanged.

Minimal config after this PR

# .npmrc in the repo — auth line not required, action adds it:
#   @myorg:registry=https://npm.pkg.github.com

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version: "lts"
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Before this PR, the workflow above would fail without also passing registry-url: https://npm.pkg.github.com, duplicating config the repo already has.

Implementation notes

  • All logic lives in src/auth.ts, next to the existing registry-url writer
  • Shared primitives: getRunnerNpmrcPath, stripProtocol, authKeyFor, buildAuthLine, NODE_AUTH_TOKEN_REF, readNpmrc — both write paths use them so URL/auth-line handling is in one place
  • readNpmrc uses try/catch on ENOENT (no existsSync + readFileSync TOCTOU)
  • On re-runs, if $RUNNER_TEMP/.npmrc already matches the target content, the write is skipped and the log is downgraded to debug
  • isReservedEnvVar uses prefix-based blocking (RUNNER_*, GITHUB_*) with an allowlist for GITHUB_TOKEN

Closes #50

Test plan

  • 18 unit tests for propagateProjectNpmrcAuth in src/auth.test.ts cover:
    • auto-writing _authToken for scoped + default registries
    • respecting existing _authToken lines (case-insensitive)
    • not writing when NODE_AUTH_TOKEN is unset
    • multiple missing registries in one project .npmrc
    • preserving unrelated lines already in $RUNNER_TEMP/.npmrc
    • replacing stale _authToken entries for the same registry
    • no-op re-run (skipped write)
    • skipping registries whose value contains ${VAR}
    • blocking runner-managed RUNNER_* / GITHUB_* vars, allowing GITHUB_TOKEN
    • propagation of ${VAR} env vars, skipping reserved system vars and unset vars, deduping repeats
    • ENOENT vs other read errors
  • vp run test — 115 tests pass
  • vp run typecheck — clean
  • vp run check:fix — clean
  • vp run builddist/index.mjs rebuilt
  • Existing CI test-registry-url job continues to pass (unchanged path)
  • Manual verification in a workflow with repo .npmrc (registry line only) + NODE_AUTH_TOKEN, no registry-url

When the workflow does not pass `registry-url`, detect the project's
`.npmrc`, scan it for `${VAR}` references, and re-export any referenced
env vars that are set (e.g. `NODE_AUTH_TOKEN`) via `@actions/core`
`exportVariable`. This writes them to `GITHUB_ENV`, so the token is
reliably visible to the `vp install` subprocess and subsequent steps.

Users with a repo-level `.npmrc` (common for GitHub Packages setups) no
longer have to duplicate their registry config in the workflow.

Closes #50
Copilot AI review requested due to automatic review settings April 22, 2026 11:56
@fengmk2 fengmk2 self-assigned this Apr 22, 2026
Review-driven simplification:
- Merge propagateProjectNpmrcAuth into src/auth.ts since both the
  registry-url write path and the .npmrc read path are concerned with
  the same thing: .npmrc + auth env export
- Replace existsSync + readFileSync TOCTOU with try/catch on ENOENT
- Dedupe referenced env vars with a single Set instead of Set + array
- Drop detectProjectNpmrc / ProjectNpmrc from the public surface;
  test only the observable behavior of propagateProjectNpmrcAuth
- Remove narrative comment in index.ts — the function name carries it
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates setup-vp to respect an in-repo .npmrc when registry-url is not provided, so auth env vars referenced by .npmrc can be propagated in a way that remains visible to installs and later workflow steps.

Changes:

  • Added .npmrc detection + ${VAR} reference extraction, and propagation of referenced env vars via @actions/core.exportVariable.
  • Wired the new propagation path into the main action flow when registry-url is absent (leaving the existing registry-url behavior unchanged).
  • Added unit tests for detection/propagation and updated README guidance; rebuilt dist/index.mjs.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/npmrc-detect.ts Implements project .npmrc detection and env-var propagation.
src/npmrc-detect.test.ts Adds unit tests covering detection and propagation behavior.
src/index.ts Integrates .npmrc propagation when registry-url isn’t set.
dist/index.mjs Rebuilt compiled action output including the new behavior.
README.md Documents .npmrc-based auth as the default path and registry-url as fallback.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 22, 2026

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b776fb5. Configure here.

fengmk2 added 2 commits April 22, 2026 20:28
When NODE_AUTH_TOKEN is set but the project .npmrc declares a custom
registry without a matching _authToken entry, write one to
$RUNNER_TEMP/.npmrc and point NPM_CONFIG_USERCONFIG at it. The repo's
.npmrc can now stay minimal — just `@scope:registry=<url>` — mirroring
the setup-node + pnpm/action-setup experience without requiring
registry-url in the workflow.

- Parse project .npmrc for registries, existing _authToken keys, and
  ${VAR} references
- Skip any registry that already has an _authToken entry
- Preserve unrelated lines in RUNNER_TEMP/.npmrc; only replace stale
  _authToken entries for the same registry
- Still propagate referenced env vars via GITHUB_ENV as before
Review-driven simplifications to src/auth.ts:

- Extract shared primitives: getRunnerNpmrcPath(), stripProtocol(),
  authKeyFor(), buildAuthLine(), NODE_AUTH_TOKEN_REF — both the
  registry-url write path and the project-.npmrc auto-auth path now
  share the same URL/auth-line logic
- Collapse ParsedNpmrc/parseNpmrc into analyzeProjectNpmrc which
  returns only what the caller needs: registriesNeedingAuth + envVarRefs
- Replace existsSync + readFileSync (TOCTOU) with a readNpmrc helper
  that catches ENOENT
- Flatten the nested filter conditional in writeSupplementalAuth
- Guard the write+log when the supplemental .npmrc already matches,
  so re-runs don't spam a misleading "Wrote _authToken entries" line
- Use a named NODE_AUTH_TOKEN_REF constant to avoid the template-literal
  escape vs plain-string inconsistency between the two write paths
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented Apr 22, 2026

@cursor review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/auth.ts Outdated
Comment thread src/auth.ts
Comment thread README.md Outdated
Comment thread src/auth.test.ts
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f61ca9e. Configure here.

- Switch RESERVED_ENV_VARS from a fixed denylist to prefix-based blocking
  (RUNNER_*, GITHUB_*) with GITHUB_TOKEN on an explicit allowlist. Previously
  a `.npmrc` referencing e.g. ${GITHUB_REF} or ${RUNNER_NAME} would re-export
  those via GITHUB_ENV and clobber runner-provided values for later steps
- Skip registry values containing ${VAR} when computing registriesNeedingAuth;
  npm/pnpm do not expand env vars inside `.npmrc` keys, so synthesizing an
  `_authToken` line against a non-literal URL would silently produce an
  unreachable auth entry. The referenced var is still collected for env
  propagation
- Reword the README so `registry-url` is described as bypassing the action's
  repo-.npmrc detection, not the package manager's config resolution
@fengmk2 fengmk2 merged commit 4f5aa3e into main Apr 22, 2026
41 checks passed
@fengmk2 fengmk2 deleted the fix/respect-project-npmrc branch April 22, 2026 13:07
fengmk2 added a commit to voidzero-dev/setup.viteplus.dev that referenced this pull request Apr 22, 2026
## Summary

Refactor CI/deploy workflows to use the new `setup-vp` behavior from
[voidzero-dev/setup-vp#54](voidzero-dev/setup-vp#54).

- Drop `registry-url: https://npm.pkg.github.com` from all `setup-vp`
steps in `.github/workflows/ci.yml` and `.github/workflows/deploy.yml`.
- Rely on the repo-level `.npmrc`
(`@void-sdk:registry=https://npm.pkg.github.com`) plus `NODE_AUTH_TOKEN`
env: the action auto-generates a matching `_authToken` entry at
`$RUNNER_TEMP/.npmrc` for each registry declared in the project `.npmrc`
that doesn't already have one.
- The checked-in `.npmrc` stays minimal — no auth line needed.

## Pinning

Pinned to commit `af4ffd95e8c3d93e048fe8f03afeb2d4e3eba927` (head of PR
#54's `fix/respect-project-npmrc` branch) via a commented SHA. Bump back
to `@v1` once the PR merges and is released.

## Test plan

- [ ] `test` job on this PR runs `vp install` successfully (private
`@void-sdk/*` packages resolve from GitHub Packages)
- [ ] `staging-deploy` job on this PR completes `vpx void deploy`
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.

vp install should respect .npmrc/custom registry config in CI without requiring registry-url

2 participants