@@ -82,21 +82,39 @@ def test_bash_escaped_dq_does_not_flip_state(self, transport):
8282 assert cmd == f'echo "esc\\ " ${{{ _v ("a" )} }}"'
8383
8484 @pytest .mark .skipif (os .name != "nt" , reason = "PowerShell semantics" )
85- def test_ps_bare_emits_env_var (self , transport ):
85+ def test_ps_bare_emits_braced_env_var (self , transport ):
8686 cmd , env = transport ._substitute_utcp_args (
8787 "mytool UTCP_ARG_x_UTCP_END" , {"x" : "a b" }, NONCE
8888 )
89- assert cmd == f"mytool $env:{ _v ('x' )} "
89+ # Braced form so suffix chars cannot be consumed into the var
90+ # name boundary.
91+ assert cmd == "mytool ${env:" + _v ("x" ) + "}"
9092 assert env [_v ("x" )] == "a b"
9193
9294 @pytest .mark .skipif (os .name != "nt" , reason = "PowerShell semantics" )
93- def test_ps_dq_emits_env_var (self , transport ):
95+ def test_ps_dq_emits_braced_env_var (self , transport ):
9496 cmd , env = transport ._substitute_utcp_args (
9597 'Write-Output "Hi UTCP_ARG_x_UTCP_END!"' , {"x" : "a; rm /" }, NONCE
9698 )
97- assert cmd == f 'Write-Output "Hi $env:{ _v ("x" )} !"'
99+ assert cmd == 'Write-Output "Hi ${ env:' + _v ("x" ) + ' }!"'
98100 assert env [_v ("x" )] == "a; rm /"
99101
102+ @pytest .mark .skipif (os .name != "nt" , reason = "PowerShell semantics" )
103+ def test_ps_alphanumeric_suffix_does_not_extend_var_name (self , transport ):
104+ # Regression: with the bare `$env:VAR` form, an alphanumeric or
105+ # underscore suffix in the template would be parsed as part of
106+ # the env var name. The braced form `${env:VAR}` closes the
107+ # boundary cleanly so the template suffix stays literal.
108+ cmd , env = transport ._substitute_utcp_args (
109+ 'Write-Output "URL=UTCP_ARG_id_UTCP_END123suffix"' ,
110+ {"id" : "abc" },
111+ NONCE ,
112+ )
113+ assert cmd == (
114+ 'Write-Output "URL=${env:' + _v ("id" ) + '}123suffix"'
115+ )
116+ assert env [_v ("id" )] == "abc"
117+
100118 @pytest .mark .skipif (os .name != "nt" , reason = "PowerShell semantics" )
101119 def test_ps_sq_raises_with_clear_message (self , transport ):
102120 with pytest .raises (ValueError , match = "single-quoted" ):
@@ -110,7 +128,7 @@ def test_ps_backtick_in_dq_preserved(self, transport):
110128 'Write-Output "pre `"x`" UTCP_ARG_a_UTCP_END"' , {"a" : "v" }, NONCE
111129 )
112130 # dq state must still be active when placeholder is hit.
113- assert cmd == f 'Write-Output "pre `"x`" $env:{ _v ("a" )} "'
131+ assert cmd == 'Write-Output "pre `"x`" ${ env:' + _v ("a" ) + ' }"'
114132
115133 def test_multiple_placeholders_share_namespace (self , transport ):
116134 cmd , env = transport ._substitute_utcp_args (
@@ -132,7 +150,10 @@ def test_multiple_placeholders_in_same_dq_compose(self, transport):
132150 NONCE ,
133151 )
134152 if os .name == "nt" :
135- assert cmd == f'curl "https://api/$env:{ _v ("id" )} /$env:{ _v ("action" )} "'
153+ assert cmd == (
154+ 'curl "https://api/${env:' + _v ("id" )
155+ + '}/${env:' + _v ("action" ) + '}"'
156+ )
136157 else :
137158 assert (
138159 cmd
0 commit comments