Files
pnpm/pnpm11/installing
Zoltan Kochan 1dd12bd515 feat(pnpr): make resolver cache authorization-aware (#12700)
Make the pnpr resolver cache authorization-aware and route private
dependencies through per-uplink registry endpoints.

Add route classification at the single fetch/auth-selection point: pnpr
selects its own server-owned upstream credentials instead of forwarding
client upstream auth, records a per-resolve footprint, and rejects inline
URL credentials. A uplinks: entry that declares an access: policy becomes
the private-route credential (folding in the former upstreamAliases block),
matched by registry origin and exposed as a read-only registry endpoint at
/~<uplink>/. access reuses bearer-token-backed pnpr identities, package
access policy, and static groups; a SHA-256 digest of the uplink's credential
participates in the footprint, so rotating the upstream credential
automatically moves new resolves to a fresh namespace. The credential is
attached only over a matching scheme (no token over plain http).

Gate every server-side fetch behind a default-deny allowlist (built-in npm
host, public routes, configured uplinks and their /~<uplink>/ endpoints, and
pnpr itself). A registry/namedRegistries matching none is rejected at the
request boundary, closing the resolver's SSRF surface at the source and
superseding the link-local denylist. The boundary also covers direct-URL
(http(s)/git, incl. scp-style) dependency specs, overrides, and lockfile
tarballs; a `..` path segment is rejected; and the same allowlist re-validates
every redirect hop. The official npm registry is a built-in host-level public
route (scoped names included), so the npmjsPublic toggle is gone. With no
off-allowlist route to resolve, every route is public or carries a private
descriptor: RouteClass::Unknown, the non-shareable footprint tier, and the
MetadataCacheScope::Bypass tier are removed. Transitive deps fetched during the
tree walk are a connect-time-guard follow-up (pnpm/pnpm#12705).

Route resolver tarball URLs through those endpoints. A proxied route emits
its /~<uplink>/ endpoint URL; public routes keep their upstream URL (fetched
directly from the registry/CDN); pnpr-hosted packages use pnpr-hosted URLs.
An endpoint URL is canonical for a client whose scope
points there, so the lockfile entry stays integrity-only and the host comes
from the client's registry config rather than the lockfile — a project
resolves to the same lockfile through /resolve or a direct/proxied install.
verification_lockfile reverses endpoint URLs to upstream for input-lockfile
verification, and classification recognizes pnpr's own /~<uplink>/ URLs.
The opaque per-tarball gateway scheme and its in-memory key->URL map are
removed.

Serve each access-bearing uplink as a /~<uplink>/ registry endpoint
(packument + tarball, gated by the uplink access policy) with a private
cache namespaced by an HMAC of (uplink, credential), so a private install
caches like a public one, a rotation re-keys automatically, and a private
uplink's content never lands in the shared mirror.

Store bounded candidate lists under an auth-excluded base key instead of a
single lockfile. Public candidates match every caller; private candidates
carry the footprint and descriptor HMAC and are reused only when the caller
still satisfies the stored uplink-or-hosted gates. Compute the base key for
both no-lockfile and lockfile-seeded requests, using hash_lockfile() for
input lockfiles, and evict expired/LRU private candidates before public
ones.

Record metadata fast-path routes into the footprint. The hook only fires at
the auth-selection point, which the npm resolver's metadata fast paths
(in-memory hit, offline disk read, version-spec exact match, publishedBy
mtime shortcut) bypass. AuthHeaders::record_route drives the hook without a
request, called up front in pick_package so every layer contributes to the
footprint.

Scope the npm metadata mirror by private access descriptor. A
MetadataCacheScope (Public / Private) classified per (registry, package)
fetch threads through pick_package, fetch_full_metadata_cached, the mirror
path, in-memory/fetch-lock keys, and the verifier's local-mirror read. A
private route stores its packument under v11/metadata-private/<descriptor-id>/.
Fail closed on 401/403/private-404. The CLI installs no hook, so every fetch
stays Public and the global mirror is unchanged.

Related to pnpm/pnpm#12699 and pnpm/rfcs#11.
2026-06-28 21:51:47 +02:00
..
2026-06-23 17:16:24 +02:00
2026-06-23 17:16:24 +02:00
2026-06-23 17:16:24 +02:00
2026-06-23 17:16:24 +02:00