From 90272661b16d861a5926af8ec394d32ec0f307fd Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Fri, 12 Apr 2024 15:25:51 -0700 Subject: [PATCH] deps: pacote@18.0.0 --- mock-registry/package.json | 2 +- node_modules/.gitignore | 12 + .../node_modules/@npmcli/run-script/LICENSE | 15 + .../run-script/lib/is-server-package.js | 11 + .../@npmcli/run-script/lib/make-spawn-args.js | 40 ++ .../run-script/lib/node-gyp-bin/node-gyp | 2 + .../run-script/lib/node-gyp-bin/node-gyp.cmd | 1 + .../@npmcli/run-script/lib/package-envs.js | 29 + .../@npmcli/run-script/lib/run-script-pkg.js | 114 ++++ .../@npmcli/run-script/lib/run-script.js | 15 + .../@npmcli/run-script/lib/set-path.js | 45 ++ .../@npmcli/run-script/lib/signal-manager.js | 50 ++ .../run-script/lib/validate-options.js | 39 ++ .../@npmcli/run-script/package.json | 53 ++ .../node_modules/pacote/LICENSE | 15 + .../node_modules/pacote/lib/bin.js | 158 ++++++ .../node_modules/pacote/lib/dir.js | 108 ++++ .../node_modules/pacote/lib/fetcher.js | 505 ++++++++++++++++++ .../node_modules/pacote/lib/file.js | 96 ++++ .../node_modules/pacote/lib/git.js | 327 ++++++++++++ .../node_modules/pacote/lib/index.js | 23 + .../node_modules/pacote/lib/registry.js | 369 +++++++++++++ .../node_modules/pacote/lib/remote.js | 91 ++++ .../pacote/lib/util/add-git-sha.js | 15 + .../node_modules/pacote/lib/util/cache-dir.js | 15 + .../pacote/lib/util/is-package-bin.js | 25 + .../node_modules/pacote/lib/util/npm.js | 14 + .../pacote/lib/util/tar-create-options.js | 31 ++ .../pacote/lib/util/trailing-slashes.js | 10 + .../node_modules/pacote/package.json | 79 +++ node_modules/pacote/lib/dir.js | 5 - node_modules/pacote/lib/fetcher.js | 2 +- node_modules/pacote/lib/git.js | 2 +- .../node_modules/@npmcli/run-script/LICENSE | 15 + .../run-script/lib/is-server-package.js | 11 + .../@npmcli/run-script/lib/make-spawn-args.js | 40 ++ .../run-script/lib/node-gyp-bin/node-gyp | 2 + .../run-script/lib/node-gyp-bin/node-gyp.cmd | 1 + .../@npmcli/run-script/lib/package-envs.js | 29 + .../@npmcli/run-script/lib/run-script-pkg.js | 110 ++++ .../@npmcli/run-script/lib/run-script.js | 15 + .../@npmcli/run-script/lib/set-path.js | 45 ++ .../@npmcli/run-script/lib/signal-manager.js | 50 ++ .../run-script/lib/validate-options.js | 39 ++ .../@npmcli/run-script/package.json | 54 ++ .../pacote/node_modules/proc-log/LICENSE | 15 + .../pacote/node_modules/proc-log/lib/index.js | 62 +++ .../pacote/node_modules/proc-log/package.json | 45 ++ node_modules/pacote/package.json | 10 +- package-lock.json | 94 +++- package.json | 2 +- workspaces/arborist/package.json | 2 +- .../config/lib/definitions/definitions.js | 2 +- workspaces/libnpmdiff/package.json | 2 +- workspaces/libnpmexec/package.json | 2 +- workspaces/libnpmpack/package.json | 2 +- 56 files changed, 2937 insertions(+), 30 deletions(-) create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/LICENSE create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/is-server-package.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/make-spawn-args.js create mode 100755 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp create mode 100755 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/package-envs.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script-pkg.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/set-path.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/signal-manager.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/validate-options.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/package.json create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/LICENSE create mode 100755 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/bin.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/dir.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/fetcher.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/file.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/git.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/index.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/registry.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/remote.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/add-git-sha.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/cache-dir.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/is-package-bin.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/npm.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/tar-create-options.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/trailing-slashes.js create mode 100644 node_modules/@npmcli/metavuln-calculator/node_modules/pacote/package.json create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/LICENSE create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/is-server-package.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/make-spawn-args.js create mode 100755 node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp create mode 100755 node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/package-envs.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script-pkg.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/set-path.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/signal-manager.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/lib/validate-options.js create mode 100644 node_modules/pacote/node_modules/@npmcli/run-script/package.json create mode 100644 node_modules/pacote/node_modules/proc-log/LICENSE create mode 100644 node_modules/pacote/node_modules/proc-log/lib/index.js create mode 100644 node_modules/pacote/node_modules/proc-log/package.json diff --git a/mock-registry/package.json b/mock-registry/package.json index 734cbfd48de38..8be3efdb1ff8f 100644 --- a/mock-registry/package.json +++ b/mock-registry/package.json @@ -51,7 +51,7 @@ "json-stringify-safe": "^5.0.1", "nock": "^13.3.3", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "tap": "^16.3.8" } } diff --git a/node_modules/.gitignore b/node_modules/.gitignore index 5aec8516deba6..a787d61a16e8e 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -31,6 +31,12 @@ !/@npmcli/installed-package-contents !/@npmcli/map-workspaces !/@npmcli/metavuln-calculator +!/@npmcli/metavuln-calculator/node_modules/ +/@npmcli/metavuln-calculator/node_modules/* +!/@npmcli/metavuln-calculator/node_modules/@npmcli/ +/@npmcli/metavuln-calculator/node_modules/@npmcli/* +!/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script +!/@npmcli/metavuln-calculator/node_modules/pacote !/@npmcli/name-from-folder !/@npmcli/node-gyp !/@npmcli/package-json @@ -187,6 +193,12 @@ !/npm-user-validate !/p-map !/pacote +!/pacote/node_modules/ +/pacote/node_modules/* +!/pacote/node_modules/@npmcli/ +/pacote/node_modules/@npmcli/* +!/pacote/node_modules/@npmcli/run-script +!/pacote/node_modules/proc-log !/parse-conflict-json !/path-key !/path-scurry diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/LICENSE b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/LICENSE new file mode 100644 index 0000000000000..19cec97b18468 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) npm, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/is-server-package.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/is-server-package.js new file mode 100644 index 0000000000000..c36c40d4898d5 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/is-server-package.js @@ -0,0 +1,11 @@ +const { stat } = require('node:fs/promises') +const { resolve } = require('node:path') + +module.exports = async path => { + try { + const st = await stat(resolve(path, 'server.js')) + return st.isFile() + } catch (er) { + return false + } +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/make-spawn-args.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/make-spawn-args.js new file mode 100644 index 0000000000000..8a32d7198cb2e --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/make-spawn-args.js @@ -0,0 +1,40 @@ +/* eslint camelcase: "off" */ +const setPATH = require('./set-path.js') +const { resolve } = require('path') +const npm_config_node_gyp = require.resolve('node-gyp/bin/node-gyp.js') + +const makeSpawnArgs = options => { + const { + event, + path, + scriptShell = true, + binPaths, + env, + stdio, + cmd, + args, + stdioString, + } = options + + const spawnEnv = setPATH(path, binPaths, { + // we need to at least save the PATH environment var + ...process.env, + ...env, + npm_package_json: resolve(path, 'package.json'), + npm_lifecycle_event: event, + npm_lifecycle_script: cmd, + npm_config_node_gyp, + }) + + const spawnOpts = { + env: spawnEnv, + stdioString, + stdio, + cwd: path, + shell: scriptShell, + } + + return [cmd, args, spawnOpts] +} + +module.exports = makeSpawnArgs diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp new file mode 100755 index 0000000000000..5bec64d961a3a --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +node "$npm_config_node_gyp" "$@" diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd new file mode 100755 index 0000000000000..4c6987ac9868b --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd @@ -0,0 +1 @@ +@node "%npm_config_node_gyp%" %* diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/package-envs.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/package-envs.js new file mode 100644 index 0000000000000..612f850fb076c --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/package-envs.js @@ -0,0 +1,29 @@ +const packageEnvs = (vals, prefix, env = {}) => { + for (const [key, val] of Object.entries(vals)) { + if (val === undefined) { + continue + } else if (val === null || val === false) { + env[`${prefix}${key}`] = '' + } else if (Array.isArray(val)) { + val.forEach((item, index) => { + packageEnvs({ [`${key}_${index}`]: item }, `${prefix}`, env) + }) + } else if (typeof val === 'object') { + packageEnvs(val, `${prefix}${key}_`, env) + } else { + env[`${prefix}${key}`] = String(val) + } + } + return env +} + +// https://github.com/npm/rfcs/pull/183 defines which fields we put into the environment +module.exports = pkg => { + return packageEnvs({ + name: pkg.name, + version: pkg.version, + config: pkg.config, + engines: pkg.engines, + bin: pkg.bin, + }, 'npm_package_') +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script-pkg.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script-pkg.js new file mode 100644 index 0000000000000..ea33db5629858 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script-pkg.js @@ -0,0 +1,114 @@ +const makeSpawnArgs = require('./make-spawn-args.js') +const promiseSpawn = require('@npmcli/promise-spawn') +const packageEnvs = require('./package-envs.js') +const { isNodeGypPackage, defaultGypInstallScript } = require('@npmcli/node-gyp') +const signalManager = require('./signal-manager.js') +const isServerPackage = require('./is-server-package.js') + +// you wouldn't like me when I'm angry... +const bruce = (id, event, cmd, args) => { + let banner = id + ? `\n> ${id} ${event}\n` + : `\n> ${event}\n` + banner += `> ${cmd.trim().replace(/\n/g, '\n> ')}` + if (args.length) { + banner += ` ${args.join(' ')}` + } + banner += '\n' + return banner +} + +const runScriptPkg = async options => { + const { + event, + path, + scriptShell, + binPaths = false, + env = {}, + stdio = 'pipe', + pkg, + args = [], + stdioString, + // note: only used when stdio:inherit + banner = true, + // how long to wait for a process.kill signal + // only exposed here so that we can make the test go a bit faster. + signalTimeout = 500, + } = options + + const { scripts = {}, gypfile } = pkg + let cmd = null + if (options.cmd) { + cmd = options.cmd + } else if (pkg.scripts && pkg.scripts[event]) { + cmd = pkg.scripts[event] + } else if ( + // If there is no preinstall or install script, default to rebuilding node-gyp packages. + event === 'install' && + !scripts.install && + !scripts.preinstall && + gypfile !== false && + await isNodeGypPackage(path) + ) { + cmd = defaultGypInstallScript + } else if (event === 'start' && await isServerPackage(path)) { + cmd = 'node server.js' + } + + if (!cmd) { + return { code: 0, signal: null } + } + + if (stdio === 'inherit' && banner !== false) { + // we're dumping to the parent's stdout, so print the banner + console.log(bruce(pkg._id, event, cmd, args)) + } + + const [spawnShell, spawnArgs, spawnOpts] = makeSpawnArgs({ + event, + path, + scriptShell, + binPaths, + env: { ...env, ...packageEnvs(pkg) }, + stdio, + cmd, + args, + stdioString, + }) + + const p = promiseSpawn(spawnShell, spawnArgs, spawnOpts, { + event, + script: cmd, + pkgid: pkg._id, + path, + }) + + if (stdio === 'inherit') { + signalManager.add(p.process) + } + + if (p.stdin) { + p.stdin.end() + } + + return p.catch(er => { + const { signal } = er + // coverage disabled because win32 never emits signals + /* istanbul ignore next */ + if (stdio === 'inherit' && signal) { + // by the time we reach here, the child has already exited. we send the + // signal back to ourselves again so that npm will exit with the same + // status as the child + process.kill(process.pid, signal) + + // just in case we don't die, reject after 500ms + // this also keeps the node process open long enough to actually + // get the signal, rather than terminating gracefully. + return new Promise((res, rej) => setTimeout(() => rej(er), signalTimeout)) + } else { + throw er + } + }) +} + +module.exports = runScriptPkg diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script.js new file mode 100644 index 0000000000000..b00304c8d6e7f --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/run-script.js @@ -0,0 +1,15 @@ +const PackageJson = require('@npmcli/package-json') +const runScriptPkg = require('./run-script-pkg.js') +const validateOptions = require('./validate-options.js') +const isServerPackage = require('./is-server-package.js') + +const runScript = async options => { + validateOptions(options) + if (options.pkg) { + return runScriptPkg(options) + } + const { content: pkg } = await PackageJson.normalize(options.path) + return runScriptPkg({ ...options, pkg }) +} + +module.exports = Object.assign(runScript, { isServerPackage }) diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/set-path.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/set-path.js new file mode 100644 index 0000000000000..c59c270d9969a --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/set-path.js @@ -0,0 +1,45 @@ +const { resolve, dirname, delimiter } = require('path') +// the path here is relative, even though it does not need to be +// in order to make the posix tests pass in windows +const nodeGypPath = resolve(__dirname, '../lib/node-gyp-bin') + +// Windows typically calls its PATH environ 'Path', but this is not +// guaranteed, nor is it guaranteed to be the only one. Merge them +// all together in the order they appear in the object. +const setPATH = (projectPath, binPaths, env) => { + const PATH = Object.keys(env).filter(p => /^path$/i.test(p) && env[p]) + .map(p => env[p].split(delimiter)) + .reduce((set, p) => set.concat(p.filter(concatted => !set.includes(concatted))), []) + .join(delimiter) + + const pathArr = [] + if (binPaths) { + pathArr.push(...binPaths) + } + // unshift the ./node_modules/.bin from every folder + // walk up until dirname() does nothing, at the root + // XXX we should specify a cwd that we don't go above + let p = projectPath + let pp + do { + pathArr.push(resolve(p, 'node_modules', '.bin')) + pp = p + p = dirname(p) + } while (p !== pp) + pathArr.push(nodeGypPath, PATH) + + const pathVal = pathArr.join(delimiter) + + // XXX include the node-gyp-bin path somehow? Probably better for + // npm or arborist or whoever to just provide that by putting it in + // the PATH environ, since that's preserved anyway. + for (const key of Object.keys(env)) { + if (/^path$/i.test(key)) { + env[key] = pathVal + } + } + + return env +} + +module.exports = setPATH diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/signal-manager.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/signal-manager.js new file mode 100644 index 0000000000000..a099a4af2b9be --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/signal-manager.js @@ -0,0 +1,50 @@ +const runningProcs = new Set() +let handlersInstalled = false + +const forwardedSignals = [ + 'SIGINT', + 'SIGTERM', +] + +// no-op, this is so receiving the signal doesn't cause us to exit immediately +// instead, we exit after all children have exited when we re-send the signal +// to ourselves. see the catch handler at the bottom of run-script-pkg.js +const handleSignal = signal => { + for (const proc of runningProcs) { + proc.kill(signal) + } +} + +const setupListeners = () => { + for (const signal of forwardedSignals) { + process.on(signal, handleSignal) + } + handlersInstalled = true +} + +const cleanupListeners = () => { + if (runningProcs.size === 0) { + for (const signal of forwardedSignals) { + process.removeListener(signal, handleSignal) + } + handlersInstalled = false + } +} + +const add = proc => { + runningProcs.add(proc) + if (!handlersInstalled) { + setupListeners() + } + + proc.once('exit', () => { + runningProcs.delete(proc) + cleanupListeners() + }) +} + +module.exports = { + add, + handleSignal, + forwardedSignals, +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/validate-options.js b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/validate-options.js new file mode 100644 index 0000000000000..8d855916ecd15 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/lib/validate-options.js @@ -0,0 +1,39 @@ +const validateOptions = options => { + if (typeof options !== 'object' || !options) { + throw new TypeError('invalid options object provided to runScript') + } + + const { + event, + path, + scriptShell, + env = {}, + stdio = 'pipe', + args = [], + cmd, + } = options + + if (!event || typeof event !== 'string') { + throw new TypeError('valid event not provided to runScript') + } + if (!path || typeof path !== 'string') { + throw new TypeError('valid path not provided to runScript') + } + if (scriptShell !== undefined && typeof scriptShell !== 'string') { + throw new TypeError('invalid scriptShell option provided to runScript') + } + if (typeof env !== 'object' || !env) { + throw new TypeError('invalid env option provided to runScript') + } + if (typeof stdio !== 'string' && !Array.isArray(stdio)) { + throw new TypeError('invalid stdio option provided to runScript') + } + if (!Array.isArray(args) || args.some(a => typeof a !== 'string')) { + throw new TypeError('invalid args option provided to runScript') + } + if (cmd !== undefined && typeof cmd !== 'string') { + throw new TypeError('invalid cmd option provided to runScript') + } +} + +module.exports = validateOptions diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/package.json b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/package.json new file mode 100644 index 0000000000000..1c98b1b170e26 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script/package.json @@ -0,0 +1,53 @@ +{ + "name": "@npmcli/run-script", + "version": "7.0.4", + "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)", + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "eslint": "eslint", + "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "lintfix": "npm run lint -- --fix", + "postlint": "template-oss-check", + "snap": "tap", + "posttest": "npm run lint", + "template-oss-apply": "template-oss-apply --force" + }, + "devDependencies": { + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.21.3", + "spawk": "^1.8.1", + "tap": "^16.0.1" + }, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "files": [ + "bin/", + "lib/" + ], + "main": "lib/run-script.js", + "repository": { + "type": "git", + "url": "https://github.com/npm/run-script.git" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.21.3", + "publish": "true" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/LICENSE b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/LICENSE new file mode 100644 index 0000000000000..a03cd0ed0b338 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter, Kat Marchán, npm, Inc., and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/bin.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/bin.js new file mode 100755 index 0000000000000..f35b62ca71a53 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/bin.js @@ -0,0 +1,158 @@ +#!/usr/bin/env node + +const run = conf => { + const pacote = require('../') + switch (conf._[0]) { + case 'resolve': + case 'manifest': + case 'packument': + if (conf._[0] === 'resolve' && conf.long) { + return pacote.manifest(conf._[1], conf).then(mani => ({ + resolved: mani._resolved, + integrity: mani._integrity, + from: mani._from, + })) + } + return pacote[conf._[0]](conf._[1], conf) + + case 'tarball': + if (!conf._[2] || conf._[2] === '-') { + return pacote.tarball.stream(conf._[1], stream => { + stream.pipe( + conf.testStdout || + /* istanbul ignore next */ + process.stdout + ) + // make sure it resolves something falsey + return stream.promise().then(() => { + return false + }) + }, conf) + } else { + return pacote.tarball.file(conf._[1], conf._[2], conf) + } + + case 'extract': + return pacote.extract(conf._[1], conf._[2], conf) + + default: /* istanbul ignore next */ { + throw new Error(`bad command: ${conf._[0]}`) + } + } +} + +const version = require('../package.json').version +const usage = () => +`Pacote - The JavaScript Package Handler, v${version} + +Usage: + + pacote resolve + Resolve a specifier and output the fully resolved target + Returns integrity and from if '--long' flag is set. + + pacote manifest + Fetch a manifest and print to stdout + + pacote packument + Fetch a full packument and print to stdout + + pacote tarball [] + Fetch a package tarball and save to + If is missing or '-', the tarball will be streamed to stdout. + + pacote extract + Extract a package to the destination folder. + +Configuration values all match the names of configs passed to npm, or +options passed to Pacote. Additional flags for this executable: + + --long Print an object from 'resolve', including integrity and spec. + --json Print result objects as JSON rather than node's default. + (This is the default if stdout is not a TTY.) + --help -h Print this helpful text. + +For example '--cache=/path/to/folder' will use that folder as the cache. +` + +const shouldJSON = (conf, result) => + conf.json || + !process.stdout.isTTY && + conf.json === undefined && + result && + typeof result === 'object' + +const pretty = (conf, result) => + shouldJSON(conf, result) ? JSON.stringify(result, 0, 2) : result + +let addedLogListener = false +const main = args => { + const conf = parse(args) + if (conf.help || conf.h) { + return console.log(usage()) + } + + if (!addedLogListener) { + process.on('log', console.error) + addedLogListener = true + } + + try { + return run(conf) + .then(result => result && console.log(pretty(conf, result))) + .catch(er => { + console.error(er) + process.exit(1) + }) + } catch (er) { + console.error(er.message) + console.error(usage()) + } +} + +const parseArg = arg => { + const split = arg.slice(2).split('=') + const k = split.shift() + const v = split.join('=') + const no = /^no-/.test(k) && !v + const key = (no ? k.slice(3) : k) + .replace(/^tag$/, 'defaultTag') + .replace(/-([a-z])/g, (_, c) => c.toUpperCase()) + const value = v ? v.replace(/^~/, process.env.HOME) : !no + return { key, value } +} + +const parse = args => { + const conf = { + _: [], + cache: process.env.HOME + '/.npm/_cacache', + } + let dashdash = false + args.forEach(arg => { + if (dashdash) { + conf._.push(arg) + } else if (arg === '--') { + dashdash = true + } else if (arg === '-h') { + conf.help = true + } else if (/^--/.test(arg)) { + const { key, value } = parseArg(arg) + conf[key] = value + } else { + conf._.push(arg) + } + }) + return conf +} + +if (module === require.main) { + main(process.argv.slice(2)) +} else { + module.exports = { + main, + run, + usage, + parseArg, + parse, + } +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/dir.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/dir.js new file mode 100644 index 0000000000000..420afc5802cb2 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/dir.js @@ -0,0 +1,108 @@ +const Fetcher = require('./fetcher.js') +const FileFetcher = require('./file.js') +const { Minipass } = require('minipass') +const tarCreateOptions = require('./util/tar-create-options.js') +const packlist = require('npm-packlist') +const tar = require('tar') +const _prepareDir = Symbol('_prepareDir') +const { resolve } = require('path') +const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson') + +const runScript = require('@npmcli/run-script') + +const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +class DirFetcher extends Fetcher { + constructor (spec, opts) { + super(spec, opts) + // just the fully resolved filename + this.resolved = this.spec.fetchSpec + + this.tree = opts.tree || null + this.Arborist = opts.Arborist || null + } + + // exposes tarCreateOptions as public API + static tarCreateOptions (manifest) { + return tarCreateOptions(manifest) + } + + get types () { + return ['directory'] + } + + [_prepareDir] () { + return this.manifest().then(mani => { + if (!mani.scripts || !mani.scripts.prepare) { + return + } + + // we *only* run prepare. + // pre/post-pack is run by the npm CLI for publish and pack, + // but this function is *also* run when installing git deps + const stdio = this.opts.foregroundScripts ? 'inherit' : 'pipe' + + // hide the banner if silent opt is passed in, or if prepare running + // in the background. + const banner = this.opts.silent ? false : stdio === 'inherit' + + return runScript({ + pkg: mani, + event: 'prepare', + path: this.resolved, + stdio, + banner, + env: { + npm_package_resolved: this.resolved, + npm_package_integrity: this.integrity, + npm_package_json: resolve(this.resolved, 'package.json'), + }, + }) + }) + } + + [_tarballFromResolved] () { + if (!this.tree && !this.Arborist) { + throw new Error('DirFetcher requires either a tree or an Arborist constructor to pack') + } + + const stream = new Minipass() + stream.resolved = this.resolved + stream.integrity = this.integrity + + const { prefix, workspaces } = this.opts + + // run the prepare script, get the list of files, and tar it up + // pipe to the stream, and proxy errors the chain. + this[_prepareDir]() + .then(async () => { + if (!this.tree) { + const arb = new this.Arborist({ path: this.resolved }) + this.tree = await arb.loadActual() + } + return packlist(this.tree, { path: this.resolved, prefix, workspaces }) + }) + .then(files => tar.c(tarCreateOptions(this.package), files) + .on('error', er => stream.emit('error', er)).pipe(stream)) + .catch(er => stream.emit('error', er)) + return stream + } + + manifest () { + if (this.package) { + return Promise.resolve(this.package) + } + + return this[_readPackageJson](this.resolved + '/package.json') + .then(mani => this.package = { + ...mani, + _integrity: this.integrity && String(this.integrity), + _resolved: this.resolved, + _from: this.from, + }) + } + + packument () { + return FileFetcher.prototype.packument.apply(this) + } +} +module.exports = DirFetcher diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/fetcher.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/fetcher.js new file mode 100644 index 0000000000000..287ec7956fc97 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/fetcher.js @@ -0,0 +1,505 @@ +// This is the base class that the other fetcher types in lib +// all descend from. +// It handles the unpacking and retry logic that is shared among +// all of the other Fetcher types. + +const npa = require('npm-package-arg') +const ssri = require('ssri') +const { promisify } = require('util') +const { basename, dirname } = require('path') +const tar = require('tar') +const { log } = require('proc-log') +const retry = require('promise-retry') +const fs = require('fs/promises') +const fsm = require('fs-minipass') +const cacache = require('cacache') +const isPackageBin = require('./util/is-package-bin.js') +const removeTrailingSlashes = require('./util/trailing-slashes.js') +const getContents = require('@npmcli/installed-package-contents') +const readPackageJsonFast = require('read-package-json-fast') +const readPackageJson = promisify(require('read-package-json')) +const { Minipass } = require('minipass') + +const cacheDir = require('./util/cache-dir.js') + +// Private methods. +// Child classes should not have to override these. +// Users should never call them. +const _extract = Symbol('_extract') +const _mkdir = Symbol('_mkdir') +const _empty = Symbol('_empty') +const _toFile = Symbol('_toFile') +const _tarxOptions = Symbol('_tarxOptions') +const _entryMode = Symbol('_entryMode') +const _istream = Symbol('_istream') +const _assertType = Symbol('_assertType') +const _tarballFromCache = Symbol('_tarballFromCache') +const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches') +const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson') + +class FetcherBase { + constructor (spec, opts) { + if (!opts || typeof opts !== 'object') { + throw new TypeError('options object is required') + } + this.spec = npa(spec, opts.where) + + this.allowGitIgnore = !!opts.allowGitIgnore + + // a bit redundant because presumably the caller already knows this, + // but it makes it easier to not have to keep track of the requested + // spec when we're dispatching thousands of these at once, and normalizing + // is nice. saveSpec is preferred if set, because it turns stuff like + // x/y#committish into github:x/y#committish. use name@rawSpec for + // registry deps so that we turn xyz and xyz@ -> xyz@ + this.from = this.spec.registry + ? `${this.spec.name}@${this.spec.rawSpec}` : this.spec.saveSpec + + this[_assertType]() + // clone the opts object so that others aren't upset when we mutate it + // by adding/modifying the integrity value. + this.opts = { ...opts } + + this.cache = opts.cache || cacheDir().cacache + this.tufCache = opts.tufCache || cacheDir().tufcache + this.resolved = opts.resolved || null + + // default to caching/verifying with sha512, that's what we usually have + // need to change this default, or start overriding it, when sha512 + // is no longer strong enough. + this.defaultIntegrityAlgorithm = opts.defaultIntegrityAlgorithm || 'sha512' + + if (typeof opts.integrity === 'string') { + this.opts.integrity = ssri.parse(opts.integrity) + } + + this.package = null + this.type = this.constructor.name + this.fmode = opts.fmode || 0o666 + this.dmode = opts.dmode || 0o777 + // we don't need a default umask, because we don't chmod files coming + // out of package tarballs. they're forced to have a mode that is + // valid, regardless of what's in the tarball entry, and then we let + // the process's umask setting do its job. but if configured, we do + // respect it. + this.umask = opts.umask || 0 + + this.preferOnline = !!opts.preferOnline + this.preferOffline = !!opts.preferOffline + this.offline = !!opts.offline + + this.before = opts.before + this.fullMetadata = this.before ? true : !!opts.fullMetadata + this.fullReadJson = !!opts.fullReadJson + if (this.fullReadJson) { + this[_readPackageJson] = readPackageJson + } else { + this[_readPackageJson] = readPackageJsonFast + } + + // rrh is a registry hostname or 'never' or 'always' + // defaults to registry.npmjs.org + this.replaceRegistryHost = (!opts.replaceRegistryHost || opts.replaceRegistryHost === 'npmjs') ? + 'registry.npmjs.org' : opts.replaceRegistryHost + + this.defaultTag = opts.defaultTag || 'latest' + this.registry = removeTrailingSlashes(opts.registry || 'https://registry.npmjs.org') + + // command to run 'prepare' scripts on directories and git dirs + // To use pacote with yarn, for example, set npmBin to 'yarn' + // and npmCliConfig with yarn's equivalents. + this.npmBin = opts.npmBin || 'npm' + + // command to install deps for preparing + this.npmInstallCmd = opts.npmInstallCmd || ['install', '--force'] + + // XXX fill more of this in based on what we know from this.opts + // we explicitly DO NOT fill in --tag, though, since we are often + // going to be packing in the context of a publish, which may set + // a dist-tag, but certainly wants to keep defaulting to latest. + this.npmCliConfig = opts.npmCliConfig || [ + `--cache=${dirname(this.cache)}`, + `--prefer-offline=${!!this.preferOffline}`, + `--prefer-online=${!!this.preferOnline}`, + `--offline=${!!this.offline}`, + ...(this.before ? [`--before=${this.before.toISOString()}`] : []), + '--no-progress', + '--no-save', + '--no-audit', + // override any omit settings from the environment + '--include=dev', + '--include=peer', + '--include=optional', + // we need the actual things, not just the lockfile + '--no-package-lock-only', + '--no-dry-run', + ] + } + + get integrity () { + return this.opts.integrity || null + } + + set integrity (i) { + if (!i) { + return + } + + i = ssri.parse(i) + const current = this.opts.integrity + + // do not ever update an existing hash value, but do + // merge in NEW algos and hashes that we don't already have. + if (current) { + current.merge(i) + } else { + this.opts.integrity = i + } + } + + get notImplementedError () { + return new Error('not implemented in this fetcher type: ' + this.type) + } + + // override in child classes + // Returns a Promise that resolves to this.resolved string value + resolve () { + return this.resolved ? Promise.resolve(this.resolved) + : Promise.reject(this.notImplementedError) + } + + packument () { + return Promise.reject(this.notImplementedError) + } + + // override in child class + // returns a manifest containing: + // - name + // - version + // - _resolved + // - _integrity + // - plus whatever else was in there (corgi, full metadata, or pj file) + manifest () { + return Promise.reject(this.notImplementedError) + } + + // private, should be overridden. + // Note that they should *not* calculate or check integrity or cache, + // but *just* return the raw tarball data stream. + [_tarballFromResolved] () { + throw this.notImplementedError + } + + // public, should not be overridden + tarball () { + return this.tarballStream(stream => stream.concat().then(data => { + data.integrity = this.integrity && String(this.integrity) + data.resolved = this.resolved + data.from = this.from + return data + })) + } + + // private + // Note: cacache will raise a EINTEGRITY error if the integrity doesn't match + [_tarballFromCache] () { + return cacache.get.stream.byDigest(this.cache, this.integrity, this.opts) + } + + get [_cacheFetches] () { + return true + } + + [_istream] (stream) { + // if not caching this, just return it + if (!this.opts.cache || !this[_cacheFetches]) { + // instead of creating a new integrity stream, we only piggyback on the + // provided stream's events + if (stream.hasIntegrityEmitter) { + stream.on('integrity', i => this.integrity = i) + return stream + } + + const istream = ssri.integrityStream(this.opts) + istream.on('integrity', i => this.integrity = i) + stream.on('error', err => istream.emit('error', err)) + return stream.pipe(istream) + } + + // we have to return a stream that gets ALL the data, and proxies errors, + // but then pipe from the original tarball stream into the cache as well. + // To do this without losing any data, and since the cacache put stream + // is not a passthrough, we have to pipe from the original stream into + // the cache AFTER we pipe into the middleStream. Since the cache stream + // has an asynchronous flush to write its contents to disk, we need to + // defer the middleStream end until the cache stream ends. + const middleStream = new Minipass() + stream.on('error', err => middleStream.emit('error', err)) + stream.pipe(middleStream, { end: false }) + const cstream = cacache.put.stream( + this.opts.cache, + `pacote:tarball:${this.from}`, + this.opts + ) + cstream.on('integrity', i => this.integrity = i) + cstream.on('error', err => stream.emit('error', err)) + stream.pipe(cstream) + + // eslint-disable-next-line promise/catch-or-return + cstream.promise().catch(() => {}).then(() => middleStream.end()) + return middleStream + } + + pickIntegrityAlgorithm () { + return this.integrity ? this.integrity.pickAlgorithm(this.opts) + : this.defaultIntegrityAlgorithm + } + + // TODO: check error class, once those are rolled out to our deps + isDataCorruptionError (er) { + return er.code === 'EINTEGRITY' || er.code === 'Z_DATA_ERROR' + } + + // override the types getter + get types () { + return false + } + + [_assertType] () { + if (this.types && !this.types.includes(this.spec.type)) { + throw new TypeError(`Wrong spec type (${ + this.spec.type + }) for ${ + this.constructor.name + }. Supported types: ${this.types.join(', ')}`) + } + } + + // We allow ENOENTs from cacache, but not anywhere else. + // An ENOENT trying to read a tgz file, for example, is Right Out. + isRetriableError (er) { + // TODO: check error class, once those are rolled out to our deps + return this.isDataCorruptionError(er) || + er.code === 'ENOENT' || + er.code === 'EISDIR' + } + + // Mostly internal, but has some uses + // Pass in a function which returns a promise + // Function will be called 1 or more times with streams that may fail. + // Retries: + // Function MUST handle errors on the stream by rejecting the promise, + // so that retry logic can pick it up and either retry or fail whatever + // promise it was making (ie, failing extraction, etc.) + // + // The return value of this method is a Promise that resolves the same + // as whatever the streamHandler resolves to. + // + // This should never be overridden by child classes, but it is public. + tarballStream (streamHandler) { + // Only short-circuit via cache if we have everything else we'll need, + // and the user has not expressed a preference for checking online. + + const fromCache = ( + !this.preferOnline && + this.integrity && + this.resolved + ) ? streamHandler(this[_tarballFromCache]()).catch(er => { + if (this.isDataCorruptionError(er)) { + log.warn('tarball', `cached data for ${ + this.spec + } (${this.integrity}) seems to be corrupted. Refreshing cache.`) + return this.cleanupCached().then(() => { + throw er + }) + } else { + throw er + } + }) : null + + const fromResolved = er => { + if (er) { + if (!this.isRetriableError(er)) { + throw er + } + log.silly('tarball', `no local data for ${ + this.spec + }. Extracting by manifest.`) + } + return this.resolve().then(() => retry(tryAgain => + streamHandler(this[_istream](this[_tarballFromResolved]())) + .catch(streamErr => { + // Most likely data integrity. A cache ENOENT error is unlikely + // here, since we're definitely not reading from the cache, but it + // IS possible that the fetch subsystem accessed the cache, and the + // entry got blown away or something. Try one more time to be sure. + if (this.isRetriableError(streamErr)) { + log.warn('tarball', `tarball data for ${ + this.spec + } (${this.integrity}) seems to be corrupted. Trying again.`) + return this.cleanupCached().then(() => tryAgain(streamErr)) + } + throw streamErr + }), { retries: 1, minTimeout: 0, maxTimeout: 0 })) + } + + return fromCache ? fromCache.catch(fromResolved) : fromResolved() + } + + cleanupCached () { + return cacache.rm.content(this.cache, this.integrity, this.opts) + } + + [_empty] (path) { + return getContents({ path, depth: 1 }).then(contents => Promise.all( + contents.map(entry => fs.rm(entry, { recursive: true, force: true })))) + } + + async [_mkdir] (dest) { + await this[_empty](dest) + return await fs.mkdir(dest, { recursive: true }) + } + + // extraction is always the same. the only difference is where + // the tarball comes from. + async extract (dest) { + await this[_mkdir](dest) + return this.tarballStream((tarball) => this[_extract](dest, tarball)) + } + + [_toFile] (dest) { + return this.tarballStream(str => new Promise((res, rej) => { + const writer = new fsm.WriteStream(dest) + str.on('error', er => writer.emit('error', er)) + writer.on('error', er => rej(er)) + writer.on('close', () => res({ + integrity: this.integrity && String(this.integrity), + resolved: this.resolved, + from: this.from, + })) + str.pipe(writer) + })) + } + + // don't use this[_mkdir] because we don't want to rimraf anything + async tarballFile (dest) { + const dir = dirname(dest) + await fs.mkdir(dir, { recursive: true }) + return this[_toFile](dest) + } + + [_extract] (dest, tarball) { + const extractor = tar.x(this[_tarxOptions]({ cwd: dest })) + const p = new Promise((resolve, reject) => { + extractor.on('end', () => { + resolve({ + resolved: this.resolved, + integrity: this.integrity && String(this.integrity), + from: this.from, + }) + }) + + extractor.on('error', er => { + log.warn('tar', er.message) + log.silly('tar', er) + reject(er) + }) + + tarball.on('error', er => reject(er)) + }) + + tarball.pipe(extractor) + return p + } + + // always ensure that entries are at least as permissive as our configured + // dmode/fmode, but never more permissive than the umask allows. + [_entryMode] (path, mode, type) { + const m = /Directory|GNUDumpDir/.test(type) ? this.dmode + : /File$/.test(type) ? this.fmode + : /* istanbul ignore next - should never happen in a pkg */ 0 + + // make sure package bins are executable + const exe = isPackageBin(this.package, path) ? 0o111 : 0 + // always ensure that files are read/writable by the owner + return ((mode | m) & ~this.umask) | exe | 0o600 + } + + [_tarxOptions] ({ cwd }) { + const sawIgnores = new Set() + return { + cwd, + noChmod: true, + noMtime: true, + filter: (name, entry) => { + if (/Link$/.test(entry.type)) { + return false + } + entry.mode = this[_entryMode](entry.path, entry.mode, entry.type) + // this replicates the npm pack behavior where .gitignore files + // are treated like .npmignore files, but only if a .npmignore + // file is not present. + if (/File$/.test(entry.type)) { + const base = basename(entry.path) + if (base === '.npmignore') { + sawIgnores.add(entry.path) + } else if (base === '.gitignore' && !this.allowGitIgnore) { + // rename, but only if there's not already a .npmignore + const ni = entry.path.replace(/\.gitignore$/, '.npmignore') + if (sawIgnores.has(ni)) { + return false + } + entry.path = ni + } + return true + } + }, + strip: 1, + onwarn: /* istanbul ignore next - we can trust that tar logs */ + (code, msg, data) => { + log.warn('tar', code, msg) + log.silly('tar', code, msg, data) + }, + umask: this.umask, + // always ignore ownership info from tarball metadata + preserveOwner: false, + } + } +} + +module.exports = FetcherBase + +// Child classes +const GitFetcher = require('./git.js') +const RegistryFetcher = require('./registry.js') +const FileFetcher = require('./file.js') +const DirFetcher = require('./dir.js') +const RemoteFetcher = require('./remote.js') + +// 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': + return new GitFetcher(spec, opts) + + case 'remote': + return new RemoteFetcher(spec, opts) + + case 'version': + case 'range': + case 'tag': + case 'alias': + return new RegistryFetcher(spec.subSpec || spec, opts) + + case 'file': + return new FileFetcher(spec, opts) + + case 'directory': + return new DirFetcher(spec, opts) + + default: + throw new TypeError('Unknown spec type: ' + spec.type) + } +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/file.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/file.js new file mode 100644 index 0000000000000..bf99bb86e359e --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/file.js @@ -0,0 +1,96 @@ +const Fetcher = require('./fetcher.js') +const fsm = require('fs-minipass') +const cacache = require('cacache') +const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +const _exeBins = Symbol('_exeBins') +const { resolve } = require('path') +const fs = require('fs') +const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson') + +class FileFetcher extends Fetcher { + constructor (spec, opts) { + super(spec, opts) + // just the fully resolved filename + this.resolved = this.spec.fetchSpec + } + + get types () { + return ['file'] + } + + manifest () { + if (this.package) { + return Promise.resolve(this.package) + } + + // have to unpack the tarball for this. + return cacache.tmp.withTmp(this.cache, this.opts, dir => + this.extract(dir) + .then(() => this[_readPackageJson](dir + '/package.json')) + .then(mani => this.package = { + ...mani, + _integrity: this.integrity && String(this.integrity), + _resolved: this.resolved, + _from: this.from, + })) + } + + [_exeBins] (pkg, dest) { + if (!pkg.bin) { + return Promise.resolve() + } + + return Promise.all(Object.keys(pkg.bin).map(k => new Promise(res => { + const script = resolve(dest, pkg.bin[k]) + // Best effort. Ignore errors here, the only result is that + // a bin script is not executable. But if it's missing or + // something, we just leave it for a later stage to trip over + // when we can provide a more useful contextual error. + fs.stat(script, (er, st) => { + if (er) { + return res() + } + const mode = st.mode | 0o111 + if (mode === st.mode) { + return res() + } + fs.chmod(script, mode, res) + }) + }))) + } + + extract (dest) { + // if we've already loaded the manifest, then the super got it. + // but if not, read the unpacked manifest and chmod properly. + return super.extract(dest) + .then(result => this.package ? result + : this[_readPackageJson](dest + '/package.json').then(pkg => + this[_exeBins](pkg, dest)).then(() => result)) + } + + [_tarballFromResolved] () { + // create a read stream and return it + return new fsm.ReadStream(this.resolved) + } + + packument () { + // simulate based on manifest + return this.manifest().then(mani => ({ + name: mani.name, + 'dist-tags': { + [this.defaultTag]: mani.version, + }, + versions: { + [mani.version]: { + ...mani, + dist: { + tarball: `file:${this.resolved}`, + integrity: this.integrity && String(this.integrity), + }, + }, + }, + })) + } +} + +module.exports = FileFetcher diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/git.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/git.js new file mode 100644 index 0000000000000..533d83d3d8dd3 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/git.js @@ -0,0 +1,327 @@ +const Fetcher = require('./fetcher.js') +const FileFetcher = require('./file.js') +const RemoteFetcher = require('./remote.js') +const DirFetcher = require('./dir.js') +const hashre = /^[a-f0-9]{40}$/ +const git = require('@npmcli/git') +const pickManifest = require('npm-pick-manifest') +const npa = require('npm-package-arg') +const { Minipass } = require('minipass') +const cacache = require('cacache') +const { log } = require('proc-log') +const npm = require('./util/npm.js') + +const _resolvedFromRepo = Symbol('_resolvedFromRepo') +const _resolvedFromHosted = Symbol('_resolvedFromHosted') +const _resolvedFromClone = Symbol('_resolvedFromClone') +const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +const _addGitSha = Symbol('_addGitSha') +const addGitSha = require('./util/add-git-sha.js') +const _clone = Symbol('_clone') +const _cloneHosted = Symbol('_cloneHosted') +const _cloneRepo = Symbol('_cloneRepo') +const _setResolvedWithSha = Symbol('_setResolvedWithSha') +const _prepareDir = Symbol('_prepareDir') +const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson') + +// get the repository url. +// prefer https if there's auth, since ssh will drop that. +// otherwise, prefer ssh if available (more secure). +// We have to add the git+ back because npa suppresses it. +const repoUrl = (h, opts) => + h.sshurl && !(h.https && h.auth) && addGitPlus(h.sshurl(opts)) || + h.https && addGitPlus(h.https(opts)) + +// add git+ to the url, but only one time. +const addGitPlus = url => url && `git+${url}`.replace(/^(git\+)+/, 'git+') + +class GitFetcher extends Fetcher { + constructor (spec, opts) { + super(spec, opts) + + // we never want to compare integrity for git dependencies: npm/rfcs#525 + if (this.opts.integrity) { + delete this.opts.integrity + log.warn(`skipping integrity check for git dependency ${this.spec.fetchSpec}`) + } + + this.resolvedRef = null + if (this.spec.hosted) { + this.from = this.spec.hosted.shortcut({ noCommittish: false }) + } + + // shortcut: avoid full clone when we can go straight to the tgz + // if we have the full sha and it's a hosted git platform + if (this.spec.gitCommittish && hashre.test(this.spec.gitCommittish)) { + this.resolvedSha = this.spec.gitCommittish + // use hosted.tarball() when we shell to RemoteFetcher later + this.resolved = this.spec.hosted + ? repoUrl(this.spec.hosted, { noCommittish: false }) + : this.spec.rawSpec + } else { + this.resolvedSha = '' + } + + this.Arborist = opts.Arborist || null + } + + // just exposed to make it easier to test all the combinations + static repoUrl (hosted, opts) { + return repoUrl(hosted, opts) + } + + get types () { + return ['git'] + } + + resolve () { + // likely a hosted git repo with a sha, so get the tarball url + // but in general, no reason to resolve() more than necessary! + if (this.resolved) { + return super.resolve() + } + + // fetch the git repo and then look at the current hash + const h = this.spec.hosted + // try to use ssh, fall back to git. + return h ? this[_resolvedFromHosted](h) + : this[_resolvedFromRepo](this.spec.fetchSpec) + } + + // first try https, since that's faster and passphrase-less for + // public repos, and supports private repos when auth is provided. + // Fall back to SSH to support private repos + // NB: we always store the https url in resolved field if auth + // is present, otherwise ssh if the hosted type provides it + [_resolvedFromHosted] (hosted) { + return this[_resolvedFromRepo](hosted.https && hosted.https()) + .catch(er => { + // Throw early since we know pathspec errors will fail again if retried + if (er instanceof git.errors.GitPathspecError) { + throw er + } + const ssh = hosted.sshurl && hosted.sshurl() + // no fallthrough if we can't fall through or have https auth + if (!ssh || hosted.auth) { + throw er + } + return this[_resolvedFromRepo](ssh) + }) + } + + [_resolvedFromRepo] (gitRemote) { + // XXX make this a custom error class + if (!gitRemote) { + return Promise.reject(new Error(`No git url for ${this.spec}`)) + } + const gitRange = this.spec.gitRange + const name = this.spec.name + return git.revs(gitRemote, this.opts).then(remoteRefs => { + return gitRange ? pickManifest({ + versions: remoteRefs.versions, + 'dist-tags': remoteRefs['dist-tags'], + name, + }, gitRange, this.opts) + : this.spec.gitCommittish ? + remoteRefs.refs[this.spec.gitCommittish] || + remoteRefs.refs[remoteRefs.shas[this.spec.gitCommittish]] + : remoteRefs.refs.HEAD // no git committish, get default head + }).then(revDoc => { + // the committish provided isn't in the rev list + // things like HEAD~3 or @yesterday can land here. + if (!revDoc || !revDoc.sha) { + return this[_resolvedFromClone]() + } + + this.resolvedRef = revDoc + this.resolvedSha = revDoc.sha + this[_addGitSha](revDoc.sha) + return this.resolved + }) + } + + [_setResolvedWithSha] (withSha) { + // we haven't cloned, so a tgz download is still faster + // of course, if it's not a known host, we can't do that. + this.resolved = !this.spec.hosted ? withSha + : repoUrl(npa(withSha).hosted, { noCommittish: false }) + } + + // when we get the git sha, we affix it to our spec to build up + // either a git url with a hash, or a tarball download URL + [_addGitSha] (sha) { + this[_setResolvedWithSha](addGitSha(this.spec, sha)) + } + + [_resolvedFromClone] () { + // do a full or shallow clone, then look at the HEAD + // kind of wasteful, but no other option, really + return this[_clone](dir => this.resolved) + } + + [_prepareDir] (dir) { + return this[_readPackageJson](dir + '/package.json').then(mani => { + // no need if we aren't going to do any preparation. + const scripts = mani.scripts + if (!mani.workspaces && (!scripts || !( + scripts.postinstall || + scripts.build || + scripts.preinstall || + scripts.install || + scripts.prepack || + scripts.prepare))) { + return + } + + // to avoid cases where we have an cycle of git deps that depend + // on one another, we only ever do preparation for one instance + // of a given git dep along the chain of installations. + // Note that this does mean that a dependency MAY in theory end up + // trying to run its prepare script using a dependency that has not + // been properly prepared itself, but that edge case is smaller + // and less hazardous than a fork bomb of npm and git commands. + const noPrepare = !process.env._PACOTE_NO_PREPARE_ ? [] + : process.env._PACOTE_NO_PREPARE_.split('\n') + if (noPrepare.includes(this.resolved)) { + log.info('prepare', 'skip prepare, already seen', this.resolved) + return + } + noPrepare.push(this.resolved) + + // the DirFetcher will do its own preparation to run the prepare scripts + // All we have to do is put the deps in place so that it can succeed. + return npm( + this.npmBin, + [].concat(this.npmInstallCmd).concat(this.npmCliConfig), + dir, + { ...process.env, _PACOTE_NO_PREPARE_: noPrepare.join('\n') }, + { message: 'git dep preparation failed' } + ) + }) + } + + [_tarballFromResolved] () { + const stream = new Minipass() + stream.resolved = this.resolved + stream.from = this.from + + // check it out and then shell out to the DirFetcher tarball packer + this[_clone](dir => this[_prepareDir](dir) + .then(() => new Promise((res, rej) => { + if (!this.Arborist) { + throw new Error('GitFetcher requires an Arborist constructor to pack a tarball') + } + const df = new DirFetcher(`file:${dir}`, { + ...this.opts, + Arborist: this.Arborist, + resolved: null, + integrity: null, + }) + const dirStream = df[_tarballFromResolved]() + dirStream.on('error', rej) + dirStream.on('end', res) + dirStream.pipe(stream) + }))).catch( + /* istanbul ignore next: very unlikely and hard to test */ + er => stream.emit('error', er) + ) + return stream + } + + // clone a git repo into a temp folder (or fetch and unpack if possible) + // handler accepts a directory, and returns a promise that resolves + // when we're done with it, at which point, cacache deletes it + // + // TODO: after cloning, create a tarball of the folder, and add to the cache + // with cacache.put.stream(), using a key that's deterministic based on the + // spec and repo, so that we don't ever clone the same thing multiple times. + [_clone] (handler, tarballOk = true) { + const o = { tmpPrefix: 'git-clone' } + const ref = this.resolvedSha || this.spec.gitCommittish + const h = this.spec.hosted + const resolved = this.resolved + + // can be set manually to false to fall back to actual git clone + tarballOk = tarballOk && + h && resolved === repoUrl(h, { noCommittish: false }) && h.tarball + + return cacache.tmp.withTmp(this.cache, o, async tmp => { + // if we're resolved, and have a tarball url, shell out to RemoteFetcher + if (tarballOk) { + const nameat = this.spec.name ? `${this.spec.name}@` : '' + return new RemoteFetcher(h.tarball({ noCommittish: false }), { + ...this.opts, + allowGitIgnore: true, + pkgid: `git:${nameat}${this.resolved}`, + resolved: this.resolved, + integrity: null, // it'll always be different, if we have one + }).extract(tmp).then(() => handler(tmp), er => { + // fall back to ssh download if tarball fails + if (er.constructor.name.match(/^Http/)) { + return this[_clone](handler, false) + } else { + throw er + } + }) + } + + const sha = await ( + h ? this[_cloneHosted](ref, tmp) + : this[_cloneRepo](this.spec.fetchSpec, ref, tmp) + ) + this.resolvedSha = sha + if (!this.resolved) { + await this[_addGitSha](sha) + } + return handler(tmp) + }) + } + + // first try https, since that's faster and passphrase-less for + // public repos, and supports private repos when auth is provided. + // Fall back to SSH to support private repos + // NB: we always store the https url in resolved field if auth + // is present, otherwise ssh if the hosted type provides it + [_cloneHosted] (ref, tmp) { + const hosted = this.spec.hosted + return this[_cloneRepo](hosted.https({ noCommittish: true }), ref, tmp) + .catch(er => { + // Throw early since we know pathspec errors will fail again if retried + if (er instanceof git.errors.GitPathspecError) { + throw er + } + const ssh = hosted.sshurl && hosted.sshurl({ noCommittish: true }) + // no fallthrough if we can't fall through or have https auth + if (!ssh || hosted.auth) { + throw er + } + return this[_cloneRepo](ssh, ref, tmp) + }) + } + + [_cloneRepo] (repo, ref, tmp) { + const { opts, spec } = this + return git.clone(repo, ref, tmp, { ...opts, spec }) + } + + manifest () { + if (this.package) { + return Promise.resolve(this.package) + } + + return this.spec.hosted && this.resolved + ? FileFetcher.prototype.manifest.apply(this) + : this[_clone](dir => + this[_readPackageJson](dir + '/package.json') + .then(mani => this.package = { + ...mani, + _resolved: this.resolved, + _from: this.from, + })) + } + + packument () { + return FileFetcher.prototype.packument.apply(this) + } +} +module.exports = GitFetcher diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/index.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/index.js new file mode 100644 index 0000000000000..cbcbd7c92d15f --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/index.js @@ -0,0 +1,23 @@ +const { get } = require('./fetcher.js') +const GitFetcher = require('./git.js') +const RegistryFetcher = require('./registry.js') +const FileFetcher = require('./file.js') +const DirFetcher = require('./dir.js') +const RemoteFetcher = require('./remote.js') + +module.exports = { + GitFetcher, + RegistryFetcher, + FileFetcher, + DirFetcher, + RemoteFetcher, + resolve: (spec, opts) => get(spec, opts).resolve(), + extract: (spec, dest, opts) => get(spec, opts).extract(dest), + manifest: (spec, opts) => get(spec, opts).manifest(), + tarball: (spec, opts) => get(spec, opts).tarball(), + packument: (spec, opts) => get(spec, opts).packument(), +} +module.exports.tarball.stream = (spec, handler, opts) => + get(spec, opts).tarballStream(handler) +module.exports.tarball.file = (spec, dest, opts) => + get(spec, opts).tarballFile(dest) diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/registry.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/registry.js new file mode 100644 index 0000000000000..de25a11af4667 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/registry.js @@ -0,0 +1,369 @@ +const Fetcher = require('./fetcher.js') +const RemoteFetcher = require('./remote.js') +const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +const pacoteVersion = require('../package.json').version +const removeTrailingSlashes = require('./util/trailing-slashes.js') +const rpj = require('read-package-json-fast') +const pickManifest = require('npm-pick-manifest') +const ssri = require('ssri') +const crypto = require('crypto') +const npa = require('npm-package-arg') +const sigstore = require('sigstore') + +// Corgis are cute. 🐕🐶 +const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' +const fullDoc = 'application/json' + +// Some really old packages have no time field in their packument so we need a +// cutoff date. +const MISSING_TIME_CUTOFF = '2015-01-01T00:00:00.000Z' + +const fetch = require('npm-registry-fetch') + +const _headers = Symbol('_headers') +class RegistryFetcher extends Fetcher { + constructor (spec, opts) { + super(spec, opts) + + // you usually don't want to fetch the same packument multiple times in + // the span of a given script or command, no matter how many pacote calls + // are made, so this lets us avoid doing that. It's only relevant for + // registry fetchers, because other types simulate their packument from + // the manifest, which they memoize on this.package, so it's very cheap + // already. + this.packumentCache = this.opts.packumentCache || null + + this.registry = fetch.pickRegistry(spec, opts) + this.packumentUrl = removeTrailingSlashes(this.registry) + '/' + + this.spec.escapedName + + const parsed = new URL(this.registry) + const regKey = `//${parsed.host}${parsed.pathname}` + // unlike the nerf-darted auth keys, this one does *not* allow a mismatch + // of trailing slashes. It must match exactly. + if (this.opts[`${regKey}:_keys`]) { + this.registryKeys = this.opts[`${regKey}:_keys`] + } + + // XXX pacote <=9 has some logic to ignore opts.resolved if + // the resolved URL doesn't go to the same registry. + // Consider reproducing that here, to throw away this.resolved + // in that case. + } + + async resolve () { + // fetching the manifest sets resolved and (if present) integrity + await this.manifest() + if (!this.resolved) { + throw Object.assign( + new Error('Invalid package manifest: no `dist.tarball` field'), + { package: this.spec.toString() } + ) + } + return this.resolved + } + + [_headers] () { + return { + // npm will override UA, but ensure that we always send *something* + 'user-agent': this.opts.userAgent || + `pacote/${pacoteVersion} node/${process.version}`, + ...(this.opts.headers || {}), + 'pacote-version': pacoteVersion, + 'pacote-req-type': 'packument', + 'pacote-pkg-id': `registry:${this.spec.name}`, + accept: this.fullMetadata ? fullDoc : corgiDoc, + } + } + + async packument () { + // note this might be either an in-flight promise for a request, + // or the actual packument, but we never want to make more than + // one request at a time for the same thing regardless. + if (this.packumentCache && this.packumentCache.has(this.packumentUrl)) { + return this.packumentCache.get(this.packumentUrl) + } + + // npm-registry-fetch the packument + // set the appropriate header for corgis if fullMetadata isn't set + // return the res.json() promise + try { + const res = await fetch(this.packumentUrl, { + ...this.opts, + headers: this[_headers](), + spec: this.spec, + // never check integrity for packuments themselves + integrity: null, + }) + const packument = await res.json() + packument._contentLength = +res.headers.get('content-length') + if (this.packumentCache) { + this.packumentCache.set(this.packumentUrl, packument) + } + return packument + } catch (err) { + if (this.packumentCache) { + this.packumentCache.delete(this.packumentUrl) + } + if (err.code !== 'E404' || this.fullMetadata) { + throw err + } + // possible that corgis are not supported by this registry + this.fullMetadata = true + return this.packument() + } + } + + async manifest () { + if (this.package) { + return this.package + } + + // When verifying signatures, we need to fetch the full/uncompressed + // packument to get publish time as this is not included in the + // corgi/compressed packument. + if (this.opts.verifySignatures) { + this.fullMetadata = true + } + + const packument = await this.packument() + let mani = await pickManifest(packument, this.spec.fetchSpec, { + ...this.opts, + defaultTag: this.defaultTag, + before: this.before, + }) + mani = rpj.normalize(mani) + /* XXX add ETARGET and E403 revalidation of cached packuments here */ + + // add _time from packument if fetched with fullMetadata + const time = packument.time?.[mani.version] + if (time) { + mani._time = time + } + + // add _resolved and _integrity from dist object + const { dist } = mani + if (dist) { + this.resolved = mani._resolved = dist.tarball + mani._from = this.from + const distIntegrity = dist.integrity ? ssri.parse(dist.integrity) + : dist.shasum ? ssri.fromHex(dist.shasum, 'sha1', { ...this.opts }) + : null + if (distIntegrity) { + if (this.integrity && !this.integrity.match(distIntegrity)) { + // only bork if they have algos in common. + // otherwise we end up breaking if we have saved a sha512 + // previously for the tarball, but the manifest only + // provides a sha1, which is possible for older publishes. + // Otherwise, this is almost certainly a case of holding it + // wrong, and will result in weird or insecure behavior + // later on when building package tree. + for (const algo of Object.keys(this.integrity)) { + if (distIntegrity[algo]) { + throw Object.assign(new Error( + `Integrity checksum failed when using ${algo}: ` + + `wanted ${this.integrity} but got ${distIntegrity}.` + ), { code: 'EINTEGRITY' }) + } + } + } + // made it this far, the integrity is worthwhile. accept it. + // the setter here will take care of merging it into what we already + // had. + this.integrity = distIntegrity + } + } + if (this.integrity) { + mani._integrity = String(this.integrity) + if (dist.signatures) { + if (this.opts.verifySignatures) { + // validate and throw on error, then set _signatures + const message = `${mani._id}:${mani._integrity}` + for (const signature of dist.signatures) { + const publicKey = this.registryKeys && + this.registryKeys.filter(key => (key.keyid === signature.keyid))[0] + if (!publicKey) { + throw Object.assign(new Error( + `${mani._id} has a registry signature with keyid: ${signature.keyid} ` + + 'but no corresponding public key can be found' + ), { code: 'EMISSINGSIGNATUREKEY' }) + } + + const publishedTime = Date.parse(mani._time || MISSING_TIME_CUTOFF) + const validPublicKey = !publicKey.expires || + publishedTime < Date.parse(publicKey.expires) + if (!validPublicKey) { + throw Object.assign(new Error( + `${mani._id} has a registry signature with keyid: ${signature.keyid} ` + + `but the corresponding public key has expired ${publicKey.expires}` + ), { code: 'EEXPIREDSIGNATUREKEY' }) + } + const verifier = crypto.createVerify('SHA256') + verifier.write(message) + verifier.end() + const valid = verifier.verify( + publicKey.pemkey, + signature.sig, + 'base64' + ) + if (!valid) { + throw Object.assign(new Error( + `${mani._id} has an invalid registry signature with ` + + `keyid: ${publicKey.keyid} and signature: ${signature.sig}` + ), { + code: 'EINTEGRITYSIGNATURE', + keyid: publicKey.keyid, + signature: signature.sig, + resolved: mani._resolved, + integrity: mani._integrity, + }) + } + } + mani._signatures = dist.signatures + } else { + mani._signatures = dist.signatures + } + } + + if (dist.attestations) { + if (this.opts.verifyAttestations) { + // Always fetch attestations from the current registry host + const attestationsPath = new URL(dist.attestations.url).pathname + const attestationsUrl = removeTrailingSlashes(this.registry) + attestationsPath + const res = await fetch(attestationsUrl, { + ...this.opts, + // disable integrity check for attestations json payload, we check the + // integrity in the verification steps below + integrity: null, + }) + const { attestations } = await res.json() + const bundles = attestations.map(({ predicateType, bundle }) => { + const statement = JSON.parse( + Buffer.from(bundle.dsseEnvelope.payload, 'base64').toString('utf8') + ) + const keyid = bundle.dsseEnvelope.signatures[0].keyid + const signature = bundle.dsseEnvelope.signatures[0].sig + + return { + predicateType, + bundle, + statement, + keyid, + signature, + } + }) + + const attestationKeyIds = bundles.map((b) => b.keyid).filter((k) => !!k) + const attestationRegistryKeys = (this.registryKeys || []) + .filter(key => attestationKeyIds.includes(key.keyid)) + if (!attestationRegistryKeys.length) { + throw Object.assign(new Error( + `${mani._id} has attestations but no corresponding public key(s) can be found` + ), { code: 'EMISSINGSIGNATUREKEY' }) + } + + for (const { predicateType, bundle, keyid, signature, statement } of bundles) { + const publicKey = attestationRegistryKeys.find(key => key.keyid === keyid) + // Publish attestations have a keyid set and a valid public key must be found + if (keyid) { + if (!publicKey) { + throw Object.assign(new Error( + `${mani._id} has attestations with keyid: ${keyid} ` + + 'but no corresponding public key can be found' + ), { code: 'EMISSINGSIGNATUREKEY' }) + } + + const integratedTime = new Date( + Number( + bundle.verificationMaterial.tlogEntries[0].integratedTime + ) * 1000 + ) + const validPublicKey = !publicKey.expires || + (integratedTime < Date.parse(publicKey.expires)) + if (!validPublicKey) { + throw Object.assign(new Error( + `${mani._id} has attestations with keyid: ${keyid} ` + + `but the corresponding public key has expired ${publicKey.expires}` + ), { code: 'EEXPIREDSIGNATUREKEY' }) + } + } + + const subject = { + name: statement.subject[0].name, + sha512: statement.subject[0].digest.sha512, + } + + // Only type 'version' can be turned into a PURL + const purl = this.spec.type === 'version' ? npa.toPurl(this.spec) : this.spec + // Verify the statement subject matches the package, version + if (subject.name !== purl) { + throw Object.assign(new Error( + `${mani._id} package name and version (PURL): ${purl} ` + + `doesn't match what was signed: ${subject.name}` + ), { code: 'EATTESTATIONSUBJECT' }) + } + + // Verify the statement subject matches the tarball integrity + const integrityHexDigest = ssri.parse(this.integrity).hexDigest() + if (subject.sha512 !== integrityHexDigest) { + throw Object.assign(new Error( + `${mani._id} package integrity (hex digest): ` + + `${integrityHexDigest} ` + + `doesn't match what was signed: ${subject.sha512}` + ), { code: 'EATTESTATIONSUBJECT' }) + } + + try { + // Provenance attestations are signed with a signing certificate + // (including the key) so we don't need to return a public key. + // + // Publish attestations are signed with a keyid so we need to + // specify a public key from the keys endpoint: `registry-host.tld/-/npm/v1/keys` + const options = { + tufCachePath: this.tufCache, + tufForceCache: true, + keySelector: publicKey ? () => publicKey.pemkey : undefined, + } + await sigstore.verify(bundle, options) + } catch (e) { + throw Object.assign(new Error( + `${mani._id} failed to verify attestation: ${e.message}` + ), { + code: 'EATTESTATIONVERIFY', + predicateType, + keyid, + signature, + resolved: mani._resolved, + integrity: mani._integrity, + }) + } + } + mani._attestations = dist.attestations + } else { + mani._attestations = dist.attestations + } + } + } + + this.package = mani + return this.package + } + + [_tarballFromResolved] () { + // we use a RemoteFetcher to get the actual tarball stream + return new RemoteFetcher(this.resolved, { + ...this.opts, + resolved: this.resolved, + pkgid: `registry:${this.spec.name}@${this.resolved}`, + })[_tarballFromResolved]() + } + + get types () { + return [ + 'tag', + 'version', + 'range', + ] + } +} +module.exports = RegistryFetcher diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/remote.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/remote.js new file mode 100644 index 0000000000000..fd617459fb031 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/remote.js @@ -0,0 +1,91 @@ +const Fetcher = require('./fetcher.js') +const FileFetcher = require('./file.js') +const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +const pacoteVersion = require('../package.json').version +const fetch = require('npm-registry-fetch') +const { Minipass } = require('minipass') + +const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches') +const _headers = Symbol('_headers') +class RemoteFetcher extends Fetcher { + constructor (spec, opts) { + super(spec, opts) + this.resolved = this.spec.fetchSpec + const resolvedURL = new URL(this.resolved) + if (this.replaceRegistryHost !== 'never' + && (this.replaceRegistryHost === 'always' + || this.replaceRegistryHost === resolvedURL.host)) { + this.resolved = new URL(resolvedURL.pathname, this.registry).href + } + + // nam is a fermented pork sausage that is good to eat + const nameat = this.spec.name ? `${this.spec.name}@` : '' + this.pkgid = opts.pkgid ? opts.pkgid : `remote:${nameat}${this.resolved}` + } + + // Don't need to cache tarball fetches in pacote, because make-fetch-happen + // will write into cacache anyway. + get [_cacheFetches] () { + return false + } + + [_tarballFromResolved] () { + const stream = new Minipass() + stream.hasIntegrityEmitter = true + + const fetchOpts = { + ...this.opts, + headers: this[_headers](), + spec: this.spec, + integrity: this.integrity, + algorithms: [this.pickIntegrityAlgorithm()], + } + + // eslint-disable-next-line promise/always-return + fetch(this.resolved, fetchOpts).then(res => { + res.body.on('error', + /* istanbul ignore next - exceedingly rare and hard to simulate */ + er => stream.emit('error', er) + ) + + res.body.on('integrity', i => { + this.integrity = i + stream.emit('integrity', i) + }) + + res.body.pipe(stream) + }).catch(er => stream.emit('error', er)) + + return stream + } + + [_headers] () { + return { + // npm will override this, but ensure that we always send *something* + 'user-agent': this.opts.userAgent || + `pacote/${pacoteVersion} node/${process.version}`, + ...(this.opts.headers || {}), + 'pacote-version': pacoteVersion, + 'pacote-req-type': 'tarball', + 'pacote-pkg-id': this.pkgid, + ...(this.integrity ? { 'pacote-integrity': String(this.integrity) } + : {}), + ...(this.opts.headers || {}), + } + } + + get types () { + return ['remote'] + } + + // getting a packument and/or manifest is the same as with a file: spec. + // unpack the tarball stream, and then read from the package.json file. + packument () { + return FileFetcher.prototype.packument.apply(this) + } + + manifest () { + return FileFetcher.prototype.manifest.apply(this) + } +} +module.exports = RemoteFetcher diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/add-git-sha.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/add-git-sha.js new file mode 100644 index 0000000000000..843fe5b600caf --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/add-git-sha.js @@ -0,0 +1,15 @@ +// add a sha to a git remote url spec +const addGitSha = (spec, sha) => { + if (spec.hosted) { + const h = spec.hosted + const opt = { noCommittish: true } + const base = h.https && h.auth ? h.https(opt) : h.shortcut(opt) + + return `${base}#${sha}` + } else { + // don't use new URL for this, because it doesn't handle scp urls + return spec.rawSpec.replace(/#.*$/, '') + `#${sha}` + } +} + +module.exports = addGitSha diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/cache-dir.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/cache-dir.js new file mode 100644 index 0000000000000..ac83b1793f199 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/cache-dir.js @@ -0,0 +1,15 @@ +const os = require('os') +const { resolve } = require('path') + +module.exports = (fakePlatform = false) => { + const temp = os.tmpdir() + const uidOrPid = process.getuid ? process.getuid() : process.pid + const home = os.homedir() || resolve(temp, 'npm-' + uidOrPid) + const platform = fakePlatform || process.platform + const cacheExtra = platform === 'win32' ? 'npm-cache' : '.npm' + const cacheRoot = (platform === 'win32' && process.env.LOCALAPPDATA) || home + return { + cacache: resolve(cacheRoot, cacheExtra, '_cacache'), + tufcache: resolve(cacheRoot, cacheExtra, '_tuf'), + } +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/is-package-bin.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/is-package-bin.js new file mode 100644 index 0000000000000..49a3f73f537ce --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/is-package-bin.js @@ -0,0 +1,25 @@ +// Function to determine whether a path is in the package.bin set. +// Used to prevent issues when people publish a package from a +// windows machine, and then install with --no-bin-links. +// +// Note: this is not possible in remote or file fetchers, since +// we don't have the manifest until AFTER we've unpacked. But the +// main use case is registry fetching with git a distant second, +// so that's an acceptable edge case to not handle. + +const binObj = (name, bin) => + typeof bin === 'string' ? { [name]: bin } : bin + +const hasBin = (pkg, path) => { + const bin = binObj(pkg.name, pkg.bin) + const p = path.replace(/^[^\\/]*\//, '') + for (const kv of Object.entries(bin)) { + if (kv[1] === p) { + return true + } + } + return false +} + +module.exports = (pkg, path) => + pkg && pkg.bin ? hasBin(pkg, path) : false diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/npm.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/npm.js new file mode 100644 index 0000000000000..a3005c255565f --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/npm.js @@ -0,0 +1,14 @@ +// run an npm command +const spawn = require('@npmcli/promise-spawn') + +module.exports = (npmBin, npmCommand, cwd, env, extra) => { + const isJS = npmBin.endsWith('.js') + const cmd = isJS ? process.execPath : npmBin + const args = (isJS ? [npmBin] : []).concat(npmCommand) + // when installing to run the `prepare` script for a git dep, we need + // to ensure that we don't run into a cycle of checking out packages + // in temp directories. this lets us link previously-seen repos that + // are also being prepared. + + return spawn(cmd, args, { cwd, env }, extra) +} diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/tar-create-options.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/tar-create-options.js new file mode 100644 index 0000000000000..d070f0f7ba2d4 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/tar-create-options.js @@ -0,0 +1,31 @@ +const isPackageBin = require('./is-package-bin.js') + +const tarCreateOptions = manifest => ({ + cwd: manifest._resolved, + prefix: 'package/', + portable: true, + gzip: { + // forcing the level to 9 seems to avoid some + // platform specific optimizations that cause + // integrity mismatch errors due to differing + // end results after compression + level: 9, + }, + + // ensure that package bins are always executable + // Note that npm-packlist is already filtering out + // anything that is not a regular file, ignored by + // .npmignore or package.json "files", etc. + filter: (path, stat) => { + if (isPackageBin(manifest, path)) { + stat.mode |= 0o111 + } + return true + }, + + // Provide a specific date in the 1980s for the benefit of zip, + // which is confounded by files dated at the Unix epoch 0. + mtime: new Date('1985-10-26T08:15:00.000Z'), +}) + +module.exports = tarCreateOptions diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/trailing-slashes.js b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/trailing-slashes.js new file mode 100644 index 0000000000000..c50cb6173b92e --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/lib/util/trailing-slashes.js @@ -0,0 +1,10 @@ +const removeTrailingSlashes = (input) => { + // in order to avoid regexp redos detection + let output = input + while (output.endsWith('/')) { + output = output.slice(0, -1) + } + return output +} + +module.exports = removeTrailingSlashes diff --git a/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/package.json b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/package.json new file mode 100644 index 0000000000000..e813975461224 --- /dev/null +++ b/node_modules/@npmcli/metavuln-calculator/node_modules/pacote/package.json @@ -0,0 +1,79 @@ +{ + "name": "pacote", + "version": "17.0.7", + "description": "JavaScript package downloader", + "author": "GitHub Inc.", + "bin": { + "pacote": "lib/bin.js" + }, + "license": "ISC", + "main": "lib/index.js", + "scripts": { + "test": "tap", + "snap": "tap", + "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "postlint": "template-oss-check", + "lintfix": "npm run lint -- --fix", + "posttest": "npm run lint", + "template-oss-apply": "template-oss-apply --force" + }, + "tap": { + "timeout": 300, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "devDependencies": { + "@npmcli/arborist": "^7.1.0", + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.21.3", + "hosted-git-info": "^7.0.0", + "mutate-fs": "^2.1.1", + "nock": "^13.2.4", + "npm-registry-mock": "^1.3.2", + "tap": "^16.0.1" + }, + "files": [ + "bin/", + "lib/" + ], + "keywords": [ + "packages", + "npm", + "git" + ], + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/npm/pacote.git" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.21.3", + "windowsCI": false, + "publish": "true" + } +} diff --git a/node_modules/pacote/lib/dir.js b/node_modules/pacote/lib/dir.js index 420afc5802cb2..6979462ea073e 100644 --- a/node_modules/pacote/lib/dir.js +++ b/node_modules/pacote/lib/dir.js @@ -41,16 +41,11 @@ class DirFetcher extends Fetcher { // but this function is *also* run when installing git deps const stdio = this.opts.foregroundScripts ? 'inherit' : 'pipe' - // hide the banner if silent opt is passed in, or if prepare running - // in the background. - const banner = this.opts.silent ? false : stdio === 'inherit' - return runScript({ pkg: mani, event: 'prepare', path: this.resolved, stdio, - banner, env: { npm_package_resolved: this.resolved, npm_package_integrity: this.integrity, diff --git a/node_modules/pacote/lib/fetcher.js b/node_modules/pacote/lib/fetcher.js index f961a45c7d346..287ec7956fc97 100644 --- a/node_modules/pacote/lib/fetcher.js +++ b/node_modules/pacote/lib/fetcher.js @@ -8,7 +8,7 @@ const ssri = require('ssri') const { promisify } = require('util') const { basename, dirname } = require('path') const tar = require('tar') -const log = require('proc-log') +const { log } = require('proc-log') const retry = require('promise-retry') const fs = require('fs/promises') const fsm = require('fs-minipass') diff --git a/node_modules/pacote/lib/git.js b/node_modules/pacote/lib/git.js index 5d24f72497ec9..533d83d3d8dd3 100644 --- a/node_modules/pacote/lib/git.js +++ b/node_modules/pacote/lib/git.js @@ -8,7 +8,7 @@ const pickManifest = require('npm-pick-manifest') const npa = require('npm-package-arg') const { Minipass } = require('minipass') const cacache = require('cacache') -const log = require('proc-log') +const { log } = require('proc-log') const npm = require('./util/npm.js') const _resolvedFromRepo = Symbol('_resolvedFromRepo') diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/LICENSE b/node_modules/pacote/node_modules/@npmcli/run-script/LICENSE new file mode 100644 index 0000000000000..19cec97b18468 --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) npm, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/is-server-package.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/is-server-package.js new file mode 100644 index 0000000000000..c36c40d4898d5 --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/is-server-package.js @@ -0,0 +1,11 @@ +const { stat } = require('node:fs/promises') +const { resolve } = require('node:path') + +module.exports = async path => { + try { + const st = await stat(resolve(path, 'server.js')) + return st.isFile() + } catch (er) { + return false + } +} diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/make-spawn-args.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/make-spawn-args.js new file mode 100644 index 0000000000000..8a32d7198cb2e --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/make-spawn-args.js @@ -0,0 +1,40 @@ +/* eslint camelcase: "off" */ +const setPATH = require('./set-path.js') +const { resolve } = require('path') +const npm_config_node_gyp = require.resolve('node-gyp/bin/node-gyp.js') + +const makeSpawnArgs = options => { + const { + event, + path, + scriptShell = true, + binPaths, + env, + stdio, + cmd, + args, + stdioString, + } = options + + const spawnEnv = setPATH(path, binPaths, { + // we need to at least save the PATH environment var + ...process.env, + ...env, + npm_package_json: resolve(path, 'package.json'), + npm_lifecycle_event: event, + npm_lifecycle_script: cmd, + npm_config_node_gyp, + }) + + const spawnOpts = { + env: spawnEnv, + stdioString, + stdio, + cwd: path, + shell: scriptShell, + } + + return [cmd, args, spawnOpts] +} + +module.exports = makeSpawnArgs diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp b/node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp new file mode 100755 index 0000000000000..5bec64d961a3a --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +node "$npm_config_node_gyp" "$@" diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd b/node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd new file mode 100755 index 0000000000000..4c6987ac9868b --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/node-gyp-bin/node-gyp.cmd @@ -0,0 +1 @@ +@node "%npm_config_node_gyp%" %* diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/package-envs.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/package-envs.js new file mode 100644 index 0000000000000..612f850fb076c --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/package-envs.js @@ -0,0 +1,29 @@ +const packageEnvs = (vals, prefix, env = {}) => { + for (const [key, val] of Object.entries(vals)) { + if (val === undefined) { + continue + } else if (val === null || val === false) { + env[`${prefix}${key}`] = '' + } else if (Array.isArray(val)) { + val.forEach((item, index) => { + packageEnvs({ [`${key}_${index}`]: item }, `${prefix}`, env) + }) + } else if (typeof val === 'object') { + packageEnvs(val, `${prefix}${key}_`, env) + } else { + env[`${prefix}${key}`] = String(val) + } + } + return env +} + +// https://github.com/npm/rfcs/pull/183 defines which fields we put into the environment +module.exports = pkg => { + return packageEnvs({ + name: pkg.name, + version: pkg.version, + config: pkg.config, + engines: pkg.engines, + bin: pkg.bin, + }, 'npm_package_') +} diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script-pkg.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script-pkg.js new file mode 100644 index 0000000000000..a4f27b500718c --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script-pkg.js @@ -0,0 +1,110 @@ +const makeSpawnArgs = require('./make-spawn-args.js') +const promiseSpawn = require('@npmcli/promise-spawn') +const packageEnvs = require('./package-envs.js') +const { isNodeGypPackage, defaultGypInstallScript } = require('@npmcli/node-gyp') +const signalManager = require('./signal-manager.js') +const isServerPackage = require('./is-server-package.js') + +const runScriptPkg = async options => { + const { + event, + path, + scriptShell, + binPaths = false, + env = {}, + stdio = 'pipe', + pkg, + args = [], + stdioString, + // how long to wait for a process.kill signal + // only exposed here so that we can make the test go a bit faster. + signalTimeout = 500, + } = options + + const { scripts = {}, gypfile } = pkg + let cmd = null + if (options.cmd) { + cmd = options.cmd + } else if (pkg.scripts && pkg.scripts[event]) { + cmd = pkg.scripts[event] + } else if ( + // If there is no preinstall or install script, default to rebuilding node-gyp packages. + event === 'install' && + !scripts.install && + !scripts.preinstall && + gypfile !== false && + await isNodeGypPackage(path) + ) { + cmd = defaultGypInstallScript + } else if (event === 'start' && await isServerPackage(path)) { + cmd = 'node server.js' + } + + if (!cmd) { + return { code: 0, signal: null } + } + + if (stdio === 'inherit') { + let banner + if (pkg._id) { + banner = `\n> ${pkg._id} ${event}\n` + } else { + banner = `\n> ${event}\n` + } + banner += `> ${cmd.trim().replace(/\n/g, '\n> ')}` + if (args.length) { + banner += ` ${args.join(' ')}` + } + banner += '\n' + const { output } = require('proc-log') + output.standard(banner) + } + + const [spawnShell, spawnArgs, spawnOpts] = makeSpawnArgs({ + event, + path, + scriptShell, + binPaths, + env: { ...env, ...packageEnvs(pkg) }, + stdio, + cmd, + args, + stdioString, + }) + + const p = promiseSpawn(spawnShell, spawnArgs, spawnOpts, { + event, + script: cmd, + pkgid: pkg._id, + path, + }) + + if (stdio === 'inherit') { + signalManager.add(p.process) + } + + if (p.stdin) { + p.stdin.end() + } + + return p.catch(er => { + const { signal } = er + // coverage disabled because win32 never emits signals + /* istanbul ignore next */ + if (stdio === 'inherit' && signal) { + // by the time we reach here, the child has already exited. we send the + // signal back to ourselves again so that npm will exit with the same + // status as the child + process.kill(process.pid, signal) + + // just in case we don't die, reject after 500ms + // this also keeps the node process open long enough to actually + // get the signal, rather than terminating gracefully. + return new Promise((res, rej) => setTimeout(() => rej(er), signalTimeout)) + } else { + throw er + } + }) +} + +module.exports = runScriptPkg diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script.js new file mode 100644 index 0000000000000..b00304c8d6e7f --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/run-script.js @@ -0,0 +1,15 @@ +const PackageJson = require('@npmcli/package-json') +const runScriptPkg = require('./run-script-pkg.js') +const validateOptions = require('./validate-options.js') +const isServerPackage = require('./is-server-package.js') + +const runScript = async options => { + validateOptions(options) + if (options.pkg) { + return runScriptPkg(options) + } + const { content: pkg } = await PackageJson.normalize(options.path) + return runScriptPkg({ ...options, pkg }) +} + +module.exports = Object.assign(runScript, { isServerPackage }) diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/set-path.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/set-path.js new file mode 100644 index 0000000000000..c59c270d9969a --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/set-path.js @@ -0,0 +1,45 @@ +const { resolve, dirname, delimiter } = require('path') +// the path here is relative, even though it does not need to be +// in order to make the posix tests pass in windows +const nodeGypPath = resolve(__dirname, '../lib/node-gyp-bin') + +// Windows typically calls its PATH environ 'Path', but this is not +// guaranteed, nor is it guaranteed to be the only one. Merge them +// all together in the order they appear in the object. +const setPATH = (projectPath, binPaths, env) => { + const PATH = Object.keys(env).filter(p => /^path$/i.test(p) && env[p]) + .map(p => env[p].split(delimiter)) + .reduce((set, p) => set.concat(p.filter(concatted => !set.includes(concatted))), []) + .join(delimiter) + + const pathArr = [] + if (binPaths) { + pathArr.push(...binPaths) + } + // unshift the ./node_modules/.bin from every folder + // walk up until dirname() does nothing, at the root + // XXX we should specify a cwd that we don't go above + let p = projectPath + let pp + do { + pathArr.push(resolve(p, 'node_modules', '.bin')) + pp = p + p = dirname(p) + } while (p !== pp) + pathArr.push(nodeGypPath, PATH) + + const pathVal = pathArr.join(delimiter) + + // XXX include the node-gyp-bin path somehow? Probably better for + // npm or arborist or whoever to just provide that by putting it in + // the PATH environ, since that's preserved anyway. + for (const key of Object.keys(env)) { + if (/^path$/i.test(key)) { + env[key] = pathVal + } + } + + return env +} + +module.exports = setPATH diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/signal-manager.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/signal-manager.js new file mode 100644 index 0000000000000..a099a4af2b9be --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/signal-manager.js @@ -0,0 +1,50 @@ +const runningProcs = new Set() +let handlersInstalled = false + +const forwardedSignals = [ + 'SIGINT', + 'SIGTERM', +] + +// no-op, this is so receiving the signal doesn't cause us to exit immediately +// instead, we exit after all children have exited when we re-send the signal +// to ourselves. see the catch handler at the bottom of run-script-pkg.js +const handleSignal = signal => { + for (const proc of runningProcs) { + proc.kill(signal) + } +} + +const setupListeners = () => { + for (const signal of forwardedSignals) { + process.on(signal, handleSignal) + } + handlersInstalled = true +} + +const cleanupListeners = () => { + if (runningProcs.size === 0) { + for (const signal of forwardedSignals) { + process.removeListener(signal, handleSignal) + } + handlersInstalled = false + } +} + +const add = proc => { + runningProcs.add(proc) + if (!handlersInstalled) { + setupListeners() + } + + proc.once('exit', () => { + runningProcs.delete(proc) + cleanupListeners() + }) +} + +module.exports = { + add, + handleSignal, + forwardedSignals, +} diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/lib/validate-options.js b/node_modules/pacote/node_modules/@npmcli/run-script/lib/validate-options.js new file mode 100644 index 0000000000000..8d855916ecd15 --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/lib/validate-options.js @@ -0,0 +1,39 @@ +const validateOptions = options => { + if (typeof options !== 'object' || !options) { + throw new TypeError('invalid options object provided to runScript') + } + + const { + event, + path, + scriptShell, + env = {}, + stdio = 'pipe', + args = [], + cmd, + } = options + + if (!event || typeof event !== 'string') { + throw new TypeError('valid event not provided to runScript') + } + if (!path || typeof path !== 'string') { + throw new TypeError('valid path not provided to runScript') + } + if (scriptShell !== undefined && typeof scriptShell !== 'string') { + throw new TypeError('invalid scriptShell option provided to runScript') + } + if (typeof env !== 'object' || !env) { + throw new TypeError('invalid env option provided to runScript') + } + if (typeof stdio !== 'string' && !Array.isArray(stdio)) { + throw new TypeError('invalid stdio option provided to runScript') + } + if (!Array.isArray(args) || args.some(a => typeof a !== 'string')) { + throw new TypeError('invalid args option provided to runScript') + } + if (cmd !== undefined && typeof cmd !== 'string') { + throw new TypeError('invalid cmd option provided to runScript') + } +} + +module.exports = validateOptions diff --git a/node_modules/pacote/node_modules/@npmcli/run-script/package.json b/node_modules/pacote/node_modules/@npmcli/run-script/package.json new file mode 100644 index 0000000000000..dc780ad3ecbec --- /dev/null +++ b/node_modules/pacote/node_modules/@npmcli/run-script/package.json @@ -0,0 +1,54 @@ +{ + "name": "@npmcli/run-script", + "version": "8.0.0", + "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)", + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "eslint": "eslint", + "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "lintfix": "npm run lint -- --fix", + "postlint": "template-oss-check", + "snap": "tap", + "posttest": "npm run lint", + "template-oss-apply": "template-oss-apply --force" + }, + "devDependencies": { + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.21.3", + "spawk": "^1.8.1", + "tap": "^16.0.1" + }, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", + "which": "^4.0.0" + }, + "files": [ + "bin/", + "lib/" + ], + "main": "lib/run-script.js", + "repository": { + "type": "git", + "url": "https://github.com/npm/run-script.git" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.21.3", + "publish": "true" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/pacote/node_modules/proc-log/LICENSE b/node_modules/pacote/node_modules/proc-log/LICENSE new file mode 100644 index 0000000000000..83837797202b7 --- /dev/null +++ b/node_modules/pacote/node_modules/proc-log/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) GitHub, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/pacote/node_modules/proc-log/lib/index.js b/node_modules/pacote/node_modules/proc-log/lib/index.js new file mode 100644 index 0000000000000..2a049e6bd16b2 --- /dev/null +++ b/node_modules/pacote/node_modules/proc-log/lib/index.js @@ -0,0 +1,62 @@ +module.exports = { + output: { + LEVELS: [ + 'standard', + 'error', + 'buffer', + ], + standard: function (...args) { + return process.emit('output', 'standard', ...args) + }, + error: function (...args) { + return process.emit('output', 'error', ...args) + }, + buffer: function (...args) { + return process.emit('output', 'buffer', ...args) + }, + }, + log: { + LEVELS: [ + 'notice', + 'error', + 'warn', + 'info', + 'verbose', + 'http', + 'silly', + 'timing', + 'pause', + 'resume', + ], + error: function (...args) { + return process.emit('log', 'error', ...args) + }, + notice: function (...args) { + return process.emit('log', 'notice', ...args) + }, + warn: function (...args) { + return process.emit('log', 'warn', ...args) + }, + info: function (...args) { + return process.emit('log', 'info', ...args) + }, + verbose: function (...args) { + return process.emit('log', 'verbose', ...args) + }, + http: function (...args) { + return process.emit('log', 'http', ...args) + }, + silly: function (...args) { + return process.emit('log', 'silly', ...args) + }, + timing: function (...args) { + return process.emit('log', 'timing', ...args) + }, + pause: function (...args) { + return process.emit('log', 'pause', ...args) + }, + resume: function (...args) { + return process.emit('log', 'resume', ...args) + }, + }, +} diff --git a/node_modules/pacote/node_modules/proc-log/package.json b/node_modules/pacote/node_modules/proc-log/package.json new file mode 100644 index 0000000000000..405e3c433acbb --- /dev/null +++ b/node_modules/pacote/node_modules/proc-log/package.json @@ -0,0 +1,45 @@ +{ + "name": "proc-log", + "version": "4.0.0", + "files": [ + "bin/", + "lib/" + ], + "main": "lib/index.js", + "description": "just emit 'log' events on the process object", + "repository": { + "type": "git", + "url": "https://github.com/npm/proc-log.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "snap": "tap", + "posttest": "npm run lint", + "postsnap": "eslint index.js test/*.js --fix", + "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "postlint": "template-oss-check", + "lintfix": "npm run lint -- --fix", + "template-oss-apply": "template-oss-apply --force" + }, + "devDependencies": { + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.21.3", + "tap": "^16.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.21.3", + "publish": true + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 8fc0bb707f1e5..9fc3f2cfee960 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "17.0.6", + "version": "18.0.0", "description": "JavaScript package downloader", "author": "GitHub Inc.", "bin": { @@ -27,7 +27,7 @@ "devDependencies": { "@npmcli/arborist": "^7.1.0", "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.21.3", + "@npmcli/template-oss": "4.21.4", "hosted-git-info": "^7.0.0", "mutate-fs": "^2.1.1", "nock": "^13.2.4", @@ -47,7 +47,7 @@ "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", + "@npmcli/run-script": "^8.0.0", "cacache": "^18.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", @@ -55,7 +55,7 @@ "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", @@ -72,7 +72,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.21.3", + "version": "4.21.4", "windowsCI": false, "publish": "true" } diff --git a/package-lock.json b/package-lock.json index 0bbf010b3d9f3..482939a320ed8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -143,7 +143,7 @@ "npm-registry-fetch": "^16.2.1", "npm-user-validate": "^2.0.0", "p-map": "^4.0.0", - "pacote": "^17.0.6", + "pacote": "^18.0.0", "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "proggy": "^2.0.0", @@ -239,7 +239,7 @@ "json-stringify-safe": "^5.0.1", "nock": "^13.3.3", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "tap": "^16.3.8" }, "engines": { @@ -1773,6 +1773,52 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/pacote": { + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.7.tgz", + "integrity": "sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ==", + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/@npmcli/mock-globals": { "resolved": "mock-globals", "link": true @@ -10705,15 +10751,15 @@ } }, "node_modules/pacote": { - "version": "17.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", - "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.0.tgz", + "integrity": "sha512-ma7uVt/q3Sb3XbLwUjOeClz+7feHjMOFegHn5whw++x+GzikZkAq/2auklSbRuy6EI2iJh1/ZqCpVaUcxRaeqQ==", "inBundle": true, "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", + "@npmcli/run-script": "^8.0.0", "cacache": "^18.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", @@ -10721,7 +10767,7 @@ "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", @@ -10736,6 +10782,32 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/pacote/node_modules/@npmcli/run-script": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.0.0.tgz", + "integrity": "sha512-5noc+eCQmX1W9nlFUe65n5MIteikd3vOA2sEPdXtlUv68KWyHNFZnT/LDRXu/E4nZ5yxjciP30pADr/GQ97W1w==", + "inBundle": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/pacote/node_modules/proc-log": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.0.0.tgz", + "integrity": "sha512-v1lzmYxGDs2+OZnmYtYZK3DG8zogt+CbQ+o/iqqtTfpyCmGWulCTEQu5GIbivf7OjgIkH2Nr8SH8UxAGugZNbg==", + "inBundle": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -16197,7 +16269,7 @@ "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^16.2.1", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "parse-conflict-json": "^3.0.0", "proc-log": "^3.0.0", "proggy": "^2.0.0", @@ -16279,7 +16351,7 @@ "diff": "^5.1.0", "minimatch": "^9.0.4", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "tar": "^6.2.1" }, "devDependencies": { @@ -16299,7 +16371,7 @@ "@npmcli/run-script": "^7.0.2", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "proc-log": "^3.0.0", "read": "^3.0.1", "read-package-json-fast": "^3.0.2", @@ -16377,7 +16449,7 @@ "@npmcli/arborist": "^7.2.1", "@npmcli/run-script": "^7.0.2", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4" + "pacote": "^18.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", diff --git a/package.json b/package.json index a2ae7ea57835a..3939bf6a3cbbe 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "npm-registry-fetch": "^16.2.1", "npm-user-validate": "^2.0.0", "p-map": "^4.0.0", - "pacote": "^17.0.6", + "pacote": "^18.0.0", "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "proggy": "^2.0.0", diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 909c7333a51f6..d81c8774cddf5 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -26,7 +26,7 @@ "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^16.2.1", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "parse-conflict-json": "^3.0.0", "proc-log": "^3.0.0", "proggy": "^2.0.0", diff --git a/workspaces/config/lib/definitions/definitions.js b/workspaces/config/lib/definitions/definitions.js index 3565cdb4feb44..03b3099c4c391 100644 --- a/workspaces/config/lib/definitions/definitions.js +++ b/workspaces/config/lib/definitions/definitions.js @@ -1861,7 +1861,7 @@ const definitions = { }, }), 'script-shell': new Definition('script-shell', { - default: null, + default: shell, defaultDescription: ` '/bin/sh' on POSIX systems, 'cmd.exe' on Windows `, diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 492f709d440f7..fc4aac936b494 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -53,7 +53,7 @@ "diff": "^5.1.0", "minimatch": "^9.0.4", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "tar": "^6.2.1" }, "templateOSS": { diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index f3311677bbc53..e6c43c893897e 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -63,7 +63,7 @@ "@npmcli/run-script": "^7.0.2", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4", + "pacote": "^18.0.0", "proc-log": "^3.0.0", "read": "^3.0.1", "read-package-json-fast": "^3.0.2", diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 4703f7c7befc2..aa0d821d22e79 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -39,7 +39,7 @@ "@npmcli/arborist": "^7.2.1", "@npmcli/run-script": "^7.0.2", "npm-package-arg": "^11.0.2", - "pacote": "^17.0.4" + "pacote": "^18.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0"