libnpmexec
Advanced tools
| const { collectUnreviewedScripts, strictAllowScriptsError } = require('@npmcli/arborist/lib/unreviewed-scripts.js') | ||
| // Strict-mode pre-flight for `npm exec` / `npx`. When | ||
| // `--strict-allow-scripts` is set, build the npx-cache ideal tree and | ||
| // throw before reify if any node has install scripts not covered by | ||
| // the resolved `allowScripts` policy. The arborist gate already | ||
| // silently skips those scripts; this turns the silent skip into a | ||
| // hard failure for CI. Bypassed by `--ignore-scripts` and | ||
| // `--dangerously-allow-all-scripts`. | ||
| const strictAllowScriptsPreflight = async (arb, opts) => { | ||
| if (!opts.strictAllowScripts) { | ||
| return | ||
| } | ||
| if (opts.ignoreScripts || opts.dangerouslyAllowAllScripts) { | ||
| return | ||
| } | ||
| if (!arb.idealTree) { | ||
| await arb.buildIdealTree(opts) | ||
| } | ||
| const unreviewed = await collectUnreviewedScripts({ | ||
| tree: arb.idealTree, | ||
| policy: opts.allowScripts || null, | ||
| ignoreScripts: opts.ignoreScripts, | ||
| dangerouslyAllowAllScripts: opts.dangerouslyAllowAllScripts, | ||
| }) | ||
| if (unreviewed.length === 0) { | ||
| return | ||
| } | ||
| throw strictAllowScriptsError(unreviewed, { | ||
| remediation: | ||
| 'Pass --allow-scripts=<pkg> for one-off approval, or bypass this ' + | ||
| 'check with --dangerously-allow-all-scripts.', | ||
| }) | ||
| } | ||
| module.exports = strictAllowScriptsPreflight |
+14
-5
@@ -7,2 +7,3 @@ 'use strict' | ||
| const Arborist = require('@npmcli/arborist') | ||
| const strictAllowScriptsPreflight = require('./strict-allow-scripts-preflight.js') | ||
| const ciInfo = require('ci-info') | ||
@@ -90,2 +91,5 @@ const { log, input } = require('proc-log') | ||
| // Strict-mode pre-flight for `npm exec` / `npx` lives in | ||
| // ./strict-allow-scripts-preflight.js | ||
| // see if the package.json at `path` has an entry that matches `cmd` | ||
@@ -306,7 +310,12 @@ // the path is a known-local directory, not a user-supplied dep, so | ||
| } | ||
| await withLock(lockPath, () => npxArb.reify({ | ||
| ...flatOptions, | ||
| save: true, | ||
| add, | ||
| })) | ||
| await withLock(lockPath, async () => { | ||
| // Hard-fail before reify if --strict-allow-scripts is set and | ||
| // any node has install scripts not covered by allowScripts. | ||
| await strictAllowScriptsPreflight(npxArb, { ...flatOptions, add }) | ||
| await npxArb.reify({ | ||
| ...flatOptions, | ||
| save: true, | ||
| add, | ||
| }) | ||
| }) | ||
| } | ||
@@ -313,0 +322,0 @@ binPaths.push(resolve(installDir, 'node_modules/.bin')) |
@@ -22,3 +22,5 @@ const ciInfo = require('ci-info') | ||
| if (args.length > 0) { | ||
| args[0] = '"' + args[0] + '"' | ||
| // single-quote so shell metacharacters in the executable name are taken | ||
| // literally; double quotes still expand $(), backticks, $var and " | ||
| args[0] = `'${args[0].replace(/'/g, `'\\''`)}'` | ||
| } | ||
@@ -25,0 +27,0 @@ } |
+2
-2
| { | ||
| "name": "libnpmexec", | ||
| "version": "10.2.9", | ||
| "version": "10.3.0", | ||
| "files": [ | ||
@@ -64,3 +64,3 @@ "bin/", | ||
| "@gar/promise-retry": "^1.0.0", | ||
| "@npmcli/arborist": "^9.7.0", | ||
| "@npmcli/arborist": "^9.8.0", | ||
| "@npmcli/package-json": "^7.0.0", | ||
@@ -67,0 +67,0 @@ "@npmcli/run-script": "^10.0.0", |
26491
7.81%11
10%614
7.72%Updated