* 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.
The git fetcher passed the lockfile-controlled `resolution.commit` value
to `git fetch --depth 1 origin <commit>` and `git checkout <commit>`
without a `--` separator and without validating that the value is a
SHA. A malicious lockfile could smuggle a value such as
`--upload-pack=touch /tmp/pwned`, which `git` parses as an option. On
SSH and local-file transports `--upload-pack` runs the supplied
command. HTTPS ignores it, but the SSH/file paths are enough to
execute code as the user running `pnpm install`.
Validate `resolution.commit` against `/^[0-9a-f]{40}$/i` at the entry
of the fetcher and throw `INVALID_GIT_COMMIT` otherwise. The check is
strictly stronger than adding a `--` separator: a validated value
cannot start with `-` or contain shell-significant characters at all.
Backport of #11967 to release/10.
---
Written by an agent (Claude Code, claude-opus-4-7).
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
sveltejs/action-deploy-docs was deleted/privated, causing git clone to
prompt for credentials and fail in non-interactive CI. Matches the repo
already used on the v11 branch.
* 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.
* fix(tarball-resolver): add integrity hash to HTTP tarball dependencies
* Refactor to download tarball just once
* Fix tests
* fix: only calc hash when it is not passed in to the fetcher
* docs: update changesets
* feat: print a warning if network requests are slow
* feat: print a warning if network requests are slow
add a new setting for fetch tarball speed
* feat: print a warning if network requests are slow
* fix: src/fetch.ts
* docs: add changeset