@@ -2135,6 +2135,72 @@ func TestExpandVarsCallSiteVarBeatsCLIArgsParam(t *testing.T) {
21352135 assert .Equal (t , "op inject -f" , expandVars ("op inject {{.CLI_ARGS}}" , vars , "--from-host" ))
21362136}
21372137
2138+ func TestExpandCLIArgsOnly (t * testing.T ) {
2139+ // Only CLI_ARGS is expanded — every other variable is left as-is so logs
2140+ // don't accidentally leak secret values.
2141+ assert .Equal (t , "pytest -n 4 backend/tests" ,
2142+ expandCLIArgsOnly ("pytest -n 4 {{.CLI_ARGS}}" , nil , "backend/tests" ))
2143+ assert .Equal (t , "pytest -n 4 backend/tests" ,
2144+ expandCLIArgsOnly ("pytest -n 4 ${CLI_ARGS}" , nil , "backend/tests" ))
2145+ assert .Equal (t , "curl -H Authorization:${TOKEN} arg" ,
2146+ expandCLIArgsOnly ("curl -H Authorization:${TOKEN} {{.CLI_ARGS}}" , map [string ]string {"TOKEN" : "hunter2" }, "arg" ))
2147+ // Call-site override beats the cliArgs param.
2148+ assert .Equal (t , "pytest -f" ,
2149+ expandCLIArgsOnly ("pytest {{.CLI_ARGS}}" , map [string ]string {"CLI_ARGS" : "-f" }, "--from-host" ))
2150+ }
2151+
2152+ func TestRunnerLogExpandsCLIArgs (t * testing.T ) {
2153+ dir := t .TempDir ()
2154+ tf := & Config {
2155+ Dir : dir ,
2156+ Tasks : map [string ]Task {
2157+ "test" : {
2158+ Cmds : []Cmd {{Cmd : "poetry run pytest -n 4 {{.CLI_ARGS}}" }},
2159+ },
2160+ },
2161+ DotenvVars : make (map [string ]string ),
2162+ }
2163+
2164+ runner := newTestRunner (t , tf , dir )
2165+ var stderr strings.Builder
2166+ runner .IO .Stderr = & stderr
2167+ captureExecs (runner )
2168+
2169+ require .NoError (t , runner .Run ("test" , "backend/tests/views/test_ask.py" ))
2170+
2171+ // The log should show the CLI_ARGS expanded — not the raw `{{.CLI_ARGS}}` template.
2172+ log := stderr .String ()
2173+ assert .Contains (t , log , "poetry run pytest -n 4 backend/tests/views/test_ask.py" )
2174+ assert .NotContains (t , log , "{{.CLI_ARGS}}" )
2175+ }
2176+
2177+ func TestRunnerLogDoesNotExpandOtherVars (t * testing.T ) {
2178+ // Other ${VAR} / {{.VAR}} references stay un-expanded in the log so we
2179+ // don't accidentally surface secrets, while CLI_ARGS is shown.
2180+ dir := t .TempDir ()
2181+ tf := & Config {
2182+ Dir : dir ,
2183+ Tasks : map [string ]Task {
2184+ "deploy" : {
2185+ Env : map [string ]string {"TOKEN" : "hunter2" },
2186+ Cmds : []Cmd {{Cmd : "deploy --token ${TOKEN} {{.CLI_ARGS}}" }},
2187+ },
2188+ },
2189+ DotenvVars : make (map [string ]string ),
2190+ }
2191+
2192+ runner := newTestRunner (t , tf , dir )
2193+ var stderr strings.Builder
2194+ runner .IO .Stderr = & stderr
2195+ captureExecs (runner )
2196+
2197+ require .NoError (t , runner .Run ("deploy" , "--dry-run" ))
2198+
2199+ log := stderr .String ()
2200+ assert .Contains (t , log , "deploy --token ${TOKEN} --dry-run" )
2201+ assert .NotContains (t , log , "hunter2" )
2202+ }
2203+
21382204func TestRunnerLogsToInjectedStderr (t * testing.T ) {
21392205 dir := t .TempDir ()
21402206 tf := & Config {
0 commit comments