Skip to content

Add header command setting #303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 22, 2023
Prev Previous commit
Next Next commit
Matche Coder CLI behavior for escaping to SSH config
  • Loading branch information
code-asher committed Sep 22, 2023
commit a090a3c2d57cc65e01bf4f197e94e317152b27a0
13 changes: 7 additions & 6 deletions src/main/kotlin/com/coder/gateway/sdk/CoderCLIManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -507,12 +507,10 @@ class CoderCLIManager @JvmOverloads constructor(
return if (cliMatches == null && dataCLIMatches != null) dataCLI else cli
}

var escapeRegex = """(["\\])""".toRegex()

/**
* Escape a command argument by wrapping it in double quotes and escaping
* any slashes and double quotes in the argument. For example, echo "te\st"
* becomes "echo \"te\\st\"".
* Escape a command argument to be used in the ProxyCommand of an SSH
* config. Surround with double quotes if the argument contains
* whitespace and escape any existing double quotes.
*
* Throws if the argument is invalid.
*/
Expand All @@ -521,7 +519,10 @@ class CoderCLIManager @JvmOverloads constructor(
if (s.contains("\n")) {
throw Exception("argument cannot contain newlines")
}
return "\"" + s.replace(escapeRegex, """\\$1""") + "\""
if (s.contains(" ") || s.contains("\t")) {
return "\"" + s.replace("\"", "\\\"") + "\""
}
return s.replace("\"", "\\\"")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/append-blank-newlines.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/append-blank.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/append-no-blocks.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Host test2
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/append-no-newline.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Host test2
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/append-no-related-blocks.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ some jetbrains config
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/header-command-windows.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--header--test.coder.invalid
HostName coder.header
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" --header-command "C:\\Program Files\\My Header Command\\\"also has quotes\"\\HeaderCommand.exe" ssh --stdio header
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "C:\Program Files\My Header Command\\"also has quotes\"\HeaderCommand.exe" ssh --stdio header
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/header-command.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--header--test.coder.invalid
HostName coder.header
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" --header-command "my-header-command \"test\"" ssh --stdio header
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --header-command "my-header-command \"test\"" ssh --stdio header
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
4 changes: 2 additions & 2 deletions src/test/fixtures/outputs/multiple-workspaces.conf
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo--test.coder.invalid
HostName coder.foo
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
Host coder-jetbrains--bar--test.coder.invalid
HostName coder.bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/replace-end-no-newline.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Host test2
Port 443 # --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/replace-end.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Host test2
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ some coder config
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/replace-middle.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Host test
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/replace-only.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
2 changes: 1 addition & 1 deletion src/test/fixtures/outputs/replace-start.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo-bar--test.coder.invalid
HostName coder.foo-bar
ProxyCommand "/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" --global-config "/tmp/coder-gateway/test.coder.invalid/config" ssh --stdio foo-bar
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo-bar
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand Down
14 changes: 9 additions & 5 deletions src/test/groovy/CoderCLIManagerTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,13 @@ class CoderCLIManagerTest extends Specification {

where:
str | expected
$/C:\"quote after slash"/$ | $/"C:\\\"quote after slash\""/$
$/C:\echo "hello world"/$ | $/"C:\\echo \"hello world\""/$
$/"C:\Program Files\HeaderCommand.exe" --flag/$ | $/"\"C:\\Program Files\\HeaderCommand.exe\" --flag"/$
$//tmp/coder/$ | $//tmp/coder/$
$//tmp/c o d e r/$ | $/"/tmp/c o d e r"/$
$/C:\no\spaces.exe/$ | $/C:\no\spaces.exe/$
$/C:\"quote after slash"/$ | $/"C:\\"quote after slash\""/$
$/C:\echo "hello world"/$ | $/"C:\echo \"hello world\""/$
$/C:\"no"\"spaces"/$ | $/C:\\"no\"\\"spaces\"/$
$/"C:\Program Files\HeaderCommand.exe" --flag/$ | $/"\"C:\Program Files\HeaderCommand.exe\" --flag"/$
}

def "configures an SSH file"() {
Expand All @@ -405,8 +409,8 @@ class CoderCLIManagerTest extends Specification {

def expectedConf = Path.of("src/test/fixtures/outputs/").resolve(output + ".conf").toFile().text
.replaceAll("\\r?\\n", System.lineSeparator())
.replace("\"/tmp/coder-gateway/test.coder.invalid/config\"", CoderCLIManager.escape(coderConfigPath.toString()))
.replace("\"/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64\"", CoderCLIManager.escape(ccm.localBinaryPath.toString()))
.replace("/tmp/coder-gateway/test.coder.invalid/config", CoderCLIManager.escape(coderConfigPath.toString()))
.replace("/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64", CoderCLIManager.escape(ccm.localBinaryPath.toString()))

when:
ccm.configSsh(workspaces.collect { DataGen.workspace(it) }, headerCommand)
Expand Down