-
Notifications
You must be signed in to change notification settings - Fork 255
Description
Motivation ("The Why")
I want to use the --min-release-age or --before option and I want to do so consistently so I set it in my .npmrc (former) or alias the npm command (latter). I also sometimes want a more recently published package - e.g., because of a vulnerability or because I request a new feature that was finally released. These two things are at odds with each other, and unfortunately --min-release-age and --before are all-or-nothing. Therefore, I would like to propose two "exceptions" for these options1:
- If a package version is explicitly recorded in the lockfile it will be installed regardless of the minimum age requested.
- If a package version is explicitly requested, e.g.
npm install package@1.2.3where v1.2.3 was released today, it will be installed regardless of the minimum age requested.
Prior Art
pnpm and yarn
Both of these have the ability to explicitly list exceptions (through minimumReleaseAgeExclude and npmPreapprovedPackages resp.) which bypass the minimum release age check. This is an alternative strategy to the one described here. The disadvantage is that it's a separate list that needs to be maintained, most notably the exceptions should (in most cases) be removed after they're no longer necessary, especially in the described scenario2.
Other Ecosystems
The Rust/Cargo proposal for its --min-release-age option (linked below) includes a similar concept:
- Unless
--preciseis used to specify a specific version, any crates updated from the registry will only consider versions published
before the time specified by the appropriatemin-publish-ageoption. If--preciseis used, that version will be used, even if it
newer than the policy would otherwise allow (although in the future, there may be an option to deny that).- If the version of a crate in the lockfile is already newer than
min-publish-age, thencargo updatewill not update that crate, nor will
it downgrade to an older version. It will leave the version as it is.
Limitations
One drawback of this approach is that using an untrusted lockfile - e.g. from an untrusted repository or Pull Request - may unexpectedly override your expected security preferences. An attacker could leverage the suggested behavior to inject a malicious dependency into the lockfile and make you download it.
I believe that
- This attack is already possible by configuring/overriding the
--min-release-agethrough a project level.npmrc3. - This is a trade-off that is worth considering as making the security feature more approachable in this way can help adoption, which might offset the risk of this thread.
Example
- There is a vulnerability in a package and the fix was published today and I want to start using it now, so I run
npm install vulnerable-but-now-fixed@4.2.0. - I contributed a bug fix or feature upstream and now want to use it myself as soon as possible, so I run
npm install excited-to-use@3.1.4. - I, or someone on my team, has done one of the above and now I try to (re)install dependencies with
npm clean-installwhere I don't want to get an error because of these newer dependencies.
How
Current Behaviour
If you want to use any new package you need to disable --min-release-age/--before entirely, affecting all packages.
Desired Behaviour
Using --min-release-age/--before is the default with explicitly recorded exceptions (through CLI arguments or the lockfile) to the rule.
References
- Relates to [RRFC] Support relative dates in
--before#844 - Relates to feat: add min-release-age cli#8965
- Similar to Cargo RFC for min publish age rust-lang/rfcs#3923
- See also Package Managers Need to Cool Down
Footnotes
-
or possibly only one of them, as I feel this idea might make less sense for the intended use case of the
--beforeoption. ↩ -
exceptions make more sense for especially trusted packages such as internal/company packages or highly trusted packages such as, idk,
express(?) ↩ -
further motivating the consideration for limiting this behavior to
--min-release-ageand not using it for--before. ↩