Skip to content

Commit 364e511

Browse files
committed
add test, support backslashes
1 parent 44d19f1 commit 364e511

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

cli/configssh_internal_test.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func Test_sshConfigSplitOnCoderSection(t *testing.T) {
139139
// This test tries to mimic the behavior of OpenSSH
140140
// when executing e.g. a ProxyCommand.
141141
// nolint:tparallel
142-
func Test_sshConfigExecEscape(t *testing.T) {
142+
func Test_sshConfigProxyCommandEscape(t *testing.T) {
143143
t.Parallel()
144144

145145
tests := []struct {
@@ -186,6 +186,60 @@ func Test_sshConfigExecEscape(t *testing.T) {
186186
}
187187
}
188188

189+
// This test tries to mimic the behavior of OpenSSH
190+
// when executing e.g. a match exec command.
191+
// nolint:tparallel
192+
func Test_sshConfigMatchExecEscape(t *testing.T) {
193+
t.Parallel()
194+
195+
tests := []struct {
196+
name string
197+
path string
198+
wantErr bool
199+
}{
200+
{"no spaces", "simple", false},
201+
{"spaces", "path with spaces", false},
202+
{"quotes fails", "path with \"quotes\"", true},
203+
{"backslashes", "path with \\backslashes", false},
204+
{"tabs", "path with \ttabs", false},
205+
{"newline fails", "path with \nnewline", true},
206+
}
207+
// nolint:paralleltest // Fixes a flake
208+
for _, tt := range tests {
209+
tt := tt
210+
t.Run(tt.name, func(t *testing.T) {
211+
cmd := "/bin/sh"
212+
arg := "-c"
213+
contents := []byte("#!/bin/sh\necho yay\n")
214+
if runtime.GOOS == "windows" {
215+
cmd = "cmd.exe"
216+
arg = "/c"
217+
contents = []byte("echo yay\n")
218+
}
219+
220+
dir := filepath.Join(t.TempDir(), tt.path)
221+
err := os.MkdirAll(dir, 0o755)
222+
require.NoError(t, err)
223+
bin := filepath.Join(dir, "coder.bat") // Windows will treat it as batch, Linux doesn't care
224+
225+
err = os.WriteFile(bin, contents, 0o755) //nolint:gosec
226+
require.NoError(t, err)
227+
228+
escaped, err := sshConfigMatchExecEscape(bin)
229+
if tt.wantErr {
230+
require.Error(t, err)
231+
return
232+
}
233+
require.NoError(t, err)
234+
235+
b, err := exec.Command(cmd, arg, escaped).CombinedOutput() //nolint:gosec
236+
require.NoError(t, err)
237+
got := strings.TrimSpace(string(b))
238+
require.Equal(t, "yay", got)
239+
})
240+
}
241+
}
242+
189243
func Test_sshConfigExecEscapeSeparatorForce(t *testing.T) {
190244
t.Parallel()
191245

cli/configssh_other.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ func sshConfigMatchExecEscape(path string) (string, error) {
2626
return "", xerrors.Errorf("path must not contain quotes: %q", path)
2727
}
2828

29-
// OpenSSH passes the match exec string directly to the user's shell. sh, bash and zsh accept spaces and tabs
30-
// simply escaped by a `\`. It's hard to predict exactly what more exotic shells might do, but this should work for
31-
// macOS and most Linux distros in their default configuration.
29+
// OpenSSH passes the match exec string directly to the user's shell. sh, bash and zsh accept spaces, tabs and
30+
// backslashes simply escaped by a `\`. It's hard to predict exactly what more exotic shells might do, but this
31+
// should work for macOS and most Linux distros in their default configuration.
32+
path = strings.ReplaceAll(path, `\`, `\\`) // must be first, since later replacements add backslashes.
3233
path = strings.ReplaceAll(path, " ", "\\ ")
3334
path = strings.ReplaceAll(path, "\t", "\\\t")
3435
return path, nil

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy