@@ -2,6 +2,7 @@ package ssh
22
33import (
44 "os"
5+ "slices"
56 "strings"
67 "testing"
78)
@@ -92,7 +93,7 @@ func TestSSHArgs(t *testing.T) {
9293 }
9394 })
9495
95- t .Run ("SetEnv with env vars" , func (t * testing.T ) {
96+ t .Run ("SendEnv with env vars" , func (t * testing.T ) {
9697 cc := ConnConfig {
9798 Host : "10.0.0.1" ,
9899 User : "pixel" ,
@@ -103,24 +104,27 @@ func TestSSHArgs(t *testing.T) {
103104 }
104105 args := Args (cc )
105106
106- // All vars should be in a single SetEnv directive (space-separated,
107- // sorted by key), preceded by -o. Multiple -o SetEnv flags don't
108- // stack in OpenSSH — only the first takes effect.
109- want := "SetEnv=API_KEY=sk-secret GITHUB_TOKEN=ghp_abc123"
107+ // SendEnv should contain only key names (sorted), no values.
108+ // Values are read from the process environment by the SSH client.
109+ want := "SendEnv=API_KEY GITHUB_TOKEN"
110110 var found bool
111111 for i , a := range args {
112- if strings .HasPrefix (a , "SetEnv =" ) {
112+ if strings .HasPrefix (a , "SendEnv =" ) {
113113 if i == 0 || args [i - 1 ] != "-o" {
114- t .Errorf ("SetEnv arg %q not preceded by -o" , a )
114+ t .Errorf ("SendEnv arg %q not preceded by -o" , a )
115115 }
116116 if a != want {
117- t .Errorf ("SetEnv = %q, want %q" , a , want )
117+ t .Errorf ("SendEnv = %q, want %q" , a , want )
118118 }
119119 found = true
120120 }
121+ // Ensure no SetEnv (secrets in argv).
122+ if strings .HasPrefix (a , "SetEnv=" ) {
123+ t .Errorf ("unexpected SetEnv arg %q — should use SendEnv" , a )
124+ }
121125 }
122126 if ! found {
123- t .Error ("SetEnv not found in args" )
127+ t .Error ("SendEnv not found in args" )
124128 }
125129
126130 // user@host should still be last.
@@ -129,20 +133,20 @@ func TestSSHArgs(t *testing.T) {
129133 }
130134 })
131135
132- t .Run ("nil env produces no SetEnv " , func (t * testing.T ) {
136+ t .Run ("nil env produces no SendEnv " , func (t * testing.T ) {
133137 args := Args (ConnConfig {Host : "10.0.0.1" , User : "pixel" })
134138 for _ , a := range args {
135- if strings .HasPrefix (a , "SetEnv =" ) {
136- t .Errorf ("unexpected SetEnv arg %q with nil env" , a )
139+ if strings .HasPrefix (a , "SendEnv =" ) {
140+ t .Errorf ("unexpected SendEnv arg %q with nil env" , a )
137141 }
138142 }
139143 })
140144
141- t .Run ("empty env produces no SetEnv " , func (t * testing.T ) {
145+ t .Run ("empty env produces no SendEnv " , func (t * testing.T ) {
142146 args := Args (ConnConfig {Host : "10.0.0.1" , User : "pixel" , Env : map [string ]string {}})
143147 for _ , a := range args {
144- if strings .HasPrefix (a , "SetEnv =" ) {
145- t .Errorf ("unexpected SetEnv arg %q with empty env" , a )
148+ if strings .HasPrefix (a , "SendEnv =" ) {
149+ t .Errorf ("unexpected SendEnv arg %q with empty env" , a )
146150 }
147151 }
148152 })
@@ -253,15 +257,18 @@ func TestConsoleArgs(t *testing.T) {
253257 }
254258 args := consoleArgs (cc , "zmx attach build" )
255259
256- // Verify SetEnv is present.
257- var foundSetEnv bool
260+ // Verify SendEnv is present (not SetEnv) .
261+ var foundSendEnv bool
258262 for _ , a := range args {
263+ if strings .HasPrefix (a , "SendEnv=" ) {
264+ foundSendEnv = true
265+ }
259266 if strings .HasPrefix (a , "SetEnv=" ) {
260- foundSetEnv = true
267+ t . Errorf ( "unexpected SetEnv arg %q — should use SendEnv" , a )
261268 }
262269 }
263- if ! foundSetEnv {
264- t .Error ("SetEnv not found in args" )
270+ if ! foundSendEnv {
271+ t .Error ("SendEnv not found in args" )
265272 }
266273
267274 // Verify -t and command at end.
@@ -277,3 +284,48 @@ func TestConsoleArgs(t *testing.T) {
277284 }
278285 })
279286}
287+
288+ func TestEnvWithOverrides (t * testing.T ) {
289+ base := []string {"HOME=/home/user" , "PATH=/usr/bin" , "EXISTING=old" }
290+
291+ t .Run ("overrides existing and adds new" , func (t * testing.T ) {
292+ result := EnvWithOverrides (base , map [string ]string {
293+ "EXISTING" : "new" ,
294+ "NEW_VAR" : "value" ,
295+ })
296+
297+ var foundExisting , foundNew bool
298+ for _ , e := range result {
299+ if e == "EXISTING=new" {
300+ foundExisting = true
301+ }
302+ if e == "NEW_VAR=value" {
303+ foundNew = true
304+ }
305+ if e == "EXISTING=old" {
306+ t .Error ("old value should be overridden" )
307+ }
308+ }
309+ if ! foundExisting {
310+ t .Error ("EXISTING not overridden" )
311+ }
312+ if ! foundNew {
313+ t .Error ("NEW_VAR not added" )
314+ }
315+ })
316+
317+ t .Run ("does not mutate base" , func (t * testing.T ) {
318+ orig := slices .Clone (base )
319+ _ = EnvWithOverrides (base , map [string ]string {"EXISTING" : "new" })
320+ if ! slices .Equal (base , orig ) {
321+ t .Error ("base slice was mutated" )
322+ }
323+ })
324+
325+ t .Run ("nil overrides returns copy" , func (t * testing.T ) {
326+ result := EnvWithOverrides (base , nil )
327+ if ! slices .Equal (result , base ) {
328+ t .Errorf ("result = %v, want %v" , result , base )
329+ }
330+ })
331+ }
0 commit comments