diff --git a/lib/commands/cache.js b/lib/commands/cache.js index 35b87bef16c23..7aaf3564cb9fc 100644 --- a/lib/commands/cache.js +++ b/lib/commands/cache.js @@ -181,11 +181,12 @@ class Cache extends BaseCommand { await pacote.tarball.stream(spec, stream => { stream.resume() return stream.promise() - }, { ...this.npm.flatOptions }) + }, { ...this.npm.flatOptions, _isRoot: true }) await pacote.manifest(spec, { ...this.npm.flatOptions, fullMetadata: true, + _isRoot: true, }) })) } diff --git a/lib/commands/ci.js b/lib/commands/ci.js index c190de7e3ea7f..7480e645a4e0d 100644 --- a/lib/commands/ci.js +++ b/lib/commands/ci.js @@ -21,6 +21,7 @@ class CI extends ArboristWorkspaceCmd { 'strict-peer-deps', 'foreground-scripts', 'ignore-scripts', + 'allow-git', 'audit', 'bin-links', 'fund', diff --git a/lib/commands/dedupe.js b/lib/commands/dedupe.js index e07bcd31e894b..3b7365c2011d3 100644 --- a/lib/commands/dedupe.js +++ b/lib/commands/dedupe.js @@ -14,6 +14,7 @@ class Dedupe extends ArboristWorkspaceCmd { 'omit', 'include', 'ignore-scripts', + 'allow-git', 'audit', 'bin-links', 'fund', diff --git a/lib/commands/diff.js b/lib/commands/diff.js index f2a43c135c0e1..d104218b3d7ef 100644 --- a/lib/commands/diff.js +++ b/lib/commands/diff.js @@ -198,6 +198,7 @@ class Diff extends BaseCommand { const packument = await pacote.packument(spec, { ...this.npm.flatOptions, preferOnline: true, + _isRoot: true, }) bSpec = pickManifest( packument, diff --git a/lib/commands/install.js b/lib/commands/install.js index 7be21582610dc..707848a43d48f 100644 --- a/lib/commands/install.js +++ b/lib/commands/install.js @@ -28,6 +28,7 @@ class Install extends ArboristWorkspaceCmd { 'package-lock-only', 'foreground-scripts', 'ignore-scripts', + 'allow-git', 'audit', 'before', 'bin-links', diff --git a/lib/commands/link.js b/lib/commands/link.js index 4955a5b77d338..e36e5bededcba 100644 --- a/lib/commands/link.js +++ b/lib/commands/link.js @@ -25,6 +25,7 @@ class Link extends ArboristWorkspaceCmd { 'omit', 'include', 'ignore-scripts', + 'allow-git', 'audit', 'bin-links', 'fund', diff --git a/lib/commands/owner.js b/lib/commands/owner.js index 0f12cf9293c30..d53c1c97b77fc 100644 --- a/lib/commands/owner.js +++ b/lib/commands/owner.js @@ -63,6 +63,7 @@ class Owner extends BaseCommand { const data = await pacote.packument(spec, { ...npm.flatOptions, fullMetadata: true, + _isRoot: true, }) if (data && data.maintainers && data.maintainers.length) { return data.maintainers.map(m => m.name) @@ -112,7 +113,13 @@ class Owner extends BaseCommand { const spec = npa(pkg) try { - const packumentOpts = { ...this.npm.flatOptions, fullMetadata: true, preferOnline: true } + const packumentOpts = { + ...this.npm.flatOptions, + fullMetadata: + true, + preferOnline: true, + _isRoot: true, + } const { maintainers } = await pacote.packument(spec, packumentOpts) if (!maintainers || !maintainers.length) { output.standard('no admin found') @@ -166,6 +173,7 @@ class Owner extends BaseCommand { ...this.npm.flatOptions, fullMetadata: true, preferOnline: true, + _isRoot: true, }) const owners = data.maintainers || [] diff --git a/lib/commands/pack.js b/lib/commands/pack.js index bd190d88d82b6..fdde78f6afe23 100644 --- a/lib/commands/pack.js +++ b/lib/commands/pack.js @@ -36,7 +36,11 @@ class Pack extends BaseCommand { const manifests = [] for (const arg of args) { const spec = npa(arg) - const manifest = await pacote.manifest(spec, { ...this.npm.flatOptions, Arborist }) + const manifest = await pacote.manifest(spec, { + ...this.npm.flatOptions, + Arborist, + _isRoot: true, + }) if (!manifest._id) { throw new Error('Invalid package, must have name and version') } diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 162e3d65ba5ce..3c8cbfb825129 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -221,6 +221,7 @@ class Publish extends BaseCommand { ...this.npm.flatOptions, preferOnline: true, registry, + _isRoot: true, }) if (typeof packument?.versions === 'undefined') { return { versions: [], highestVersion: null } diff --git a/lib/commands/unpublish.js b/lib/commands/unpublish.js index e1c06d3184057..73d9d03804558 100644 --- a/lib/commands/unpublish.js +++ b/lib/commands/unpublish.js @@ -26,6 +26,7 @@ class Unpublish extends BaseCommand { ...opts, spec: name, query: { write: true }, + _isRoot: true, }) return Object.keys(packument.versions) } diff --git a/lib/commands/view.js b/lib/commands/view.js index 3d62c2e9083d8..dd563cb2d52b9 100644 --- a/lib/commands/view.js +++ b/lib/commands/view.js @@ -41,6 +41,7 @@ class View extends BaseCommand { ...npm.flatOptions, fullMetadata: true, preferOnline: true, + _isRoot: true, } const spec = npa(opts.conf.argv.remain[2]) const pckmnt = await packument(spec, config) @@ -136,6 +137,7 @@ class View extends BaseCommand { ...this.npm.flatOptions, preferOnline: true, fullMetadata: true, + _isRoot: true, }) // get the data about this package diff --git a/lib/package-url-cmd.js b/lib/package-url-cmd.js index c7ae32174fcb6..26c61b521ae60 100644 --- a/lib/package-url-cmd.js +++ b/lib/package-url-cmd.js @@ -23,12 +23,12 @@ class PackageUrlCommand extends BaseCommand { } for (const arg of args) { - // XXX It is very odd that `where` is how pacote knows to look anywhere - // other than the cwd. + // XXX It is very odd that `where` is how pacote knows to look anywhere other than the cwd. const opts = { ...this.npm.flatOptions, where: this.npm.localPrefix, fullMetadata: true, + _isRoot: true, } const mani = await pacote.manifest(arg, opts) const url = this.getUrl(arg, mani) diff --git a/lib/utils/error-message.js b/lib/utils/error-message.js index 578bcc82287de..50d15d7bc9a37 100644 --- a/lib/utils/error-message.js +++ b/lib/utils/error-message.js @@ -84,6 +84,11 @@ const errorMessage = (er, npm) => { break } + case 'EALLOWGIT': + summary.push(['', er.message]) + detail.push(['', `Refusing to fetch "${er.package}"`]) + break + case 'ENOGIT': summary.push(['', er.message]) detail.push(['', [ diff --git a/node_modules/pacote/lib/fetcher.js b/node_modules/pacote/lib/fetcher.js index f2ac97619d3af..8d52d28eefd4d 100644 --- a/node_modules/pacote/lib/fetcher.js +++ b/node_modules/pacote/lib/fetcher.js @@ -469,11 +469,31 @@ const FileFetcher = require('./file.js') const DirFetcher = require('./dir.js') const RemoteFetcher = require('./remote.js') +// possible values for allow: 'all', 'root', 'none' +const canUseGit = (allow = 'all', isRoot = false) => { + if (allow === 'all') { + return true + } + if (allow !== 'none' && isRoot) { + return true + } + return false +} + // Get an appropriate fetcher object from a spec and options FetcherBase.get = (rawSpec, opts = {}) => { const spec = npa(rawSpec, opts.where) switch (spec.type) { case 'git': + if (!canUseGit(opts.allowGit, opts._isRoot)) { + throw Object.assign( + new Error(`Fetching${opts.allowGit === 'root' ? ' non-root' : ''} packages from git has been disabled`), + { + code: 'EALLOWGIT', + package: spec.toString(), + } + ) + } return new GitFetcher(spec, opts) case 'remote': diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 1837cd09ffc9a..b0cef67100abb 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "21.0.4", + "version": "21.1.0", "description": "JavaScript package downloader", "author": "GitHub Inc.", "bin": { diff --git a/package-lock.json b/package-lock.json index 648d580e44530..52761ed870386 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,7 +135,7 @@ "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", - "pacote": "^21.0.4", + "pacote": "^21.1.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", @@ -9232,9 +9232,9 @@ "license": "BlueOak-1.0.0" }, "node_modules/pacote": { - "version": "21.0.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.4.tgz", - "integrity": "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA==", + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.1.0.tgz", + "integrity": "sha512-WF/PwrImIIVaLmtuCeO5L7n6DA0ZGCqmDPO/XbNjZgNUX+2O5z4f4Wdmu6erBWNICkl3ftKJvit2eIVcpegRRw==", "inBundle": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 7286f9f0a7fdc..424cb2fc81c37 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", - "pacote": "^21.0.4", + "pacote": "^21.1.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", diff --git a/smoke-tests/tap-snapshots/test/index.js.test.cjs b/smoke-tests/tap-snapshots/test/index.js.test.cjs index b9b287f3ad18d..1e29ff05185d1 100644 --- a/smoke-tests/tap-snapshots/test/index.js.test.cjs +++ b/smoke-tests/tap-snapshots/test/index.js.test.cjs @@ -57,8 +57,9 @@ npm error Options: npm error [--install-strategy ] [--legacy-bundling] npm error [--global-style] [--omit [--omit ...]] npm error [--include [--include ...]] -npm error [--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] [--no-audit] -npm error [--no-bin-links] [--no-fund] [--dry-run] +npm error [--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] +npm error [--allow-git ] [--no-audit] [--no-bin-links] [--no-fund] +npm error [--dry-run] npm error [-w|--workspace [-w|--workspace ...]] npm error [--workspaces] [--include-workspace-root] [--install-links] npm error diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index ca6bf25c81fb0..d96ebf3412e04 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -16,6 +16,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna "access": null, "all": false, "allow-same-version": false, + "allow-git": "all", "also": null, "audit": true, "audit-level": null, @@ -189,6 +190,7 @@ exports[`test/lib/commands/config.js TAP config list --long > output matches sna _auth = (protected) access = null all = false +allow-git = "all" allow-same-version = false also = null audit = true diff --git a/tap-snapshots/test/lib/commands/view.js.test.cjs b/tap-snapshots/test/lib/commands/view.js.test.cjs index 3a55aa48a2da9..d5e7f6bfd4963 100644 --- a/tap-snapshots/test/lib/commands/view.js.test.cjs +++ b/tap-snapshots/test/lib/commands/view.js.test.cjs @@ -5,6 +5,22 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' +exports[`test/lib/commands/view.js TAP allow-git=root, package with multiple dist‑tags and no time > must match snapshot 1`] = ` + +gray@1.1.0 | Proprietary | deps: none | versions: 1 + +dist +.tarball: http://gray/1.1.0.tgz +.shasum: b + +dist-tags: +latest: 1.1.0 +stable: 1.1.0 +old: 1.0.0 +beta: 1.2.0-beta +alpha: 1.2.0-alpha +` + exports[`test/lib/commands/view.js TAP deprecated package with license, bugs, repository and other fields > must match snapshot 1`] = ` green@1.0.0 | ACME | deps: 2 | versions: 2 @@ -279,22 +295,6 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/commands/view.js TAP package with multiple dist‑tags and no time > must match snapshot 1`] = ` - -gray@1.1.0 | Proprietary | deps: none | versions: 1 - -dist -.tarball: http://gray/1.1.0.tgz -.shasum: b - -dist-tags: -latest: 1.1.0 -stable: 1.1.0 -old: 1.0.0 -beta: 1.2.0-beta -alpha: 1.2.0-alpha -` - exports[`test/lib/commands/view.js TAP package with no modified time > must match snapshot 1`] = ` cyan@1.0.0 | Proprietary | deps: none | versions: 2 diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index ba3a537259c59..b9b2e32355e94 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -215,6 +215,24 @@ upon by the current project. +#### \`allow-git\` + +* Default: "all" +* Type: "all", "none", or "root" + +Limits the ability for npm to fetch dependencies from git references. That +is, dependencies that point to a git repo instead of a version or semver +range. Please note that this could leave your tree incomplete and some +packages may not function as intended or designed. + +\`all\` allows any git dependencies to be fetched and installed. \`none\` +prevents any git dependencies from being fetched and installed. \`root\` only +allows git dependencies defined in your project's package.json to be fetched +installed. Also allows git dependencies to be fetched for other commands +like \`npm view\` + + + #### \`allow-same-version\` * Default: false @@ -2210,6 +2228,7 @@ Array [ "access", "all", "allow-same-version", + "allow-git", "also", "audit", "audit-level", @@ -2384,6 +2403,7 @@ Array [ "access", "all", "allow-same-version", + "allow-git", "also", "audit", "audit-level", @@ -2562,6 +2582,7 @@ Object { "_auth": null, "access": null, "all": false, + "allowGit": "all", "allowSameVersion": false, "audit": true, "auditLevel": null, @@ -2906,8 +2927,9 @@ Options: [--install-strategy ] [--legacy-bundling] [--global-style] [--omit [--omit ...]] [--include [--include ...]] -[--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] [--no-audit] -[--no-bin-links] [--no-fund] [--dry-run] +[--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] +[--allow-git ] [--no-audit] [--no-bin-links] [--no-fund] +[--dry-run] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -2929,6 +2951,7 @@ aliases: clean-install, ic, install-clean, isntall-clean #### \`strict-peer-deps\` #### \`foreground-scripts\` #### \`ignore-scripts\` +#### \`allow-git\` #### \`audit\` #### \`bin-links\` #### \`fund\` @@ -3006,7 +3029,8 @@ Options: [--global-style] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--include [--include ...]] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--ignore-scripts] [--allow-git ] [--no-audit] [--no-bin-links] +[--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -3028,6 +3052,7 @@ alias: ddp #### \`omit\` #### \`include\` #### \`ignore-scripts\` +#### \`allow-git\` #### \`audit\` #### \`bin-links\` #### \`fund\` @@ -3449,9 +3474,9 @@ Options: [--global-style] [--omit [--omit ...]] [--include [--include ...]] [--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only] -[--foreground-scripts] [--ignore-scripts] [--no-audit] [--before ] -[--no-bin-links] [--no-fund] [--dry-run] [--cpu ] [--os ] -[--libc ] +[--foreground-scripts] [--ignore-scripts] [--allow-git ] +[--no-audit] [--before ] [--no-bin-links] [--no-fund] [--dry-run] +[--cpu ] [--os ] [--libc ] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -3479,6 +3504,7 @@ aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall #### \`package-lock-only\` #### \`foreground-scripts\` #### \`ignore-scripts\` +#### \`allow-git\` #### \`audit\` #### \`before\` #### \`bin-links\` @@ -3503,8 +3529,9 @@ Options: [--install-strategy ] [--legacy-bundling] [--global-style] [--omit [--omit ...]] [--include [--include ...]] -[--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] [--no-audit] -[--no-bin-links] [--no-fund] [--dry-run] +[--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] +[--allow-git ] [--no-audit] [--no-bin-links] [--no-fund] +[--dry-run] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -3526,6 +3553,7 @@ aliases: cit, clean-install-test, sit #### \`strict-peer-deps\` #### \`foreground-scripts\` #### \`ignore-scripts\` +#### \`allow-git\` #### \`audit\` #### \`bin-links\` #### \`fund\` @@ -3549,9 +3577,9 @@ Options: [--global-style] [--omit [--omit ...]] [--include [--include ...]] [--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only] -[--foreground-scripts] [--ignore-scripts] [--no-audit] [--before ] -[--no-bin-links] [--no-fund] [--dry-run] [--cpu ] [--os ] -[--libc ] +[--foreground-scripts] [--ignore-scripts] [--allow-git ] +[--no-audit] [--before ] [--no-bin-links] [--no-fund] [--dry-run] +[--cpu ] [--os ] [--libc ] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -3579,6 +3607,7 @@ alias: it #### \`package-lock-only\` #### \`foreground-scripts\` #### \`ignore-scripts\` +#### \`allow-git\` #### \`audit\` #### \`before\` #### \`bin-links\` @@ -3606,7 +3635,8 @@ Options: [--global-style] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--include [--include ...]] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--ignore-scripts] [--allow-git ] [--no-audit] [--no-bin-links] +[--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -3631,6 +3661,7 @@ alias: ln #### \`omit\` #### \`include\` #### \`ignore-scripts\` +#### \`allow-git\` #### \`audit\` #### \`bin-links\` #### \`fund\` diff --git a/test/lib/commands/install.js b/test/lib/commands/install.js index bfc75c28cf51c..d886ed787166c 100644 --- a/test/lib/commands/install.js +++ b/test/lib/commands/install.js @@ -236,6 +236,40 @@ t.test('exec commands', async t => { await npm.exec('install', ['npm']) t.ok('No exceptions happen') }) + + t.test('allow-git=none', async t => { + const { npm } = await loadMockNpm(t, { + config: { + 'allow-git': 'none', + }, + }) + await t.rejects( + npm.exec('install', ['npm/npm']), + { + code: 'EALLOWGIT', + message: 'Fetching packages from git has been disabled', + package: 'github:npm/npm', + } + ) + }) + + t.test('allow-git=root refuses non-root git dependency', async t => { + const { npm } = await loadMockNpm(t, { + config: { + 'allow-git': 'none', + }, + prefixDir: { + 'package.json': JSON.stringify({ name: '@npmcli/test-package', version: '1.0.0' }), + abbrev: { + 'package.json': JSON.stringify({ name: 'abbrev', version: '1.0.0', dependencies: { npm: 'npm/npm' } }), + }, + }, + }) + await t.rejects( + npm.exec('install', ['./abbrev']), + /Fetching packages from git has been disabled/ + ) + }) }) t.test('completion', async t => { diff --git a/test/lib/commands/view.js b/test/lib/commands/view.js index 5b63cecf7daf7..e5e0fbff981c9 100644 --- a/test/lib/commands/view.js +++ b/test/lib/commands/view.js @@ -378,7 +378,7 @@ const packument = (nv, opts) => { } const loadMockNpm = async function (t, opts = {}) { - const mockNpm = await _loadMockNpm(t, { + return _loadMockNpm(t, { command: 'view', mocks: { pacote: { @@ -391,7 +391,6 @@ const loadMockNpm = async function (t, opts = {}) { ...opts.config, }, }) - return mockNpm } t.test('package from git', async t => { @@ -827,8 +826,17 @@ t.test('no package completion', async t => { t.end() }) -t.test('package with multiple dist‑tags and no time', async t => { - const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false } }) +t.test('allow-git=root, package with multiple dist‑tags and no time', async t => { + const { view, joinedOutput } = await loadMockNpm(t, { config: { unicode: false, 'allow-git': 'root' } }) await view.exec(['https://github.com/npm/gray']) t.matchSnapshot(joinedOutput()) }) + +t.test('allow-git=none', async t => { + const { view } = await loadMockNpm(t, { config: { 'allow-git': 'none' }, mocks: {} }) + await t.rejects(view.exec(['npm/npm']), { + code: 'EALLOWGIT', + package: 'github:npm/npm', + message: 'Fetching packages from git has been disabled', + }) +}) diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index 699735f349826..b4319fab6bd37 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -504,27 +504,25 @@ module.exports = cls => class IdealTreeBuilder extends cls { this.#depsQueue.push(tree) } - // This returns a promise because we might not have the name yet, and need to - // call pacote.manifest to find the name. + // This returns a promise because we might not have the name yet, and need to call pacote.manifest to find the name. async #add (tree, { add, saveType = null, saveBundle = false }) { // If we have a link it will need to be added relative to the target's path const path = tree.target.path - // get the name for each of the specs in the list. - // ie, doing `foo@bar` we just return foo but if it's a url or git, we - // don't know the name until we fetch it and look in its manifest. + // Get the name for each of the specs in the list. + // e.g. doing `foo@bar` we just return foo but if it's a url or git, we don't know the name until we fetch it and look in its manifest. await Promise.all(add.map(async rawSpec => { - // We do NOT provide the path to npa here, because user-additions need to - // be resolved relative to the tree being added to. + // We do NOT provide the path to npa here, because user-additions need to be resolved relative to the tree being added to. let spec = npa(rawSpec) - // if it's just @'' then we reload whatever's there, or get latest - // if it's an explicit tag, we need to install that specific tag version + // if it's just @'' then we reload whatever's there, or get latest. + // if it's an explicit tag, we need to install that specific tag version. const isTag = spec.rawSpec && spec.type === 'tag' // look up the names of file/directory/git specs if (!spec.name || isTag) { - const mani = await pacote.manifest(spec, { ...this.options }) + const _isRoot = tree.isProjectRoot || tree.isWorkspace + const mani = await pacote.manifest(spec, { ...this.options, _isRoot }) if (isTag) { // translate tag to a version spec = npa(`${mani.name}@${mani.version}`) diff --git a/workspaces/arborist/lib/node.js b/workspaces/arborist/lib/node.js index 8c6d361e86385..c0891df4af1e4 100644 --- a/workspaces/arborist/lib/node.js +++ b/workspaces/arborist/lib/node.js @@ -584,9 +584,7 @@ class Node { } get isProjectRoot () { - // only treat as project root if it's the actual link that is the root, - // or the target of the root link, but NOT if it's another link to the - // same root that happens to be somewhere else. + // only treat as project root if it's the actual link that is the root, or the target of the root link, but NOT if it's another link to the same root that happens to be somewhere else. return this === this.root || this === this.root.target } diff --git a/workspaces/config/lib/definitions/definitions.js b/workspaces/config/lib/definitions/definitions.js index 766182ad2bb1c..78818eb1489b5 100644 --- a/workspaces/config/lib/definitions/definitions.js +++ b/workspaces/config/lib/definitions/definitions.js @@ -187,6 +187,20 @@ const definitions = { `, flatten, }), + 'allow-git': new Definition('allow-git', { + default: 'all', + type: ['all', 'none', 'root'], + description: ` + Limits the ability for npm to fetch dependencies from git references. + That is, dependencies that point to a git repo instead of a version or semver range. + Please note that this could leave your tree incomplete and some packages may not function as intended or designed. + + \`all\` allows any git dependencies to be fetched and installed. + \`none\` prevents any git dependencies from being fetched and installed. + \`root\` only allows git dependencies defined in your project's package.json to be fetched installed. Also allows git dependencies to be fetched for other commands like \`npm view\` + `, + flatten, + }), also: new Definition('also', { default: null, type: [null, 'dev', 'development'], diff --git a/workspaces/config/tap-snapshots/test/type-description.js.test.cjs b/workspaces/config/tap-snapshots/test/type-description.js.test.cjs index 7325654569b3d..4eb0a5942f262 100644 --- a/workspaces/config/tap-snapshots/test/type-description.js.test.cjs +++ b/workspaces/config/tap-snapshots/test/type-description.js.test.cjs @@ -19,6 +19,11 @@ Object { "all": Array [ "boolean value (true or false)", ], + "allow-git": Array [ + "all", + "none", + "root", + ], "allow-same-version": Array [ "boolean value (true or false)", ], diff --git a/workspaces/libnpmdiff/lib/index.js b/workspaces/libnpmdiff/lib/index.js index 10532c1990dc4..3b3ce90408606 100644 --- a/workspaces/libnpmdiff/lib/index.js +++ b/workspaces/libnpmdiff/lib/index.js @@ -22,7 +22,10 @@ const diff = async (specs, opts = {}) => { aManifest, bManifest, ] = - await Promise.all(specs.map(spec => pacote.manifest(spec, opts))) + await Promise.all(specs.map(spec => pacote.manifest(spec, { + ...opts, + _isRoot: true, + }))) const versions = { a: aManifest.version, diff --git a/workspaces/libnpmexec/lib/index.js b/workspaces/libnpmexec/lib/index.js index 7b4c85a7510a1..502082c6b0dcc 100644 --- a/workspaces/libnpmexec/lib/index.js +++ b/workspaces/libnpmexec/lib/index.js @@ -26,7 +26,12 @@ const manifests = new Map() const getManifest = async (spec, flatOptions) => { if (!manifests.has(spec.raw)) { - const manifest = await pacote.manifest(spec, { ...flatOptions, preferOnline: true, Arborist }) + const manifest = await pacote.manifest(spec, { + ...flatOptions, + preferOnline: true, + Arborist, + _isRoot: true, + }) manifests.set(spec.raw, manifest) } return manifests.get(spec.raw) diff --git a/workspaces/libnpmpack/lib/index.js b/workspaces/libnpmpack/lib/index.js index bd3e0c7bd7232..df6d35cb172c6 100644 --- a/workspaces/libnpmpack/lib/index.js +++ b/workspaces/libnpmpack/lib/index.js @@ -12,7 +12,7 @@ async function pack (spec = 'file:.', opts = {}) { // gets spec spec = npa(spec) - const manifest = await pacote.manifest(spec, { ...opts, Arborist }) + const manifest = await pacote.manifest(spec, { ...opts, Arborist, _isRoot: true }) const stdio = opts.foregroundScripts ? 'inherit' : 'pipe'