Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .yarn/versions/dab519eb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
releases:
"@yarnpkg/cli": minor
"@yarnpkg/core": minor
"@yarnpkg/plugin-essentials": minor
"@yarnpkg/plugin-npm": minor

declined:
- "@yarnpkg/builder"
- "@yarnpkg/doctor"
- "@yarnpkg/extensions"
- "@yarnpkg/nm"
- "@yarnpkg/pnpify"
- "@yarnpkg/sdks"
- "@yarnpkg/plugin-catalog"
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-exec"
- "@yarnpkg/plugin-file"
- "@yarnpkg/plugin-git"
- "@yarnpkg/plugin-github"
- "@yarnpkg/plugin-http"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-jsr"
- "@yarnpkg/plugin-link"
- "@yarnpkg/plugin-nm"
- "@yarnpkg/plugin-npm-cli"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-pnpm"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
25 changes: 13 additions & 12 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
catalog:
typescript: ^5.9.2

changesetIgnorePatterns:
- .github/**
- .yarn/cache/**
Expand All @@ -15,34 +18,32 @@ immutablePatterns:

initScope: yarnpkg

pnpZipBackend: js
npmMinimalAgeGate: 0

npmPublishAccess: public

npmPublishProvenance: true

catalog:
typescript: "^5.9.2"

packageExtensions:
markdown-it@*:
dependencies:
punycode: "*"

"@docusaurus/preset-classic@3.7.0":
peerDependencies:
"@docusaurus/plugin-content-docs": "3.7.0"
"@docusaurus/plugin-content-docs": 3.7.0
docusaurus-plugin-typedoc-api@^4:
dependencies:
"@docusaurus/mdx-loader": "^3"
"@docusaurus/theme-common": "^3"
"@docusaurus/mdx-loader": ^3
"@docusaurus/theme-common": ^3
peerDependencies:
"@docusaurus/plugin-content-docs": "*"
react-dom: "*"
typedoc: "*"
"@docusaurus/plugin-content-docs": "*"
markdown-it@*:
dependencies:
punycode: "*"

pnpEnableEsmLoader: true

pnpZipBackend: js

preferInteractive: true

supportedArchitectures:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ export const ADVISORIES = new Map<string, Array<npmAuditTypes.AuditMetadata>>([
}]],
]);

// Packages without an explicit publish date pretend to have been released long
// ago, so that the `npmMinimalAgeGate` setting (defaulting to `1d`) doesn't
// quarantine them when running tests.
const OLD_RELEASE_DATE = new Date(0).toISOString();

const RELEASE_DATE_PACKAGES: Record<string, Record<string, number | string>> = {
"release-date": {
"1.0.0": new Date(new Date().getTime() - /* 10 days */ 1000 * 60 * 60 * 24 * 10).toISOString(),
Expand Down Expand Up @@ -444,7 +449,9 @@ export const startPackageServer = ({type}: {type: keyof typeof packageServerUrls
}),
)),
),
time: name in RELEASE_DATE_PACKAGES ? RELEASE_DATE_PACKAGES[name] : undefined,
time: name in RELEASE_DATE_PACKAGES
? RELEASE_DATE_PACKAGES[name]
: Object.fromEntries(versions.map(version => [version, OLD_RELEASE_DATE])),
[`dist-tags`]: {
latest: semver.maxSatisfying(versions, `*`),
...distTags,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe(`Commands`, () => {

expect(match).not.toBeNull();
const currentVersion = Number(match![1]);
const previousVersion = Math.max(0, currentVersion - 1);
const previousVersion = Math.max(0, currentVersion - 2);

const downgraded = lockfile.replace(
/^(__metadata:\r?\n {2}version: )\d+$/m,
Expand All @@ -96,6 +96,41 @@ describe(`Commands`, () => {
}),
);

test(
`it should migrate old lockfiles by disabling npmMinimalAgeGate when unset`,
makeTemporaryEnv({
dependencies: {
[`no-deps`]: `1.0.0`,
},
}, async ({path, run}) => {
const lockfilePath = ppath.join(path, Filename.lockfile);
const rcPath = ppath.join(path, Filename.rc);

await run(`install`);

const lockfile = await xfs.readFilePromise(lockfilePath, `utf8`);
const match = lockfile.match(/^__metadata:\r?\n {2}version: (\d+)$/m);

expect(match).not.toBeNull();
const currentVersion = Number(match![1]);
const previousVersion = Math.max(0, currentVersion - 1);

const downgraded = lockfile.replace(
/^(__metadata:\r?\n {2}version: )\d+$/m,
`$1${previousVersion}`,
);

expect(downgraded).not.toEqual(lockfile);
await xfs.writeFilePromise(lockfilePath, downgraded);

await expect(xfs.existsPromise(rcPath)).resolves.toBeFalsy();

await run(`install`);

await expect(xfs.readFilePromise(rcPath, `utf8`)).resolves.toMatch(/npmMinimalAgeGate:\s+['"]?0['"]?/);
}),
);

test(
`it should print the logs to the standard output when using --inline-builds`,
makeTemporaryEnv({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,5 +369,83 @@ describe(`Features`, () => {
}),
);
});
describe(`--no-time-gate`, () => {
test(
`yarn add should ignore the minimum release age when --no-time-gate is set`,
makeTemporaryEnv({}, {
npmMinimalAgeGate: `1d`,
}, async ({run, source}) => {
await run(`add`, `--no-time-gate`, `release-date@^1.0.0`);

await expect(source(`require('release-date/package.json')`)).resolves.toMatchObject({
name: `release-date`,
version: `1.1.1`,
});
}),
);

test(
`yarn add should ignore the minimum release age for exact versions when --no-time-gate is set`,
makeTemporaryEnv({}, {
npmMinimalAgeGate: `1d`,
}, async ({run, source}) => {
await run(`add`, `--no-time-gate`, `release-date@1.1.1`);

await expect(source(`require('release-date/package.json')`)).resolves.toMatchObject({
name: `release-date`,
version: `1.1.1`,
});
}),
);

test(
`yarn up should ignore the minimum release age when --no-time-gate is set`,
makeTemporaryEnv({
dependencies: {[`release-date`]: `^1.0.0`},
}, {
npmMinimalAgeGate: `1d`,
}, async ({run, source}) => {
await run(`install`);
await run(`set`, `resolution`, `release-date@npm:^1.0.0`, `npm:1.0.0`);

const preUpVersion = (await source(`require('release-date/package.json')`)).version;
if (preUpVersion !== `1.0.0`)
throw new Error(`Pre-up version is not 1.0.0`);

await run(`up`, `--no-time-gate`, `release-date`);

await expect(source(`require('release-date/package.json')`)).resolves.toMatchObject({
name: `release-date`,
version: `1.1.1`,
});
}),
);

test(
`yarn up -R should ignore the minimum release age when --no-time-gate is set`,
makeTemporaryEnv({
dependencies: {[`release-date`]: `^1.0.0`},
}, {
npmMinimalAgeGate: `1d`,
pnpFallbackMode: `all`,
pnpMode: `loose`,
}, async ({run, source}) => {
await run(`install`);
await run(`set`, `resolution`, `release-date@npm:^1.0.0`, `npm:1.0.0`);
await run(`set`, `resolution`, `release-date-transitive@npm:^1.0.0`, `npm:1.0.0`);

await run(`up`, `--no-time-gate`, `-R`, `*`);

await expect(source(`require('release-date/package.json')`)).resolves.toMatchObject({
name: `release-date`,
version: `1.1.1`,
});
await expect(source(`require('release-date-transitive/package.json')`)).resolves.toMatchObject({
name: `release-date-transitive`,
version: `1.1.1`,
});
}),
);
});
});
});
2 changes: 1 addition & 1 deletion packages/docusaurus/docs/features/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Yarn doesn't run postinstalls by default ever since 4.14. You must either enable

## Age gate

Yarn 4.12 introduced `npmMinimalAgeGate` to restrict packages installed on your machine to only packages that got published at least N days prior. The `npmPreapprovedPackages` setting also lets you bypass this check for specific packages.
Yarn 4.12 introduced `npmMinimalAgeGate` to restrict packages installed on your machine to only packages that got published at least N days prior. The setting defaults to `1d`, so a brand new release won't be installed until it has had a chance to be reviewed by the community. The `npmPreapprovedPackages` setting also lets you bypass this check for specific packages, and the `--no-time-gate` flag on `yarn add` and `yarn up` lets you bypass it for a single command.

## Hardened mode

Expand Down
2 changes: 1 addition & 1 deletion packages/docusaurus/static/configuration/yarnrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@
{ "type": "number" },
{ "type": "string", "pattern": "^(\\d*\\.?\\d+)(ms|s|m|h|d|w)?$" }
],
"default": "3d"
"default": "1d"
},
"npmPreapprovedPackages": {
"_package": "@yarnpkg/core",
Expand Down
8 changes: 8 additions & 0 deletions packages/plugin-essentials/sources/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ export default class AddCommand extends BaseCommand {
description: `Reuse the highest version already used somewhere within the project`,
});

