@@ -12,17 +12,38 @@ const DEFAULT_DSN = 'https://username@domain/123';
1212const DEFAULT_SENTRY_ORG_SLUG = 'sentry-javascript-sdks' ;
1313const DEFAULT_SENTRY_PROJECT = 'sentry-javascript-e2e-tests' ;
1414
15- function asyncExec ( command : string , options : { env : Record < string , string | undefined > ; cwd : string } ) : Promise < void > {
15+ function asyncExec (
16+ command : string | string [ ] ,
17+ options : { env : Record < string , string | undefined > ; cwd : string } ,
18+ ) : Promise < void > {
1619 return new Promise ( ( resolve , reject ) => {
17- const process = spawn ( command , { ...options , shell : true } ) ;
20+ // If command is an array, use spawn with separate command and args (safer)
21+ // If command is a string, maintain backward compatibility with shell: true
22+ let process : ReturnType < typeof spawn > ;
23+ if ( typeof command === 'string' ) {
24+ process = spawn ( command , { ...options , shell : true } ) ;
25+ } else {
26+ if ( command . length === 0 ) {
27+ return reject ( new Error ( 'Command array cannot be empty' ) ) ;
28+ }
29+ const cmd = command [ 0 ] ;
30+ if ( ! cmd ) {
31+ return reject ( new Error ( 'Command array cannot be empty' ) ) ;
32+ }
33+ process = spawn ( cmd , command . slice ( 1 ) , { ...options , shell : false } ) ;
34+ }
1835
19- process . stdout . on ( 'data' , data => {
20- console . log ( `${ data } ` ) ;
21- } ) ;
36+ if ( process . stdout ) {
37+ process . stdout . on ( 'data' , data => {
38+ console . log ( `${ data } ` ) ;
39+ } ) ;
40+ }
2241
23- process . stderr . on ( 'data' , data => {
24- console . error ( `${ data } ` ) ;
25- } ) ;
42+ if ( process . stderr ) {
43+ process . stderr . on ( 'data' , data => {
44+ console . error ( `${ data } ` ) ;
45+ } ) ;
46+ }
2647
2748 process . on ( 'error' , error => {
2849 reject ( error ) ;
@@ -43,6 +64,8 @@ async function run(): Promise<void> {
4364
4465 // Allow to run a single app only via `yarn test:run <app-name>`
4566 const appName = process . argv [ 2 ] || '' ;
67+ // Forward any additional flags to the test command
68+ const testFlags = process . argv . slice ( 3 ) ;
4669
4770 const dsn = process . env . E2E_TEST_DSN || DEFAULT_DSN ;
4871
@@ -87,7 +110,9 @@ async function run(): Promise<void> {
87110 await asyncExec ( 'volta run pnpm test:build' , { env, cwd } ) ;
88111
89112 console . log ( `Testing ${ testAppPath } ...` ) ;
90- await asyncExec ( 'volta run pnpm test:assert' , { env, cwd } ) ;
113+ // Pass command and arguments as an array to prevent command injection
114+ const testCommand = [ 'volta' , 'run' , 'pnpm' , 'test:assert' , ...testFlags ] ;
115+ await asyncExec ( testCommand , { env, cwd } ) ;
91116
92117 // clean up (although this is tmp, still nice to do)
93118 await rm ( tmpDirPath , { recursive : true } ) ;
0 commit comments