Skip to content

fix(libnpmexec): honor min-release-age-exclude when resolving specs - #9944

Open
MrRio wants to merge 2 commits into
npm:latestfrom
MrRio:fix/npx-min-release-age-exclude
Open

fix(libnpmexec): honor min-release-age-exclude when resolving specs#9944
MrRio wants to merge 2 commits into
npm:latestfrom
MrRio:fix/npx-min-release-age-exclude

Conversation

@MrRio

@MrRio MrRio commented Sep 3, 2026

Copy link
Copy Markdown

Description

npx resolves its spec with pacote.manifest, forwarding flatOptions.before (set by min-release-age). pacote knows nothing about min-release-age-exclude, so excluded packages still failed with ETARGET. npm install isn't affected because arborist drops before per-spec for exempted names.

This matters because it undermines the release-age protection itself: min-release-age-exclude exists so teams can keep a strict age window on third-party packages while still running their own trusted packages immediately. With npx ignoring it, the only workaround is --min-release-age=0, which turns the supply-chain safeguard off for the entire transitive tree instead of just the one exempted package.

This makes libnpmexec do the same before calling pacote.manifest, reusing arborist's release-age-exclude.js helper (isReleaseAgeExcluded + trustedSpecName, so npm: alias keys can't exempt the package they resolve to). The deep require follows the existing pattern in strict-allow-scripts-preflight.js; no new dependencies. The install into the npx cache already goes through arborist, so only the direct manifest lookup needed fixing.

Testing

Two tests added to workspaces/libnpmexec/test/registry.js: an excluded spec resolves and runs despite a past before cutoff (fails with ENOVERSIONS without the fix), and a non-excluded spec is still blocked.

Verified manually from this checkout against the public registry, using a package version published inside the age window (pnpm@11.25.0, published 2026-08-29):

Before this change, the exclude pattern is ignored:

$ node . exec --min-release-age=10 --min-release-age-exclude=pnpm --yes -- pnpm@11.25.0 --version
npm error code ETARGET
npm error notarget No matching version found for pnpm@11.25.0 with a date before 24/08/2026 ...

After this change, the same command resolves and runs:

$ node . exec --min-release-age=10 --min-release-age-exclude=pnpm --yes -- pnpm@11.25.0 --version
11.25.0

The filter itself still applies — dropping --min-release-age-exclude from the command above still fails with ETARGET after this change.

Fixes #9765

Alternative to #9768 — reuses arborist's helper instead of duplicating the minimatch logic in libnpmexec.

npx resolves its requested spec with pacote.manifest directly, passing
flatOptions.before (set by min-release-age) straight through. pacote has
no knowledge of min-release-age-exclude, so packages matching an exclude
pattern were still rejected with ETARGET/ENOVERSIONS.

Reuse arborist's release-age-exclude helper (the same logic npm install
applies per-spec) to drop the before cutoff when the spec's trusted name
matches an exclude pattern.

Fixes: npm#9765
@MrRio
MrRio requested review from a team as code owners September 3, 2026 05:40
@MrRio

MrRio commented Sep 3, 2026

Copy link
Copy Markdown
Author

@martinrrm would you be able to take a look at this as an approach? Making things tricky for our users without it as we want to protect them from supply chain attack risk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] min-release-age-exclude is not honored by npx

1 participant