Allow version-scoped entries in min-release-age-exclude
#204502
Unanswered
MorrisonCole
asked this question in
npm
Replies: 1 comment
|
💬 Your Product Feedback Has Been Submitted 🎉 Thank you for taking the time to share your insights with us! Your feedback is invaluable as we build a better GitHub experience for all our users. Here's what you can expect moving forward ⏩
Where to look to see what's shipping 👀
What you can do in the meantime 💻
As a member of the GitHub community, your participation is essential. While we can't promise that every suggestion will be implemented, we want to emphasize that your feedback is instrumental in guiding our decisions and priorities. Thank you once again for your contribution to making GitHub even better! We're grateful for your ongoing support and collaboration in shaping the future of our platform. ⭐ |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
🏷️ Discussion Type
Product Feedback
Body
Summary
min-release-age-exclude(npm/cli#9532, shipped in11.17.0) matches on package name only.First motivation is that with
min-release-ageconfigured,npm install <pkg>can silently resolve backwards off a patched version that is already in the lockfile, reverting a security fix with no error and no warning.Second is that having an explicit exception (like you can with Yarn (yarnpkg/berry#6901) / pnpm (pnpm/pnpm#9957), with Renovate even supporting adding versioned exclusion entries for the later for security updates) is just much easier to review and reason about (as opposed to reading the lockfile).
Motivation
npm/cli#8994 solved exclusions for first-party packages (e.g., exclude
@myorg/*) so that internal releases could install immediately while third-party dependencies stay behind the window.However, the other use of an exclude list is unblocking a security fix published inside the window. There, a name-wide form is both too broad and too permanent. Adding
lodashto pick up a patched4.18.1also exempts4.18.2,4.19.0, and everything published under that name from then on (i.e., a compromised release the following week installs with no delay). Nothing records that the exemption was only ever meant for one version, so nobody knows when it is safe to remove.To be clear about what the lockfile already handles: once a patched version is locked,
npm ciand a lockfile-in-syncnpm installboth install it regardless of the window. When re-resolving though, if the range still admits a pre-fix version npm resolves to that rather than erroring.The workarounds discussed in npm/cli#8994 (drop
min-release-age, install, re-add it; or a one-off--min-release-age=0) leave nothing durable in the repo to prevent the later silent revert, and--min-release-age=0additionally lifts the window for everything else that install touches.Reproduction
Reproduced on npm 11.19.0 and npm 12.0.2.
lodash@4.18.1was 130 days old at the time of writing and4.17.23is older than the window, somin-release-age=200excludes the newer version only.The locked
4.18.1is replaced by4.17.23in the lockfile with no error and no warning. If the range is tightened to^4.18.1the same command fails loudly instead, which is the correct and useful behaviour:Exemption attempts against the silent case:
.npmrcmin-release-age-exclude[]=lodash4.18.1- works, but exempts the package permanentlymin-release-age-exclude[]=lodash@4.18.14.17.23- parses fine, silently matches nothing (a bit of a trap especially if coming from Yarn/pnpm!)Note:
npm ci,npm installwith the lockfile in sync (andnpm install <unrelated-pkg>) all install the locked version. This issue is specifically about re-resolution of the affected package.Prior art
Yarn -
npmPreapprovedPackagesin.yarnrc.yml, added in 4.10.0 alongsidenpmMinimalAgeGate. Entries are parsed as package descriptors: the ident is matched with glob support, then the candidate version is tested against the descriptor's semver range; an entry with no range approves every version (npmConfigUtils.ts). Full ranges are accepted, not just exact versions.Yarn 4.18.0 has the same silent-downgrade behaviour as npm in the reproduction above (it also rewrites the range in
package.json), but the version-scoped exemption resolves it:With that in place,
yarn add lodashresolves to4.18.1instead of downgrading - the exemption holds the patched version through re-resolution and lapses by itself once the version ages past the gate.npm currently has no way to express that it as far as I can see!
Note that pnpm 11.21.0 actually enforces the window against the lockfile, so exclusions must be listed regardless of whether they're already present in the lockfile.
Proposal
Allow an optional version part per entry:
<name>[@<version-or-range>]. Entries with no version part keep today's semantics exactly, so this is backwards compatible. Renovate, etc. can then write the exact exclusion along with the security update, and/or specific versions can be excluded in a self-documenting way.Smaller alternative
If version-scoped matching isn't wanted, erroring or warning on an entry that parses as
name@versionwould at least make it fail loudly instead of silently exempting nothing while a security fix is reverted.All reactions