-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: set minimumReleaseAge to delay new versions of dependencies from being installed #9957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new minimumReleaseAge feature that delays the installation of newly released dependencies to reduce security risks from compromised packages. The feature ensures only packages published before a specified time cutoff are installed, with an optional exclude list for trusted dependencies.
- Adds
minimumReleaseAgeconfiguration option that specifies delay in minutes before new versions can be installed - Implements
minimumReleaseAgeExcludeto exempt specific packages from the release age restriction - Integrates time-based filtering throughout the dependency resolution pipeline with strict enforcement option
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| store/store-connection-manager/src/createNewStoreController.ts | Adds minimumReleaseAge to controller options and enables strict published-by checking |
| resolving/npm-resolver/test/distTagsByDate.test.ts | New test file for dist-tag filtering based on publish date cutoffs |
| resolving/npm-resolver/src/pickPackageFromMeta.ts | Major refactoring to move date filtering logic and add dist-tag repopulation |
| resolving/npm-resolver/src/pickPackage.ts | Adds strict mode for published-by checks with error handling |
| resolving/npm-resolver/src/index.ts | Adds strictPublishedByCheck option to resolver factory |
| pkg-manager/resolve-dependencies/src/resolveDependencyTree.ts | Calculates maximum publish date from minimumReleaseAge configuration |
| pkg-manager/resolve-dependencies/src/resolveDependencies.ts | Applies release age filtering during dependency resolution |
| pkg-manager/plugin-commands-installation/test/add.ts | Test for installation failure when no versions meet release age requirement |
| pkg-manager/core/test/install/minimumReleaseAge.ts | Core functionality tests for minimumReleaseAge feature |
| pkg-manager/core/src/install/index.ts | Passes minimumReleaseAge options to dependency resolution |
| pkg-manager/core/src/install/extendInstallOptions.ts | Type definitions for new minimumReleaseAge options |
| config/config/src/types.ts | Configuration type definitions for release age settings |
| config/config/src/Config.ts | Interface definitions for minimumReleaseAge configuration |
| .changeset/full-dolls-invite.md | Documentation of the new feature and usage examples |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <[email protected]>
|
How exactly does this parameter work? Let's say I have Then I run:
and
What version would be installed? |
…ig options (#6901) ## What's the problem this PR addresses? closes #6899. See rationale in pnpm/pnpm#9921 and pnpm/pnpm#9957, but the tl;dr is that with the recent uptick in compromised npm packages, this can offer some level of protection to prevent end-users from installing malware prior to detection and removal from registries. There are a few differences from the pnpm implementation. I felt these differences made sense with some of the other features `yarn` supports, but I also understand the desire for parity between package managers, so open to thoughts there. 1. `npm` added in the option names (`npmMinimumReleaseAge` versus `minimumReleaseAge`). Since yarn implements many resolvers and this is only implemented in the case of the npm resolver, I felt that this made the behavior of the options more clear. 2. `npmMinimumReleaseAgeExclude` supports not only package names like pnpm's implementation, but it also supports: - exact match on package locators (i.e. exact package resolutions -- like `@aws-sdk/[email protected]` or `@aws-sdk/types@npm:3.877.0`) - micromatch glob patterns on package descriptors (i.e. semver descriptors -- like `@aws-sdk/types@^3.0.0`, `@aws-sdk/types@npm:^3.0.0`, `@aws-sdk/types@*` or `@aws-sdk/*`) The rationale here is mostly in the case that you know certain package versions that are affected (e.g. `[email protected]`) or if you need to upgrade to an excluded version, but its part of a monorepo -- that's where the micromatch glob comes in handy. ## How did you fix it? I added the options and checked for them within the NPM semver resolver when evaluating candidates. I'm new to this codebase -- I think I've made all the updates needed and was able to test some scenarios successfully (see below). ### Testing manually <spoiler> <details> I used `@aws-sdk/[email protected]` to test. At the time of writing, this package was published 7742 minutes ago, which is less than 10000 minutes (used in configurations below). #### `yarn add @aws-sdk/[email protected]` fails ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 ``` install command ```bash ❯ yarn add @aws-sdk/[email protected] ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0082: │ @aws-sdk/types@npm:3.887.0: No candidates found ➤ YN0000: └ Completed ➤ YN0000: · Failed with errors in 0s 11ms ``` #### `yarn add @aws-sdk/types@^3.0.0` resolves prior version ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 ``` install command ```bash ❯ yarn add @aws-sdk/types@^3.0.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.862.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 237ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 271ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.862.0 (via npm:^3.0.0) ``` #### `yarn add @aws-sdk/types@^3.0.0` resolves most recent version with package exclude = `@aws-sdk/types` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/types" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.0.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.887.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 237ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 265ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.887.0 (via npm:^3.0.0) ``` #### `yarn add @aws-sdk/types@^3.0.0` resolves most recent version with package exclude = `@aws-sdk/*` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/*" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.0.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.887.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 205ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 232ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.887.0 (via npm:^3.0.0) ``` #### `yarn add @aws-sdk/types@^3.0.0` resolves most recent version with package exclude = `@aws-sdk/[email protected]` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/[email protected]" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.0.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.887.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 292ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 324ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.887.0 (via npm:^3.0.0) ``` #### `yarn add @aws-sdk/types@^3.0.0` resolves most recent version with package exclude = `@aws-sdk/types@^3.0.0` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/types@^3.0.0" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.0.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.887.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 248ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 278ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.887.0 (via npm:^3.0.0) ``` #### `yarn add @aws-sdk/types@^3.5.0` resolves prior version with package exclude = `@aws-sdk/types@^3.0.0` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/types@^3.0.0" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.5.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.862.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 219ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 256ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.862.0 (via npm:^3.5.0) ``` #### `yarn add @aws-sdk/types@^3.5.0` resolves prior version with package exclude = `@aws-sdk/types@npm:^3.0.0` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/types@npm:^3.0.0" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.5.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.862.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 223ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.862.0 (via npm:^3.5.0) ``` #### `yarn add @aws-sdk/types@^3.0.0` resolves most recent version with package exclude = `@aws-sdk/types@npm:^3.0.0` ✅ `.yarnrc.yml` ```yaml npmMinimumReleaseAge: 10000 npmMinimumReleaseAgeExclude: - "@aws-sdk/types@npm:^3.0.0" ``` install command - installs `@aws-sdk/[email protected]` ✅ ```bash ❯ yarn add @aws-sdk/types@^3.0.0 ➤ YN0000: · Yarn 4.9.4-git.20250917.hash-a05df867e ➤ YN0000: ┌ Resolution step ➤ YN0085: │ + @aws-sdk/types@npm:3.887.0, @smithy/types@npm:4.5.0, tslib@npm:2.8.1 ➤ YN0000: └ Completed in 0s 239ms ➤ YN0000: ┌ Fetch step ➤ YN0000: └ Completed ➤ YN0000: ┌ Link step ➤ YN0000: └ Completed ➤ YN0000: · Done in 0s 269ms ❯ yarn why @aws-sdk/types └─ test-yarn-project@workspace:. └─ @aws-sdk/types@npm:3.887.0 (via npm:^3.0.0) ``` </details> </spoiler> ## Checklist <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [x] I will check that all automated PR checks pass before the PR gets reviewed. --------- Co-authored-by: Maël Nison <[email protected]>
@limonte I believe the answer is However, if the user notices the vulnerability via |
close #9921