noTimeGate = Option.Boolean(`--no-time-gate`, false, {
description: `Disable the minimum release age check for this command`,
});

mode = Option.String(`--mode`, {
description: `Change what artifacts installs generate`,
validator: t.isEnum(InstallMode),
Expand All @@ -124,6 +128,10 @@ export default class AddCommand extends BaseCommand {

async execute() {
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);

if (this.noTimeGate)
configuration.useWithSource(`<cli>`, {npmMinimalAgeGate: `0`}, configuration.startingCwd, {overwrite: true});

const {project, workspace} = await Project.find(configuration, this.context.cwd);
const cache = await Cache.find(configuration);

Expand Down
4 changes: 4 additions & 0 deletions packages/plugin-essentials/sources/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ const LOCKFILE_MIGRATION_RULES: Array<{
selector: v => v < 9,
name: `enableScripts`,
value: true,
}, {
selector: v => v < 10,
name: `npmMinimalAgeGate` as keyof ConfigurationValueMap,
value: `0`,
}];

// eslint-disable-next-line arca/no-default-export
Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-essentials/sources/commands/up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export default class UpCommand extends BaseCommand {
description: `Resolve again ALL resolutions for those packages`,
});

noTimeGate = Option.Boolean(`--no-time-gate`, false, {
description: `Disable the minimum release age check for this command`,
});

mode = Option.String(`--mode`, {
description: `Change what artifacts installs generate`,
validator: t.isEnum(InstallMode),
Expand All @@ -105,6 +109,10 @@ export default class UpCommand extends BaseCommand {

async executeUpRecursive() {
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);

if (this.noTimeGate)
configuration.useWithSource(`<cli>`, {npmMinimalAgeGate: `0`}, configuration.startingCwd, {overwrite: true});

const {project, workspace} = await Project.find(configuration, this.context.cwd);
const cache = await Cache.find(configuration);

Expand Down Expand Up @@ -151,6 +159,10 @@ export default class UpCommand extends BaseCommand {

async executeUpClassic() {
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);

if (this.noTimeGate)
configuration.useWithSource(`<cli>`, {npmMinimalAgeGate: `0`}, configuration.startingCwd, {overwrite: true});

const {project, workspace} = await Project.find(configuration, this.context.cwd);
const cache = await Cache.find(configuration);

Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-npm/sources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const packageGateSettings = {
description: `Minimum age of a package version according to the publish date on the npm registry to be considered for installation`,
type: SettingsType.DURATION,
unit: DurationUnit.MINUTES,
default: `0m`,
default: `1d`,
},
npmPreapprovedPackages: {
description: `Array of package descriptors or package name glob patterns to exclude from the minimum release age check`,
Expand Down
2 changes: 1 addition & 1 deletion packages/yarnpkg-core/sources/Project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {IdentHash, DescriptorHash, LocatorHash, PackageExtensionStatus} from './
// the Package type; no more no less.
export const LOCKFILE_VERSION = miscUtils.parseInt(
process.env.YARN_LOCKFILE_VERSION_OVERRIDE ??
9,
10,
);

// Same thing but must be bumped when the members of the Project class changes (we
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Manual changes might be lost - proceed with caution!

__metadata:
version: 9
version: 10
cacheKey: 10

"@aashutoshrathi/word-wrap@npm:^1.2.3":
Expand Down
Loading