1
1
import * as childProcess from 'child_process' ;
2
- import { quoteAll } from 'shescape/stateless' ;
2
+ import { escapeAll , quoteAll } from 'shescape/stateless' ;
3
+ import * as os from 'node:os' ;
3
4
4
5
export function execute (
5
6
command : string ,
@@ -9,13 +10,26 @@ export function execute(
9
10
const spawnOptions : {
10
11
shell : boolean ;
11
12
cwd ?: string ;
12
- } = { shell : true } ;
13
+ } = { shell : false } ;
13
14
if ( options && options . cwd ) {
14
15
spawnOptions . cwd = options . cwd ;
15
16
}
16
17
17
- args = quoteAll ( args , { flagProtection : false } ) ;
18
-
18
+ if ( args ) {
19
+ // Best practices, also security-wise, is to not invoke processes in a shell, but as a stand-alone command.
20
+ // However, on Windows, we need to invoke the command in a shell, due to internal NodeJS problems with this approach
21
+ // see: https://nodejs.org/docs/latest-v24.x/api/child_process.html#spawning-bat-and-cmd-files-on-windows
22
+ const isWinLocal = / ^ w i n / . test ( os . platform ( ) ) ;
23
+ if ( isWinLocal ) {
24
+ spawnOptions . shell = true ;
25
+ // Further, we distinguish between quoting and escaping arguments since quoteAll does not support quoting without
26
+ // supplying a shell, but escapeAll does.
27
+ // See this (very long) discussion for more details: https://github.com/ericcornelissen/shescape/issues/2009
28
+ args = quoteAll ( args , { ...spawnOptions , flagProtection : false } ) ;
29
+ } else {
30
+ args = escapeAll ( args , { ...spawnOptions , flagProtection : false } ) ;
31
+ }
32
+ }
19
33
return new Promise ( ( resolve , reject ) => {
20
34
let stdout = '' ;
21
35
let stderr = '' ;
@@ -28,6 +42,12 @@ export function execute(
28
42
stderr = stderr + data ;
29
43
} ) ;
30
44
45
+ // Handle spawn errors (e.g., ENOENT when command doesn't exist)
46
+ proc . on ( 'error' , ( error ) => {
47
+ stderr = error . message ;
48
+ reject ( { stdout, stderr } ) ;
49
+ } ) ;
50
+
31
51
proc . on ( 'close' , ( code : number ) => {
32
52
if ( code !== 0 ) {
33
53
return reject ( new Error ( stdout || stderr ) ) ;
0 commit comments