diff --git a/src/lib/runner/build-args.ts b/src/lib/runner/build-args.ts index a1d9238..c29cdd7 100644 --- a/src/lib/runner/build-args.ts +++ b/src/lib/runner/build-args.ts @@ -18,6 +18,15 @@ function stringifyValue(value: unknown, joinWith: string): string { return String(value); } +/** Quotes a value for the human-readable `redactedCommandLine` display only - the real + * invocation always passes values as discrete argv elements/env vars (see build note below), + * so this never affects execution. Without it, a value like "Glitz and glam" renders as three + * bare words indistinguishable from separate argv entries. */ +function quoteForDisplay(value: string): string { + if (value !== "" && /^[a-zA-Z0-9_@%+=:,./-]+$/.test(value)) return value; + return `"${value.replace(/([$`"\\])/g, "\\$1")}"`; +} + /** Builds an argv-array invocation from validated variable values. Never produces a shell string. */ export function buildInvocation( script: ScriptConfig, @@ -43,7 +52,10 @@ export function buildInvocation( const argName = variable.argName!; const value = stringifyValue(raw, variable.joinWith); argv.push(argName, value); - redactedArgv.push(argName, variable.secret ? REDACTED : value); + redactedArgv.push( + argName, + variable.secret ? REDACTED : quoteForDisplay(value), + ); break; } case "flag": { @@ -57,7 +69,7 @@ export function buildInvocation( const value = stringifyValue(raw, variable.joinWith); env[variable.envName!] = value; redactedEnvAssignments.push( - `${variable.envName}=${variable.secret ? REDACTED : value}`, + `${variable.envName}=${variable.secret ? REDACTED : quoteForDisplay(value)}`, ); break; }