@@ -96,7 +96,16 @@ program
9696 . choices ( [ 'auto' , 'admin' , 'user' ] )
9797 . default ( 'auto' ) ,
9898 )
99- . option ( '--include <tags>' , 'Comma-separated extra tags to include (e.g. "@critical").' )
99+ . option (
100+ '--also-include <tags>' ,
101+ 'Additional tag pattern(s) to OR onto the smoke selection (e.g. "@critical"). ' +
102+ 'To NARROW the smoke set, use --pages instead.' ,
103+ )
104+ // Backwards-compat alias for the original `--include` name. Deprecated —
105+ // will be removed in a future release. Kept hidden from the main help.
106+ . addOption (
107+ new Option ( '--include <tags>' , '(deprecated) alias for --also-include.' ) . hideHelp ( ) ,
108+ )
100109 . option ( '--exclude <tags>' , 'Comma-separated tags to exclude.' )
101110 . option (
102111 '--pages <names>' ,
@@ -108,12 +117,7 @@ program
108117 'Per-test timeout. Accepts "180s", "3m", or raw ms.' ,
109118 '180s' ,
110119 )
111- . option (
112- '--output <dir>' ,
113- 'Output directory for the smoke report.' ,
114- ( ) => defaultOutputDir ( ) ,
115- defaultOutputDir ( ) ,
116- )
120+ . option ( '--output <dir>' , 'Output directory for the smoke report.' )
117121 . option ( '--headed' , 'Run the browser in headed mode (debugging only).' , false )
118122 . option ( '--insecure-tls' , 'Accept self-signed TLS certificates.' , false )
119123 . action ( async ( raw : Record < string , unknown > ) => {
@@ -124,6 +128,9 @@ program
124128 ) ;
125129 process . exit ( 2 ) ;
126130 }
131+ // Scrub the password value from process.argv so accidental introspection
132+ // (logs, crash dumps, `ps`-style helpers reading argv) cannot leak it.
133+ scrubPasswordFromArgv ( ) ;
127134
128135 const endpoint = String ( raw . endpoint ) ;
129136 const webserver =
@@ -145,18 +152,25 @@ program
145152 return ;
146153 }
147154
155+ // `--also-include` is the canonical flag; `--include` is a hidden alias.
156+ const alsoIncludeRaw =
157+ ( raw . alsoInclude as string | string [ ] | undefined ) ??
158+ ( raw . include as string | string [ ] | undefined ) ;
159+
160+ const outputDir = path . resolve ( String ( raw . output ?? defaultOutputDir ( ) ) ) ;
161+
148162 const opts : SmokeRunOptions = {
149163 endpoint,
150164 webserver,
151165 email : String ( raw . email ) ,
152166 password,
153167 role : ( raw . role as SmokeRoleSelection ) ?? 'auto' ,
154- include : splitCsvArg ( raw . include as string | string [ ] | undefined ) ,
168+ include : splitCsvArg ( alsoIncludeRaw ) ,
155169 exclude : splitCsvArg ( raw . exclude as string | string [ ] | undefined ) ,
156170 pages : splitCsvArg ( raw . pages as string | string [ ] | undefined ) ,
157171 workers : typeof raw . workers === 'number' && raw . workers > 0 ? raw . workers : undefined ,
158172 timeoutMs,
159- outputDir : path . resolve ( String ( raw . output ?? defaultOutputDir ( ) ) ) ,
173+ outputDir,
160174 headed : raw . headed === true ,
161175 insecureTls : raw . insecureTls === true ,
162176 } ;
@@ -203,6 +217,27 @@ async function resolvePassword(raw: Record<string, unknown>): Promise<string | u
203217 return undefined ;
204218}
205219
220+ /**
221+ * Replace the resolved password value in `process.argv` with `***` so
222+ * downstream introspection (crash dumps, logs that dump argv, child
223+ * processes inheriting argv via APIs that read the parent's command
224+ * line) cannot leak the secret. Covers both `--password VALUE` and
225+ * `--password=VALUE` forms.
226+ */
227+ function scrubPasswordFromArgv ( ) : void {
228+ for ( let i = 0 ; i < process . argv . length ; i ++ ) {
229+ const a = process . argv [ i ] ;
230+ if ( a == null ) continue ;
231+ if ( a . startsWith ( '--password=' ) ) {
232+ process . argv [ i ] = '--password=***' ;
233+ continue ;
234+ }
235+ if ( a === '--password' && i > 0 && process . argv [ i + 1 ] != null ) {
236+ process . argv [ i + 1 ] = '***' ;
237+ }
238+ }
239+ }
240+
206241function readStdin ( ) : Promise < string > {
207242 return new Promise ( ( resolve , reject ) => {
208243 const chunks : Buffer [ ] = [ ] ;
0 commit comments