libnpmexec 10.2.8 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +19 -6
- package/lib/run-script.js +3 -1
- package/lib/strict-allow-scripts-preflight.js +40 -0
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const { dirname, join, resolve } = require('node:path')
|
|
|
4
4
|
const crypto = require('node:crypto')
|
|
5
5
|
const { mkdir } = require('node:fs/promises')
|
|
6
6
|
const Arborist = require('@npmcli/arborist')
|
|
7
|
+
const strictAllowScriptsPreflight = require('./strict-allow-scripts-preflight.js')
|
|
7
8
|
const ciInfo = require('ci-info')
|
|
8
9
|
const { log, input } = require('proc-log')
|
|
9
10
|
const npa = require('npm-package-arg')
|
|
@@ -86,9 +87,14 @@ const missingFromTree = async ({ spec, tree, flatOptions, isNpxTree, shallow })
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
// Strict-mode pre-flight for `npm exec` / `npx` lives in
|
|
91
|
+
// ./strict-allow-scripts-preflight.js
|
|
92
|
+
|
|
89
93
|
// see if the package.json at `path` has an entry that matches `cmd`
|
|
94
|
+
// the path is a known-local directory, not a user-supplied dep, so
|
|
95
|
+
// allow-directory must not gate this introspection
|
|
90
96
|
const hasPkgBin = (path, cmd, flatOptions) =>
|
|
91
|
-
pacote.manifest(path, flatOptions)
|
|
97
|
+
pacote.manifest(path, { ...flatOptions, allowDirectory: 'all' })
|
|
92
98
|
.then(manifest => manifest?.bin?.[cmd]).catch(() => null)
|
|
93
99
|
|
|
94
100
|
const exec = async (opts) => {
|
|
@@ -147,6 +153,8 @@ const exec = async (opts) => {
|
|
|
147
153
|
// we have to install the local package into the npx cache so that its
|
|
148
154
|
// bin links get set up
|
|
149
155
|
flatOptions.installLinks = false
|
|
156
|
+
// self-execution of a local bin, not a directory dep install
|
|
157
|
+
flatOptions.allowDirectory = 'all'
|
|
150
158
|
// args[0] will exist when the package is installed
|
|
151
159
|
packages.push(p)
|
|
152
160
|
yes = true
|
|
@@ -297,11 +305,16 @@ const exec = async (opts) => {
|
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
307
|
}
|
|
300
|
-
await withLock(lockPath, () =>
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
add
|
|
304
|
-
|
|
308
|
+
await withLock(lockPath, async () => {
|
|
309
|
+
// Hard-fail before reify if --strict-allow-scripts is set and
|
|
310
|
+
// any node has install scripts not covered by allowScripts.
|
|
311
|
+
await strictAllowScriptsPreflight(npxArb, { ...flatOptions, add })
|
|
312
|
+
await npxArb.reify({
|
|
313
|
+
...flatOptions,
|
|
314
|
+
save: true,
|
|
315
|
+
add,
|
|
316
|
+
})
|
|
317
|
+
})
|
|
305
318
|
}
|
|
306
319
|
binPaths.push(resolve(installDir, 'node_modules/.bin'))
|
|
307
320
|
const pkgJson = await PackageJson.load(installDir)
|
package/lib/run-script.js
CHANGED
|
@@ -19,7 +19,9 @@ const run = async ({
|
|
|
19
19
|
// necessary for preventing bash/cmd keywords from overriding
|
|
20
20
|
if (!isWindowsShell) {
|
|
21
21
|
if (args.length > 0) {
|
|
22
|
-
|
|
22
|
+
// single-quote so shell metacharacters in the executable name are taken
|
|
23
|
+
// literally; double quotes still expand $(), backticks, $var and "
|
|
24
|
+
args[0] = `'${args[0].replace(/'/g, `'\\''`)}'`
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const { collectUnreviewedScripts, strictAllowScriptsError } = require('@npmcli/arborist/lib/unreviewed-scripts.js')
|
|
2
|
+
|
|
3
|
+
// Strict-mode pre-flight for `npm exec` / `npx`. When
|
|
4
|
+
// `--strict-allow-scripts` is set, build the npx-cache ideal tree and
|
|
5
|
+
// throw before reify if any node has install scripts not covered by
|
|
6
|
+
// the resolved `allowScripts` policy. The arborist gate already
|
|
7
|
+
// silently skips those scripts; this turns the silent skip into a
|
|
8
|
+
// hard failure for CI. Bypassed by `--ignore-scripts` and
|
|
9
|
+
// `--dangerously-allow-all-scripts`.
|
|
10
|
+
const strictAllowScriptsPreflight = async (arb, opts) => {
|
|
11
|
+
if (!opts.strictAllowScripts) {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
if (opts.ignoreScripts || opts.dangerouslyAllowAllScripts) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!arb.idealTree) {
|
|
19
|
+
await arb.buildIdealTree(opts)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const unreviewed = await collectUnreviewedScripts({
|
|
23
|
+
tree: arb.idealTree,
|
|
24
|
+
policy: opts.allowScripts || null,
|
|
25
|
+
ignoreScripts: opts.ignoreScripts,
|
|
26
|
+
dangerouslyAllowAllScripts: opts.dangerouslyAllowAllScripts,
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
if (unreviewed.length === 0) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw strictAllowScriptsError(unreviewed, {
|
|
34
|
+
remediation:
|
|
35
|
+
'Pass --allow-scripts=<pkg> for one-off approval, or bypass this ' +
|
|
36
|
+
'check with --dangerously-allow-all-scripts.',
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = strictAllowScriptsPreflight
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libnpmexec",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.3.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"bin/",
|
|
6
6
|
"lib/"
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@gar/promise-retry": "^1.0.0",
|
|
64
|
-
"@npmcli/arborist": "^9.
|
|
64
|
+
"@npmcli/arborist": "^9.8.0",
|
|
65
65
|
"@npmcli/package-json": "^7.0.0",
|
|
66
66
|
"@npmcli/run-script": "^10.0.0",
|
|
67
67
|
"ci-info": "^4.0.0",
|