Skip to content

Commit caee378

Browse files
committed
fixup test on Windows
1 parent 970b115 commit caee378

File tree

2 files changed

+29
-27
lines changed

2 files changed

+29
-27
lines changed

cli/configssh_internal_test.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,17 @@ func Test_sshConfigMatchExecEscape(t *testing.T) {
193193
t.Parallel()
194194

195195
tests := []struct {
196-
name string
197-
path string
198-
wantErr bool
196+
name string
197+
path string
198+
wantErrOther bool
199+
wantErrWindows bool
199200
}{
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},
201+
{"no spaces", "simple", false, false},
202+
{"spaces", "path with spaces", false, false},
203+
{"quotes", "path with \"quotes\"", false, true},
204+
{"backslashes", "path with\\backslashes", false, false},
205+
{"tabs", "path with \ttabs", false, true},
206+
{"newline fails", "path with \nnewline", true, true},
206207
}
207208
// nolint:paralleltest // Fixes a flake
208209
for _, tt := range tests {
@@ -214,24 +215,26 @@ func Test_sshConfigMatchExecEscape(t *testing.T) {
214215
if runtime.GOOS == "windows" {
215216
cmd = "cmd.exe"
216217
arg = "/c"
217-
contents = []byte("echo yay\n")
218+
contents = []byte("@echo yay\n")
218219
}
219220

220221
dir := filepath.Join(t.TempDir(), tt.path)
221-
err := os.MkdirAll(dir, 0o755)
222-
require.NoError(t, err)
223222
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-
228223
escaped, err := sshConfigMatchExecEscape(bin)
229-
if tt.wantErr {
224+
if (runtime.GOOS == "windows" && tt.wantErrWindows) || (runtime.GOOS != "windows" && tt.wantErrOther) {
230225
require.Error(t, err)
231226
return
232227
}
233228
require.NoError(t, err)
234229

230+
err = os.MkdirAll(dir, 0o755)
231+
require.NoError(t, err)
232+
233+
err = os.WriteFile(bin, contents, 0o755) //nolint:gosec
234+
require.NoError(t, err)
235+
236+
// OpenSSH processes %% escape sequences into %
237+
escaped = strings.ReplaceAll(escaped, "%%", "%")
235238
b, err := exec.Command(cmd, arg, escaped).CombinedOutput() //nolint:gosec
236239
require.NoError(t, err)
237240
got := strings.TrimSpace(string(b))

cli/configssh_windows.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,24 @@ var hideForceUnixSlashes = false
3434
//
3535
// Other notes:
3636
// - @ in `@cmd.exe` suppresses echoing it, so you don't get this command printed
37-
// - without another invocation of cmd.exe (e.g. `do @cmd.exe /c %%aC:\Program Files\Coder\bin\coder.exe%%a`) then
38-
// the double-quote gets interpreted as part of the path and you get: '"C:\Program' is not recognized. Constructing
39-
// the string and then passing it to another instance of cmd.exe does this trick here.
37+
// - we need another invocation of cmd.exe (e.g. `do @cmd.exe /c %%aC:\Program Files\Coder\bin\coder.exe%%a`). Without
38+
// it the double-quote gets interpreted as part of the path, and you get: '"C:\Program' is not recognized.
39+
// Constructing the string and then passing it to another instance of cmd.exe does this trick here.
4040
// - OpenSSH passes the `Match exec` command to cmd.exe regardless of whether the user has a unix-like shell like
4141
// git bash, so we don't have a `forceUnixPath` option like for the ProxyCommand which does respect the user's
42-
// configured shell.
42+
// configured shell on Windows.
4343
func sshConfigMatchExecEscape(path string) (string, error) {
4444
// This is unlikely to ever happen, but newlines are allowed on
4545
// certain filesystems, but cannot be used inside ssh config.
4646
if strings.ContainsAny(path, "\n") {
4747
return "", xerrors.Errorf("invalid path: %s", path)
4848
}
49-
// Windows does not allow double-quotes in paths. If we get one it is an error.
50-
if strings.Contains(path, `"`) {
51-
return "", xerrors.Errorf("path must not contain quotes: %q", path)
49+
// Windows does not allow double-quotes or tabs in paths. If we get one it is an error.
50+
if strings.ContainsAny(path, "\"\t") {
51+
return "", xerrors.Errorf("path must not contain quotes or tabs: %q", path)
5252
}
53-
// A space or a tab requires quoting, but tabs must not be escaped
54-
// (\t) since OpenSSH interprets it as a literal \t, not a tab.
55-
if strings.ContainsAny(path, " \t") {
53+
54+
if strings.ContainsAny(path, " ") {
5655
// c.f. function comment for how this works.
5756
path = fmt.Sprintf("for /f %%%%a in ('powershell.exe -Command [char]34') do @cmd.exe /c %%%%a%s%%%%a", path) //nolint:gocritic // We don't want %q here.
5857
}

0 commit comments

Comments
 (0)