diff --git a/README.md b/README.md index a9508e70a..1f1a662f4 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,10 @@ same major line. Should you need to upgrade to a new major, use an explicit not to lookup on the remote registry for the latest version of the selected package manager. +- `COREPACK_ENABLE_URL_VERSION_FOR_KNOWN_PM` can be set to `1` to allow use of + custom URLs to load a package manager known by Corepack (`yarn`, `npm`, and + `pnpm`). + - `COREPACK_ENABLE_NETWORK` can be set to `0` to prevent Corepack from accessing the network (in which case you'll be responsible for hydrating the package manager versions that will be required for the projects you'll run, using diff --git a/sources/main.ts b/sources/main.ts index 9b880ee05..a15316e20 100644 --- a/sources/main.ts +++ b/sources/main.ts @@ -35,9 +35,9 @@ function getPackageManagerRequestFromCli(parameter: string | undefined, context: return null; const [, binaryName, binaryVersion] = match; - const packageManager = context.engine.getPackageManagerFor(binaryName); - if (!packageManager) - return null; + const packageManager = context.engine.getPackageManagerFor(binaryName)!; + + if (packageManager == null && binaryVersion == null) return null; return { packageManager, @@ -47,28 +47,34 @@ function getPackageManagerRequestFromCli(parameter: string | undefined, context: } async function executePackageManagerRequest({packageManager, binaryName, binaryVersion}: PackageManagerRequest, args: Array, context: Context) { - const defaultVersion = await context.engine.getDefaultVersion(packageManager); - const definition = context.engine.config.definitions[packageManager]!; - - // If all leading segments match one of the patterns defined in the `transparent` - // key, we tolerate calling this binary even if the local project isn't explicitly - // configured for it, and we use the special default version if requested. + let fallbackLocator: Locator = { + name: binaryName, + reference: undefined as any, + }; let isTransparentCommand = false; - for (const transparentPath of definition.transparent.commands) { - if (transparentPath[0] === binaryName && transparentPath.slice(1).every((segment, index) => segment === args[index])) { - isTransparentCommand = true; - break; + if (packageManager != null) { + const defaultVersion = await context.engine.getDefaultVersion(packageManager); + const definition = context.engine.config.definitions[packageManager]!; + + // If all leading segments match one of the patterns defined in the `transparent` + // key, we tolerate calling this binary even if the local project isn't explicitly + // configured for it, and we use the special default version if requested. + for (const transparentPath of definition.transparent.commands) { + if (transparentPath[0] === binaryName && transparentPath.slice(1).every((segment, index) => segment === args[index])) { + isTransparentCommand = true; + break; + } } - } - const fallbackReference = isTransparentCommand - ? definition.transparent.default ?? defaultVersion - : defaultVersion; + const fallbackReference = isTransparentCommand + ? definition.transparent.default ?? defaultVersion + : defaultVersion; - const fallbackLocator: Locator = { - name: packageManager, - reference: fallbackReference, - }; + fallbackLocator = { + name: packageManager, + reference: fallbackReference, + }; + } let descriptor: Descriptor; try { diff --git a/sources/specUtils.ts b/sources/specUtils.ts index fcafdf0c2..a1ee17756 100644 --- a/sources/specUtils.ts +++ b/sources/specUtils.ts @@ -38,6 +38,8 @@ export function parseSpec(raw: unknown, source: string, {enforceExactVersion = t if (!isSupportedPackageManager(name)) { throw new UsageError(`Unsupported package manager specification (${raw})`); } + } else if (isSupportedPackageManager(name) && process.env.COREPACK_ENABLE_URL_VERSION_FOR_KNOWN_PM !== `1`) { + throw new UsageError(`Illegal use of URL for known package manager. Instead, select a specific version, or set COREPACK_ENABLE_URL_VERSION_FOR_KNOWN_PM=1 in your environment (${raw})`); } diff --git a/tests/_runCli.ts b/tests/_runCli.ts index e028af751..f863c10b0 100644 --- a/tests/_runCli.ts +++ b/tests/_runCli.ts @@ -1,7 +1,7 @@ import {PortablePath, npath} from '@yarnpkg/fslib'; import {spawn} from 'child_process'; -export async function runCli(cwd: PortablePath, argv: Array): Promise<{exitCode: number | null, stdout: string, stderr: string}> { +export async function runCli(cwd: PortablePath, argv: Array, options?: Parameters[2]): Promise<{exitCode: number | null, stdout: string, stderr: string}> { const out: Array = []; const err: Array = []; @@ -11,6 +11,7 @@ export async function runCli(cwd: PortablePath, argv: Array): Promise<{e const child = spawn(process.execPath, [`--no-warnings`, `-r`, require.resolve(`./recordRequests.js`), require.resolve(`../dist/corepack.js`), ...argv], { cwd: npath.fromPortablePath(cwd), env: process.env, + ...options, stdio: `pipe`, }); diff --git a/tests/main.test.ts b/tests/main.test.ts index 3e4f8de07..e0f03b09c 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -29,6 +29,50 @@ it(`should refuse to download a package manager if the hash doesn't match`, asyn }); }); +it.failing(`should refuse to download a known package manager from a URL`, async () => { + await xfs.mktempPromise(async cwd => { + // Package managers known by Corepack cannot be loaded from a URL. + await expect(runCli(cwd, [`yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /Illegal use of URL for known package manager/, + }); + + // Unknown package managers can be loaded from a URL. + await expect(runCli(cwd, [`corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `0.24.1\n`, + }); + }); +}); + +it.failing(`should refuse to download a known package manager from a URL in package.json`, async () => { + await xfs.mktempPromise(async cwd => { + // Package managers known by Corepack cannot be loaded from a URL. + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /Illegal use of URL for known package manager/, + }); + + // Unknown package managers can be loaded from a URL. + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, + }); + + await expect(runCli(cwd, [`corepack`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `0.24.1\n`, + }); + }); +}); + it(`should require a version to be specified`, async () => { await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { @@ -89,7 +133,8 @@ const testedPackageManagers: Array<[string, string] | [string, string, string]> for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of testedPackageManagers) { it(`should use the right package manager version for a given project (${name}@${version})`, async () => { await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`${name}@${version}`, `--version`])).resolves.toMatchObject({ + const env = {...process.env, COREPACK_ENABLE_URL_VERSION_FOR_KNOWN_PM: `1`}; + await expect(runCli(cwd, [`${name}@${version}`, `--version`], {env})).resolves.toMatchObject({ exitCode: 0, stderr: ``, stdout: `${expectedVersion}\n`, @@ -99,7 +144,7 @@ for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of tested packageManager: `${name}@${version}`, }); - await expect(runCli(cwd, [name, `--version`])).resolves.toMatchObject({ + await expect(runCli(cwd, [name, `--version`], {env})).resolves.toMatchObject({ exitCode: 0, stderr: ``, stdout: `${expectedVersion}\n`, diff --git a/tests/nock/0mijz-lZ_5pF8f6tlAdbKg-2.dat b/tests/nock/0mijz-lZ_5pF8f6tlAdbKg-0.dat similarity index 100% rename from tests/nock/0mijz-lZ_5pF8f6tlAdbKg-2.dat rename to tests/nock/0mijz-lZ_5pF8f6tlAdbKg-0.dat diff --git a/tests/nock/0mijz-lZ_5pF8f6tlAdbKg-1.dat b/tests/nock/0mijz-lZ_5pF8f6tlAdbKg-1.dat deleted file mode 100644 index 3728f6a82..000000000 Binary files a/tests/nock/0mijz-lZ_5pF8f6tlAdbKg-1.dat and /dev/null differ diff --git a/tests/nock/2Vuch5EnmzPEVel1DWYfPQ-2.dat b/tests/nock/2Vuch5EnmzPEVel1DWYfPQ-0.dat similarity index 100% rename from tests/nock/2Vuch5EnmzPEVel1DWYfPQ-2.dat rename to tests/nock/2Vuch5EnmzPEVel1DWYfPQ-0.dat diff --git a/tests/nock/2Vuch5EnmzPEVel1DWYfPQ-1.dat b/tests/nock/2Vuch5EnmzPEVel1DWYfPQ-1.dat deleted file mode 100644 index 7a9750708..000000000 Binary files a/tests/nock/2Vuch5EnmzPEVel1DWYfPQ-1.dat and /dev/null differ diff --git a/tests/nock/2bh2z3MgoMIcnxHAMev5uQ-2.dat b/tests/nock/2bh2z3MgoMIcnxHAMev5uQ-0.dat similarity index 100% rename from tests/nock/2bh2z3MgoMIcnxHAMev5uQ-2.dat rename to tests/nock/2bh2z3MgoMIcnxHAMev5uQ-0.dat diff --git a/tests/nock/2bh2z3MgoMIcnxHAMev5uQ-1.dat b/tests/nock/2bh2z3MgoMIcnxHAMev5uQ-1.dat deleted file mode 100644 index e090a6232..000000000 Binary files a/tests/nock/2bh2z3MgoMIcnxHAMev5uQ-1.dat and /dev/null differ diff --git a/tests/nock/2ituqIIXsQUU5l2SZSMRDQ-2.dat b/tests/nock/2ituqIIXsQUU5l2SZSMRDQ-0.dat similarity index 100% rename from tests/nock/2ituqIIXsQUU5l2SZSMRDQ-2.dat rename to tests/nock/2ituqIIXsQUU5l2SZSMRDQ-0.dat diff --git a/tests/nock/2ituqIIXsQUU5l2SZSMRDQ-1.dat b/tests/nock/2ituqIIXsQUU5l2SZSMRDQ-1.dat deleted file mode 100644 index e090a6232..000000000 Binary files a/tests/nock/2ituqIIXsQUU5l2SZSMRDQ-1.dat and /dev/null differ diff --git a/tests/nock/6BSdMkNfyZxTnw4r9rK5ig-2.dat b/tests/nock/6BSdMkNfyZxTnw4r9rK5ig-0.dat similarity index 100% rename from tests/nock/6BSdMkNfyZxTnw4r9rK5ig-2.dat rename to tests/nock/6BSdMkNfyZxTnw4r9rK5ig-0.dat diff --git a/tests/nock/6BSdMkNfyZxTnw4r9rK5ig-1.dat b/tests/nock/6BSdMkNfyZxTnw4r9rK5ig-1.dat deleted file mode 100644 index 7a9750708..000000000 Binary files a/tests/nock/6BSdMkNfyZxTnw4r9rK5ig-1.dat and /dev/null differ diff --git a/tests/nock/6wKqy4gh7jHaGEejJ6MskQ-1.dat b/tests/nock/6wKqy4gh7jHaGEejJ6MskQ-0.dat similarity index 100% rename from tests/nock/6wKqy4gh7jHaGEejJ6MskQ-1.dat rename to tests/nock/6wKqy4gh7jHaGEejJ6MskQ-0.dat diff --git a/tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-2.dat b/tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-0.dat similarity index 100% rename from tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-2.dat rename to tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-0.dat diff --git a/tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-1.dat b/tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-1.dat deleted file mode 100644 index 27c1259c6..000000000 Binary files a/tests/nock/6zkNeK1b_EJchZZ1iQz7GQ-1.dat and /dev/null differ diff --git a/tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-2.dat b/tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-0.dat similarity index 100% rename from tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-2.dat rename to tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-0.dat diff --git a/tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-1.dat b/tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-1.dat deleted file mode 100644 index ff2377b03..000000000 Binary files a/tests/nock/7_ZKSRHG7OfkRvPJHYpxbQ-1.dat and /dev/null differ diff --git a/tests/nock/8LXMft4IyEWeaqoiynS5FA-1.dat b/tests/nock/8LXMft4IyEWeaqoiynS5FA-1.dat index 242f7f5fb..b8c86777f 100644 Binary files a/tests/nock/8LXMft4IyEWeaqoiynS5FA-1.dat and b/tests/nock/8LXMft4IyEWeaqoiynS5FA-1.dat differ diff --git a/tests/nock/6wKqy4gh7jHaGEejJ6MskQ-2.dat b/tests/nock/Bk2ABpjab9iEEgLyTDm7Nw-1.dat similarity index 100% rename from tests/nock/6wKqy4gh7jHaGEejJ6MskQ-2.dat rename to tests/nock/Bk2ABpjab9iEEgLyTDm7Nw-1.dat diff --git a/tests/nock/D4fdrCUUCl7i1D6eeg49zQ-2.dat b/tests/nock/D4fdrCUUCl7i1D6eeg49zQ-0.dat similarity index 100% rename from tests/nock/D4fdrCUUCl7i1D6eeg49zQ-2.dat rename to tests/nock/D4fdrCUUCl7i1D6eeg49zQ-0.dat diff --git a/tests/nock/D4fdrCUUCl7i1D6eeg49zQ-1.dat b/tests/nock/D4fdrCUUCl7i1D6eeg49zQ-1.dat deleted file mode 100644 index 9b690dabb..000000000 Binary files a/tests/nock/D4fdrCUUCl7i1D6eeg49zQ-1.dat and /dev/null differ diff --git a/tests/nock/GSh7RCQN4e8flEL6h2lnwQ-2.dat b/tests/nock/GSh7RCQN4e8flEL6h2lnwQ-0.dat similarity index 100% rename from tests/nock/GSh7RCQN4e8flEL6h2lnwQ-2.dat rename to tests/nock/GSh7RCQN4e8flEL6h2lnwQ-0.dat diff --git a/tests/nock/GSh7RCQN4e8flEL6h2lnwQ-1.dat b/tests/nock/GSh7RCQN4e8flEL6h2lnwQ-1.dat deleted file mode 100644 index ff2377b03..000000000 Binary files a/tests/nock/GSh7RCQN4e8flEL6h2lnwQ-1.dat and /dev/null differ diff --git a/tests/nock/K26guRbYG9vZYQwgFU5lHg-2.dat b/tests/nock/K26guRbYG9vZYQwgFU5lHg-0.dat similarity index 100% rename from tests/nock/K26guRbYG9vZYQwgFU5lHg-2.dat rename to tests/nock/K26guRbYG9vZYQwgFU5lHg-0.dat diff --git a/tests/nock/K26guRbYG9vZYQwgFU5lHg-1.dat b/tests/nock/K26guRbYG9vZYQwgFU5lHg-1.dat deleted file mode 100644 index 9b690dabb..000000000 Binary files a/tests/nock/K26guRbYG9vZYQwgFU5lHg-1.dat and /dev/null differ diff --git a/tests/nock/LU_vfrNkPzIhLrr405IpzQ-2.dat b/tests/nock/LU_vfrNkPzIhLrr405IpzQ-0.dat similarity index 100% rename from tests/nock/LU_vfrNkPzIhLrr405IpzQ-2.dat rename to tests/nock/LU_vfrNkPzIhLrr405IpzQ-0.dat diff --git a/tests/nock/LU_vfrNkPzIhLrr405IpzQ-1.dat b/tests/nock/LU_vfrNkPzIhLrr405IpzQ-1.dat deleted file mode 100644 index 9b690dabb..000000000 Binary files a/tests/nock/LU_vfrNkPzIhLrr405IpzQ-1.dat and /dev/null differ diff --git a/tests/nock/MVR-DPxEL7jQE9aetA791Q-2.dat b/tests/nock/MVR-DPxEL7jQE9aetA791Q-0.dat similarity index 100% rename from tests/nock/MVR-DPxEL7jQE9aetA791Q-2.dat rename to tests/nock/MVR-DPxEL7jQE9aetA791Q-0.dat diff --git a/tests/nock/MVR-DPxEL7jQE9aetA791Q-1.dat b/tests/nock/MVR-DPxEL7jQE9aetA791Q-1.dat deleted file mode 100644 index 3728f6a82..000000000 Binary files a/tests/nock/MVR-DPxEL7jQE9aetA791Q-1.dat and /dev/null differ diff --git a/tests/nock/TnyRFo6IK894n_HQkACElA-2.dat b/tests/nock/TnyRFo6IK894n_HQkACElA-0.dat similarity index 100% rename from tests/nock/TnyRFo6IK894n_HQkACElA-2.dat rename to tests/nock/TnyRFo6IK894n_HQkACElA-0.dat diff --git a/tests/nock/TnyRFo6IK894n_HQkACElA-1.dat b/tests/nock/TnyRFo6IK894n_HQkACElA-1.dat deleted file mode 100644 index 27c1259c6..000000000 Binary files a/tests/nock/TnyRFo6IK894n_HQkACElA-1.dat and /dev/null differ diff --git a/tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-2.dat b/tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-0.dat similarity index 100% rename from tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-2.dat rename to tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-0.dat diff --git a/tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-1.dat b/tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-1.dat deleted file mode 100644 index e090a6232..000000000 Binary files a/tests/nock/Vp5BnbFIGGY7ZeZMncmwMw-1.dat and /dev/null differ diff --git a/tests/nock/cRq-o3WTbH0_0MVIM498_Q-2.dat b/tests/nock/bDcDanMLxr34TrZvvKkWyw-1.dat similarity index 100% rename from tests/nock/cRq-o3WTbH0_0MVIM498_Q-2.dat rename to tests/nock/bDcDanMLxr34TrZvvKkWyw-1.dat diff --git a/tests/nock/oza0_71_8jb3typs-3gduw-2.dat b/tests/nock/bDcDanMLxr34TrZvvKkWyw-2.dat similarity index 100% rename from tests/nock/oza0_71_8jb3typs-3gduw-2.dat rename to tests/nock/bDcDanMLxr34TrZvvKkWyw-2.dat diff --git a/tests/nock/bNE0FYc3WlnFGzjHaIdf5A-1.dat b/tests/nock/bNE0FYc3WlnFGzjHaIdf5A-1.dat index 63fbcff1d..fde1530ed 100644 Binary files a/tests/nock/bNE0FYc3WlnFGzjHaIdf5A-1.dat and b/tests/nock/bNE0FYc3WlnFGzjHaIdf5A-1.dat differ diff --git a/tests/nock/sogVBiC-f6IO6vTAaPDx5w-2.dat b/tests/nock/cRq-o3WTbH0_0MVIM498_Q-0.dat similarity index 100% rename from tests/nock/sogVBiC-f6IO6vTAaPDx5w-2.dat rename to tests/nock/cRq-o3WTbH0_0MVIM498_Q-0.dat diff --git a/tests/nock/cRq-o3WTbH0_0MVIM498_Q-1.dat b/tests/nock/cRq-o3WTbH0_0MVIM498_Q-1.dat deleted file mode 100644 index 7a9750708..000000000 Binary files a/tests/nock/cRq-o3WTbH0_0MVIM498_Q-1.dat and /dev/null differ diff --git a/tests/nock/zIqNSOkKydlbZyC4vpFlug-2.dat b/tests/nock/oza0_71_8jb3typs-3gduw-0.dat similarity index 100% rename from tests/nock/zIqNSOkKydlbZyC4vpFlug-2.dat rename to tests/nock/oza0_71_8jb3typs-3gduw-0.dat diff --git a/tests/nock/oza0_71_8jb3typs-3gduw-1.dat b/tests/nock/oza0_71_8jb3typs-3gduw-1.dat deleted file mode 100644 index ff2377b03..000000000 Binary files a/tests/nock/oza0_71_8jb3typs-3gduw-1.dat and /dev/null differ diff --git a/tests/nock/sogVBiC-f6IO6vTAaPDx5w-0.dat b/tests/nock/sogVBiC-f6IO6vTAaPDx5w-0.dat new file mode 100644 index 000000000..b03652e61 Binary files /dev/null and b/tests/nock/sogVBiC-f6IO6vTAaPDx5w-0.dat differ diff --git a/tests/nock/sogVBiC-f6IO6vTAaPDx5w-1.dat b/tests/nock/sogVBiC-f6IO6vTAaPDx5w-1.dat deleted file mode 100644 index 3728f6a82..000000000 Binary files a/tests/nock/sogVBiC-f6IO6vTAaPDx5w-1.dat and /dev/null differ diff --git a/tests/nock/tlFGXHHjkkY67GM_Uo2jmA-1.dat b/tests/nock/tlFGXHHjkkY67GM_Uo2jmA-0.dat similarity index 100% rename from tests/nock/tlFGXHHjkkY67GM_Uo2jmA-1.dat rename to tests/nock/tlFGXHHjkkY67GM_Uo2jmA-0.dat diff --git a/tests/nock/tlFGXHHjkkY67GM_Uo2jmA-2.dat b/tests/nock/tlFGXHHjkkY67GM_Uo2jmA-2.dat deleted file mode 100644 index 6e86b5726..000000000 Binary files a/tests/nock/tlFGXHHjkkY67GM_Uo2jmA-2.dat and /dev/null differ diff --git a/tests/nock/zIqNSOkKydlbZyC4vpFlug-0.dat b/tests/nock/zIqNSOkKydlbZyC4vpFlug-0.dat new file mode 100644 index 000000000..b03652e61 Binary files /dev/null and b/tests/nock/zIqNSOkKydlbZyC4vpFlug-0.dat differ diff --git a/tests/nock/zIqNSOkKydlbZyC4vpFlug-1.dat b/tests/nock/zIqNSOkKydlbZyC4vpFlug-1.dat deleted file mode 100644 index 27c1259c6..000000000 Binary files a/tests/nock/zIqNSOkKydlbZyC4vpFlug-1.dat and /dev/null differ