Skip to content

Commit 9dd219b

Browse files
fix: respect allowScripts policy in prune, dedupe, uninstall, audit, and link (#9462)
Backport of #9456 to `release/v11`. Co-authored-by: Jamie Magee <jamie.magee@gmail.com>
1 parent cd8d18a commit 9dd219b

10 files changed

Lines changed: 156 additions & 0 deletions

File tree

lib/commands/audit.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const ArboristWorkspaceCmd = require('../arborist-cmd.js')
33
const auditError = require('../utils/audit-error.js')
44
const { log, output } = require('proc-log')
55
const reifyFinish = require('../utils/reify-finish.js')
6+
const resolveAllowScripts = require('../utils/resolve-allow-scripts.js')
67
const VerifySignatures = require('../utils/verify-signatures.js')
78

89
class Audit extends ArboristWorkspaceCmd {
@@ -58,12 +59,14 @@ class Audit extends ArboristWorkspaceCmd {
5859
}
5960
const reporter = this.npm.config.get('json') ? 'json' : 'detail'
6061
const Arborist = require('@npmcli/arborist')
62+
const { policy: allowScriptsPolicy } = await resolveAllowScripts(this.npm)
6163
const opts = {
6264
...this.npm.flatOptions,
6365
audit: true,
6466
path: this.npm.prefix,
6567
reporter,
6668
workspaces: this.workspaceNames,
69+
allowScripts: allowScriptsPolicy,
6770
}
6871

6972
const arb = new Arborist(opts)

lib/commands/dedupe.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const reifyFinish = require('../utils/reify-finish.js')
2+
const resolveAllowScripts = require('../utils/resolve-allow-scripts.js')
23
const ArboristWorkspaceCmd = require('../arborist-cmd.js')
34

45
// dedupe duplicated packages, or find them in the tree
@@ -35,6 +36,7 @@ class Dedupe extends ArboristWorkspaceCmd {
3536
const dryRun = this.npm.config.get('dry-run')
3637
const where = this.npm.prefix
3738
const Arborist = require('@npmcli/arborist')
39+
const { policy: allowScriptsPolicy } = await resolveAllowScripts(this.npm)
3840
const opts = {
3941
...this.npm.flatOptions,
4042
path: where,
@@ -44,6 +46,7 @@ class Dedupe extends ArboristWorkspaceCmd {
4446
// In order to reduce potential confusion we set this to false.
4547
save: false,
4648
workspaces: this.workspaceNames,
49+
allowScripts: allowScriptsPolicy,
4750
}
4851
const arb = new Arborist(opts)
4952
await arb.dedupe(opts)

lib/commands/link.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const npa = require('npm-package-arg')
44
const pkgJson = require('@npmcli/package-json')
55
const semver = require('semver')
66
const reifyFinish = require('../utils/reify-finish.js')
7+
const resolveAllowScripts = require('../utils/resolve-allow-scripts.js')
78
const ArboristWorkspaceCmd = require('../arborist-cmd.js')
89

910
class Link extends ArboristWorkspaceCmd {
@@ -115,11 +116,13 @@ class Link extends ArboristWorkspaceCmd {
115116
)
116117
// create a new arborist instance for the local prefix and
117118
// reify all the pending names as symlinks there
119+
const { policy: allowScriptsPolicy } = await resolveAllowScripts(this.npm)
118120
const localArb = new Arborist({
119121
...this.npm.flatOptions,
120122
prune: false,
121123
path: this.npm.prefix,
122124
save,
125+
allowScripts: allowScriptsPolicy,
123126
})
124127
await localArb.reify({
125128
...this.npm.flatOptions,
@@ -128,6 +131,7 @@ class Link extends ArboristWorkspaceCmd {
128131
add: names.map(l => `file:${resolve(globalTop, 'node_modules', l)}`),
129132
save,
130133
workspaces: this.workspaceNames,
134+
allowScripts: allowScriptsPolicy,
131135
})
132136

133137
await reifyFinish(this.npm, localArb)

lib/commands/prune.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const reifyFinish = require('../utils/reify-finish.js')
2+
const resolveAllowScripts = require('../utils/resolve-allow-scripts.js')
23
const ArboristWorkspaceCmd = require('../arborist-cmd.js')
34

45
class Prune extends ArboristWorkspaceCmd {
@@ -19,10 +20,12 @@ class Prune extends ArboristWorkspaceCmd {
1920
async exec () {
2021
const where = this.npm.prefix
2122
const Arborist = require('@npmcli/arborist')
23+
const { policy: allowScriptsPolicy } = await resolveAllowScripts(this.npm)
2224
const opts = {
2325
...this.npm.flatOptions,
2426
path: where,
2527
workspaces: this.workspaceNames,
28+
allowScripts: allowScriptsPolicy,
2629
}
2730
const arb = new Arborist(opts)
2831
await arb.prune(opts)

lib/commands/uninstall.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { resolve } = require('node:path')
22
const pkgJson = require('@npmcli/package-json')
33
const reifyFinish = require('../utils/reify-finish.js')
4+
const resolveAllowScripts = require('../utils/resolve-allow-scripts.js')
45
const completion = require('../utils/installed-shallow.js')
56
const ArboristWorkspaceCmd = require('../arborist-cmd.js')
67

@@ -39,11 +40,13 @@ class Uninstall extends ArboristWorkspaceCmd {
3940
: this.npm.localPrefix
4041

4142
const Arborist = require('@npmcli/arborist')
43+
const { policy: allowScriptsPolicy } = await resolveAllowScripts(this.npm)
4244
const opts = {
4345
...this.npm.flatOptions,
4446
path,
4547
rm: args,
4648
workspaces: this.workspaceNames,
49+
allowScripts: allowScriptsPolicy,
4750
}
4851
const arb = new Arborist(opts)
4952
await arb.reify(opts)

test/lib/commands/audit.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2258,3 +2258,31 @@ t.test('audit signatures', async t => {
22582258
})
22592259
})
22602260
})
2261+
2262+
t.test('audit fix threads allowScripts policy through to arborist', async t => {
2263+
let capturedOpts
2264+
const FakeArborist = function (opts) {
2265+
capturedOpts = opts
2266+
this.options = opts
2267+
this.actualTree = { inventory: new Map() }
2268+
this.auditReport = {}
2269+
}
2270+
FakeArborist.prototype.audit = async () => {}
2271+
2272+
const { npm } = await loadMockNpm(t, {
2273+
prefixDir: {
2274+
'package.json': JSON.stringify({
2275+
name: 'host',
2276+
version: '1.0.0',
2277+
allowScripts: { canvas: true },
2278+
}),
2279+
},
2280+
mocks: {
2281+
'@npmcli/arborist': FakeArborist,
2282+
'{LIB}/utils/reify-finish.js': async () => {},
2283+
},
2284+
})
2285+
await npm.exec('audit', ['fix'])
2286+
t.strictSame(capturedOpts.allowScripts, { canvas: true },
2287+
'opts.allowScripts populated from package.json')
2288+
})

test/lib/commands/dedupe.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,30 @@ t.test('dedupe', async (t) => {
9494
fs.existsSync(path.join(npm.prefix, 'node_modules', 'test-dep-b', 'node_modules', 'test-sub')),
9595
'test-dep-b/test-sub was removed')
9696
})
97+
98+
t.test('dedupe threads allowScripts policy through to arborist', async t => {
99+
let capturedOpts
100+
const FakeArborist = function (opts) {
101+
capturedOpts = opts
102+
this.options = opts
103+
this.actualTree = { inventory: new Map() }
104+
}
105+
FakeArborist.prototype.dedupe = async () => {}
106+
107+
const { npm } = await loadMockNpm(t, {
108+
prefixDir: {
109+
'package.json': JSON.stringify({
110+
name: 'host',
111+
version: '1.0.0',
112+
allowScripts: { canvas: true },
113+
}),
114+
},
115+
mocks: {
116+
'@npmcli/arborist': FakeArborist,
117+
'{LIB}/utils/reify-finish.js': async () => {},
118+
},
119+
})
120+
await npm.exec('dedupe', [])
121+
t.strictSame(capturedOpts.allowScripts, { canvas: true },
122+
'opts.allowScripts populated from package.json')
123+
})

test/lib/commands/link.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,34 @@ t.test('test linked installed as symlinks', async t => {
523523

524524
t.matchSnapshot(await printLinks(), 'linked package should not be installed')
525525
})
526+
527+
t.test('link threads allowScripts policy through to arborist', async t => {
528+
const capturedOpts = []
529+
const FakeArborist = function (opts) {
530+
capturedOpts.push(opts)
531+
this.options = opts
532+
this.actualTree = { inventory: new Map() }
533+
}
534+
FakeArborist.prototype.loadActual = async () => ({ isLink: false, children: new Map() })
535+
FakeArborist.prototype.reify = async () => {}
536+
537+
const mock = await mockNpm(t, {
538+
command: 'link',
539+
prefixDir: {
540+
'package.json': JSON.stringify({
541+
name: 'host',
542+
version: '1.0.0',
543+
allowScripts: { canvas: true },
544+
}),
545+
},
546+
mocks: {
547+
'@npmcli/arborist': FakeArborist,
548+
'{LIB}/utils/reify-finish.js': async () => {},
549+
},
550+
})
551+
await mock.npm.exec('link', ['canvas'])
552+
// the local Arborist is the last one constructed in linkInstall
553+
const localOpts = capturedOpts[capturedOpts.length - 1]
554+
t.strictSame(localOpts.allowScripts, { canvas: true },
555+
'local arborist opts.allowScripts populated from package.json')
556+
})

test/lib/commands/prune.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,30 @@ t.test('should prune using Arborist', async (t) => {
1919
})
2020
await npm.exec('prune', [])
2121
})
22+
23+
t.test('prune threads allowScripts policy through to arborist', async t => {
24+
let capturedOpts
25+
const FakeArborist = function (opts) {
26+
capturedOpts = opts
27+
this.options = opts
28+
this.actualTree = { inventory: new Map() }
29+
}
30+
FakeArborist.prototype.prune = async () => {}
31+
32+
const { npm } = await loadMockNpm(t, {
33+
prefixDir: {
34+
'package.json': JSON.stringify({
35+
name: 'host',
36+
version: '1.0.0',
37+
allowScripts: { canvas: true },
38+
}),
39+
},
40+
mocks: {
41+
'@npmcli/arborist': FakeArborist,
42+
'{LIB}/utils/reify-finish.js': async () => {},
43+
},
44+
})
45+
await npm.exec('prune', [])
46+
t.strictSame(capturedOpts.allowScripts, { canvas: true },
47+
'opts.allowScripts populated from package.json')
48+
})

test/lib/commands/uninstall.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,30 @@ t.test('completion', async t => {
214214
const res = await uninstall.completion({ conf: { argv: { remain: ['npm', 'uninstall'] } } })
215215
t.match(res, ['bar', 'foo'])
216216
})
217+
218+
t.test('uninstall threads allowScripts policy through to arborist', async t => {
219+
let capturedOpts
220+
const FakeArborist = function (opts) {
221+
capturedOpts = opts
222+
this.options = opts
223+
this.actualTree = { inventory: new Map() }
224+
}
225+
FakeArborist.prototype.reify = async () => {}
226+
227+
const { npm } = await _mockNpm(t, {
228+
prefixDir: {
229+
'package.json': JSON.stringify({
230+
name: 'host',
231+
version: '1.0.0',
232+
allowScripts: { canvas: true },
233+
}),
234+
},
235+
mocks: {
236+
'@npmcli/arborist': FakeArborist,
237+
'{LIB}/utils/reify-finish.js': async () => {},
238+
},
239+
})
240+
await npm.exec('uninstall', ['canvas'])
241+
t.strictSame(capturedOpts.allowScripts, { canvas: true },
242+
'opts.allowScripts populated from package.json')
243+
})

0 commit comments

Comments
 (0)