fix(install): honour the machine npm registry in the portable Node.js runtime - #57
Merged
Giorgio Ughini (GiorgioUghini) merged 1 commit intoAug 7, 2026
Conversation
The installers unpack a portable Node.js archive and run its bundled npm.
Node.js ships the builtin npmrc that sets `prefix=${APPDATA}\npm` only in the
Windows MSI, so the portable archive leaves npm resolving `globalconfig` inside
the throwaway runtime directory. On machines whose npm registry is configured in
the global npmrc rather than a user `~/.npmrc`, npm never saw that file, fell
back to registry.npmjs.org, and `npm ci` failed with
ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE wherever network policy blocks the
public registry.
Locate the machine's real global npmrc before the portable runtime is prepended
to PATH and pass it to npm as NPM_CONFIG_GLOBALCONFIG. npm's default
`replace-registry-host=npmjs` then maps the lockfile's canonical npmjs URLs onto
the configured mirror, and the lockfile integrity hashes are still verified.
Machines without any npm configuration resolve no override and keep using
registry.npmjs.org exactly as before.
Also add a SKILL_RECORDER_NPM_REGISTRY escape hatch, report the registry that
will actually be used, and explain the mirror options when `npm ci` fails.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Merged
10 tasks
pull Bot
pushed a commit
to Stars1233/skill-recorder
that referenced
this pull request
Aug 7, 2026
PR microsoft#57 added a SKILL_RECORDER_NPM_REGISTRY escape hatch that made both installers reference the npm registry environment variable directly. That trips the deliberate compliance guard in scripts/compliance.test.mjs, which asserts the installers never pin an npm registry -- the exact regression that broke installs for users behind a corporate proxy in the first place. The escape hatch was redundant anyway: npm already honours a caller-set registry environment variable, so users keep the same capability without the installer sources dictating a registry. The actual fix stays: the installers still point the portable runtime at the machine's existing npm configuration via NPM_CONFIG_GLOBALCONFIG, which discovers rather than overrides the configured registry. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 02a84c32-5401-470c-a8f1-b5f7a3f1b05b
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.
Problem
Internal-Microsoft users cannot install the latest release.
npm cifails with:accompanied by a Windows Security toast: "This content is blocked by your IT admin ... [te] npm url block".
Root cause
The installers download a portable Node.js archive and run its bundled npm.
Node.js ships the builtin npmrc containing
prefix=${APPDATA}\npmonly in the Windows MSI — the.zip/.tar.gzarchives do not have it. Verified against a runtime the installer had already unpacked:So the portable npm resolves
prefixto its own throwaway runtime directory andglobalconfigto<runtime>\etc\npmrc, which never exists. On Microsoft-managed machines the corporate registry lives exactly in the global npmrc, and there is no user-level~/.npmrc:Reproduced by simulating the portable prefix:
With no configured registry, npm's
replace-registry-host=npmjshas nothing to remap to, so every tarball is fetched from the lockfile's canonicalregistry.npmjs.orgURLs — which network policy blocks.This surfaced in 0.4.0:
95b56c7correctly stopped committing internalms-feed-*.pkgs.visualstudio.comURLs in the lockfile (which broke external users) and removed theNPM_CONFIG_REGISTRY/NPM_CONFIG_REPLACE_REGISTRY_HOST=neveroverrides.INSTALL.mdnow relies on "npm may map those URLs to a configured compatible corporate registry" — but the portable runtime never sees that configuration.Fix
Locate the machine's real global npmrc before the portable runtime is prepended to
PATH(probenpm config get globalconfig, falling back to%APPDATA%\npm\etc\npmrc), and pass it to the portable npm viaNPM_CONFIG_GLOBALCONFIG.replace-registry-host=npmjsthen maps the canonical lockfile URLs onto the configured mirror.Also included:
SKILL_RECORDER_NPM_REGISTRYescape hatch (HTTPS-validated) for a one-off registry.npm cifailures explain the mirror options instead of just surfacing a TLS error.install.sh.No impact on external users
The override is applied only when an npm config file actually exists. On a machine with no npm configuration, nothing is set and npm keeps using
registry.npmjs.org. Verified:Security posture is unchanged: the lockfile's integrity hashes are verified whichever registry serves the packages, and
--ignore-scripts=false --dangerously-allow-all-scripts=false --strict-allow-scriptsare still passed on the command line, which outranks any config file.Verification
End-to-end
npm ciagainst a lockfile pinninghttps://registry.npmjs.org/zod/-/zod-4.4.3.tgz:Before (portable prefix, no globalconfig):
After (portable prefix + machine globalconfig):
Also run:
scripts\install-windows.test.ps1— passes, extended with coverage for the newResolve-MachineNpmConfigPathhelper (existing npmrc,undefined/nullplaceholders, missing file, quoted path).install.ps1parses cleanly under Windows PowerShell 5.1 and PowerShell 7.bash -n install.shclean;detect_machine_npm_configexercised with and without npm onPATH.node scripts/check-lockfile-portability.mjsstill passes.Note for a follow-up (not addressed here)
623 of 625 lockfile entries carry SHA-1 integrity (
sha1-...) rather thansha512-..., because the feed that generated the lockfile returns only the legacydist.shasum. That is a weaker integrity guarantee than intended and is worth regenerating separately.