fix(arborist): allow-remote exemption for proxy/mirror-fronted registry tarballs (#9550)
With `allow-remote=none` (the default on npm 12) or `allow-remote=root`, a `npm install` fails with `EALLOWREMOTE` on ordinary registry dependencies when the configured registry origin differs from the lockfile `resolved` origin. ``` npm error code EALLOWREMOTE npm error Fetching packages of type "remote" have been disabled ``` This is the common proxy/mirror case: a committed `package-lock.json` whose `resolved` URLs point to `https://registry.npmjs.org/...`, while the machine (or CI) is configured to use a private registry proxy/mirror with a different origin. It affects both the hoisted and the linked install strategy. ## Why When extracting a registry-resolved package, reify hands pacote a `name@URL` spec, which pacote re-parses as `type=remote` and gates with allow-remote. To avoid mis-firing on registry tarballs, `#isRegistryResolvedTarball` exempts them — but it compared the raw lockfile `resolved` URL against the configured registry origin. With a proxy/mirror configured, `resolved` is the canonical `registry.npmjs.org` URL while the configured registry is the proxy, so the origins never matched, the exemption returned `false`, and the registry tarball was rejected as remote. Crucially, reify already fetches a different URL than the raw `resolved`: `#registryResolved` applies `replace-registry-host` (default `npmjs`), rewriting the `registry.npmjs.org` host to the configured registry while preserving the path. So npm fetches the tarball from the proxy correctly; only the allow-remote check was evaluating the wrong (pre-rewrite) URL. ## How Evaluate the effective URL npm actually fetches, not the raw lockfile value. `#isRegistryResolvedTarball` now parses `this.#registryResolved(node.resolved)` — the host-rewritten URL — before the same origin + registry-path-prefix comparison. After rewriting, a public-registry-pinned tarball resolves to the configured registry and is correctly recognized as registry-mediated. The existing security boundary is preserved: under the default `replace-registry-host`, a same-origin tarball pointing outside the registry path is not rewritten and is still rejected, and a genuinely URL-declared dependency still fails the `node.isRegistryDependency` guard. Under `replace-registry-host=always`, every tarball is routed through the configured registry, so registry dependencies are no longer treated as remote — consistent with what `always` means. ## References Fixes #9548
M
Manzoor Wani committed
8bbd70d939cec237b4e045993955895971c9eb85
Parent: 315e3bd
Committed by GitHub <noreply@github.com>
on 6/18/2026, 9:09:51 PM