* fix(security): harden build-approval artifact identities on v10
Port of pnpm/pnpm#12294 (commit bf1b731ee6) to release/10.
Package-name entries in onlyBuiltDependencies (and allowBuilds) no longer
approve lifecycle scripts for artifacts whose identity a name cannot pin:
git, git-hosted tarball, direct tarball, and local directory dependencies.
To approve such an artifact explicitly, use its peer-suffix-free lockfile
depPath as the key — the GIT_DEP_PREPARE_NOT_ALLOWED hint, pnpm
ignored-builds, and pnpm approve-builds print exactly that key.
- AllowBuild policy functions identify packages by DepPath instead of
caller-supplied name/version. Identity trust is derived from the depPath
shape: a registry-style depPath (name@semver) is a trusted identity.
- The trust is sound because lockfile entries are structurally checked
wherever they are materialized into fetchable resolutions
(pkgSnapshotToResolution) and before rebuild runs scripts: a
registry-style key backed by a git, directory, or git-hosted tarball
resolution is rejected with ERR_PNPM_RESOLUTION_SHAPE_MISMATCH.
- preparePackage requires a pkgResolutionId and gates on the synthesized
name@<resolution id> depPath; scp-style git URLs are normalized to
ssh:// form in resolution ids and the git fetcher reuses
createGitHostedPkgId from the resolver.
- isGitHostedTarballUrl matches case-insensitively and is shared from
@pnpm/lockfile.utils; new removePeersSuffix() in @pnpm/dependency-path
and allowBuildKeyFromIgnoredBuild() in @pnpm/builder.policy.
- pnpm rebuild and approve-builds accept depPath specs for selecting and
approving artifact builds; installs rebuild ignored builds approved by
depPath keys.
- shell-quote is overridden to 1.8.4 (GHSA-w7jw-789q-3m8p /
CVE-2026-9277).
Differences from main: v10 has no lockfile resolution verifier, so the
structural pass lives in pkgSnapshotToResolution and the rebuild loop; the
AllowBuild policy keeps v10's boolean return; the revoked-approval
detection and global-virtual-store hash changes have no v10 counterpart.
* test: serve the direct-tarball fixture from an off-registry origin
The registry mock binds only localhost, so a hard-coded 127.0.0.1 URL is
refused in CI, and a tarball URL on the registry's own origin resolves as
a registry package, which defeats the direct-tarball identity the test
needs. An in-test HTTP server redirecting to the mock provides a separate
origin whose binding the test controls.
* test: approve the git-protocol licenses fixture by its depPath
A git-hosted artifact has an untrusted package identity, so the
ajv-keywords build has to be approved by its depPath. Pin the fixture to
the commit the depPath names.
Cherry-pick of #11481 from main, adapted to the v10 layout.
For git-hosted tarballs (codeload.github.com / gitlab.com / bitbucket.org)
the fetcher dropped the integrity it computed while downloading, so the
lockfile only stored the URL. A compromised git host or man-in-the-middle
could serve a substituted tarball on subsequent installs and pnpm would
install it without lockfile changes.
This pins the SHA-512 SRI of the raw tarball in the lockfile in the same
sha512-<base64> form npm-registry tarballs use; subsequent installs verify
the download against that integrity in the worker.
A new optional gitHosted: boolean field is recorded on TarballResolution
so every store-key consumer can route by a single typed read instead of
re-deriving the routing from the URL. Lockfiles written by older pnpm
versions are enriched on load (URL fallback) so the field can be relied
on uniformly.
🤖 Cherry-picked by Claude (claude-opus-4-7) on behalf of @zkochan
* fix(git-fetcher): ensure the specified commit is used after checkout
* fix(git-resolver): always resolve to a full commit
* chore: add changeset heavy-dragons-start
* test: fix related test case
* test: fix some other test that gets stuck
* Update heavy-dragons-start.md with PR reference
Add reference to pull request #10310 for clarity.
* chore: `package.json` add type field
* chore: add type field to every package.json
* chore: add type field to every package.json
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
* fix(git-resolver): handle private git repo resolution
In the case where:
1. No git auth token was specified by the user
2. The package requested to be fetched via https
3. The user does not have SSH access to the repo but has HTTPS access
4. The package was hosted in a private GitHub repo
pnpm would fallback to using SSH since it was a "likely private repo"
and would fail to resolve the package. Now, rather than only checking if
there is an auth token specified, it also checks both:
1. Is the repo private
2. Does the user have access to ls-remote it.
And if these conditions are true, it tries to use https anyway.
This matches the behavior of npm and Yarn berry. Yarn classic also has
this bug, and there's a code comment that alludes to it.