-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexec.ts
More file actions
75 lines (71 loc) · 2.43 KB
/
exec.ts
File metadata and controls
75 lines (71 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* @fileoverview Execute npm commands with optimized flags and security defaults.
*
* SECURITY: Array-based arguments prevent command injection. All elements
* in the args array are properly escaped by Node.js when passed to spawn().
*
* NOTE: We don't apply hardening flags to npm because:
* 1. npm is a trusted system tool installed with Node.js.
* 2. npm requires full system access (filesystem, network, child processes).
* 3. Hardening flags would prevent npm from functioning even with --allow-* grants.
* 4. The permission model is intended for untrusted user code, not package managers.
*/
import { NPM_BIN_PATH } from '../../../constants/agents'
import { WIN32 } from '../../../constants/platform'
import { isDebug } from '../../../debug/namespace'
import {
ArrayPrototypeIndexOf,
ArrayPrototypeSlice,
} from '../../../primordials/array'
import { spawn } from '../../../spawn/spawn'
import {
isNpmAuditFlag,
isNpmFundFlag,
isNpmLoglevelFlag,
isNpmProgressFlag,
} from './flags'
import type { SpawnOptions } from '../../../spawn/types'
/**
* Execute npm commands with optimized flags and settings.
*
* @example
* ```typescript
* await execNpm(['install', '--save', 'lodash'])
* await execNpm(['run', 'build'], { cwd: '/tmp/project' })
* ```
*/
export function execNpm(args: string[], options?: SpawnOptions | undefined) {
const useDebug = isDebug()
const terminatorPos = ArrayPrototypeIndexOf(args, '--')
const npmArgs = (
terminatorPos === -1 ? args : ArrayPrototypeSlice(args, 0, terminatorPos)
).filter(
(a: string) =>
!isNpmAuditFlag(a) && !isNpmFundFlag(a) && !isNpmProgressFlag(a),
)
const otherArgs =
terminatorPos === -1 ? [] : ArrayPrototypeSlice(args, terminatorPos)
// Default loglevel "warn" (one quieter than npm's default "notice").
const logLevelArgs =
useDebug || npmArgs.some(isNpmLoglevelFlag) ? [] : ['--loglevel', 'warn']
return spawn(
NPM_BIN_PATH,
[
// Even with `--loglevel=error`, npm still runs through 'audit'/'fund'
// codepaths unless --no-audit / --no-fund are passed explicitly.
'--no-audit',
'--no-fund',
// Avoid input being swallowed by the spinner in recent npm versions.
'--no-progress',
...logLevelArgs,
...npmArgs,
...otherArgs,
],
{
__proto__: null,
// npm on Windows is a .cmd file that requires a shell.
shell: WIN32,
...options,
} as SpawnOptions,
)
}