fix: respect project .npmrc without requiring registry-url#54
Conversation
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
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
There was a problem hiding this comment.
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
.npmrcdetection +${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-urlis absent (leaving the existingregistry-urlbehavior 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.
|
@cursor review |
There was a problem hiding this comment.
✅ 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.
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
|
@cursor review |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
✅ 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
## 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`
Summary
When the workflow doesn't pass
registry-url, honor the project.npmrcand makeNODE_AUTH_TOKEN"just work" — so the repo's.npmrccan stay minimal and the workflow doesn't have to duplicate registry config.Three things happen in the no-
registry-urlbranch:_authTokenfor declared registries. IfNODE_AUTH_TOKENis set in env and the project.npmrcdeclares a registry (e.g.@myorg:registry=https://npm.pkg.github.com) without a matching_authTokenentry, write//<host>/:_authToken=${NODE_AUTH_TOKEN}to$RUNNER_TEMP/.npmrcand pointNPM_CONFIG_USERCONFIGat it. This mirrors thesetup-node+pnpm/action-setupexperience without requiringregistry-urlin the workflow._authTokenentries. If the repo.npmrcalready has an_authTokenline for that registry (case-insensitive), it's left alone — no supplemental file is written.${VAR}references viaGITHUB_ENV. Any env vars referenced in the project.npmrc(e.g.${NODE_AUTH_TOKEN},${NPM_TOKEN}) that are set inprocess.envare re-exported so they persist to thevp installsubprocess and subsequent steps. Runner-managed namespaces (RUNNER_*,GITHUB_*) are blocked by prefix withGITHUB_TOKENon an explicit allowlist, so a.npmrcreferencing${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.npmrckeys, so the synthesized_authTokenline would be unreachable. The referenced var is still collected for env propagation.The existing
registry-urlpath is unchanged.Minimal config after this PR
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
src/auth.ts, next to the existingregistry-urlwritergetRunnerNpmrcPath,stripProtocol,authKeyFor,buildAuthLine,NODE_AUTH_TOKEN_REF,readNpmrc— both write paths use them so URL/auth-line handling is in one placereadNpmrcuses try/catch onENOENT(noexistsSync+readFileSyncTOCTOU)$RUNNER_TEMP/.npmrcalready matches the target content, the write is skipped and the log is downgraded todebugisReservedEnvVaruses prefix-based blocking (RUNNER_*,GITHUB_*) with an allowlist forGITHUB_TOKENCloses #50
Test plan
propagateProjectNpmrcAuthinsrc/auth.test.tscover:_authTokenfor scoped + default registries_authTokenlines (case-insensitive)NODE_AUTH_TOKENis unset.npmrc$RUNNER_TEMP/.npmrc_authTokenentries for the same registry${VAR}RUNNER_*/GITHUB_*vars, allowingGITHUB_TOKEN${VAR}env vars, skipping reserved system vars and unset vars, deduping repeatsENOENTvs other read errorsvp run test— 115 tests passvp run typecheck— cleanvp run check:fix— cleanvp run build—dist/index.mjsrebuilttest-registry-urljob continues to pass (unchanged path).npmrc(registry line only) +NODE_AUTH_TOKEN, noregistry-url