Skip to content

Commit 72cf9d5

Browse files
committed
Add extra SSH options setting
1 parent 3096448 commit 72cf9d5

File tree

7 files changed

+63
-22
lines changed

7 files changed

+63
-22
lines changed

src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt

+7
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ class CoderSettingsConfigurable : BoundConfigurable("Coder") {
109109
CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.comment")
110110
)
111111
}.layout(RowLayout.PARENT_GRID)
112+
row(CoderGatewayBundle.message("gateway.connector.settings.ssh-config-options.title")) {
113+
textArea().resizableColumn().align(AlignX.FILL)
114+
.bindText(state::sshConfigOptions)
115+
.comment(
116+
CoderGatewayBundle.message("gateway.connector.settings.ssh-config-options.comment")
117+
)
118+
}.layout(RowLayout.PARENT_GRID)
112119
}
113120
}
114121

src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,11 @@ class CoderCLIManager(
268268
UserKnownHostsFile /dev/null
269269
LogLevel ERROR
270270
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
271-
""".trimIndent().replace("\n", System.lineSeparator())
271+
""".trimIndent()
272+
.plus(if (settings.sshConfigOptions.trim() != "") {
273+
"\n" + settings.sshConfigOptions.trim().prependIndent(" ")
274+
} else "")
275+
.replace("\n", System.lineSeparator())
272276
})
273277

274278
if (contents == null) {

src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt

+8
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ open class CoderSettingsState(
5757
// around issues on macOS where it periodically wakes and Gateway
5858
// reconnects, keeping the workspace constantly up.
5959
open var disableAutostart: Boolean = getOS() == OS.MAC,
60+
// Extra SSH config options.
61+
open var sshConfigOptions: String = "",
6062
)
6163

6264
/**
@@ -113,6 +115,12 @@ open class CoderSettings(
113115
val disableAutostart: Boolean
114116
get() = state.disableAutostart
115117

118+
/**
119+
* Extra SSH config to append to each host block.
120+
*/
121+
val sshConfigOptions: String
122+
get() = state.sshConfigOptions
123+
116124
/**
117125
* Where the specified deployment should put its data.
118126
*/

src/main/resources/messages/CoderGatewayBundle.properties

+4
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,7 @@ gateway.connector.settings.disable-autostart.comment=Checking this box will \
117117
cause the plugin to configure the CLI with --disable-autostart. You must go \
118118
through the IDE selection again for the plugin to reconfigure the CLI with \
119119
this setting.
120+
gateway.connector.settings.ssh-config-options.title=SSH config options
121+
gateway.connector.settings.ssh-config-options.comment=Extra SSH config options \
122+
to use when connecting to a workspace. This text will be appended as-is to \
123+
the SSH configuration block for each workspace.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# --- START CODER JETBRAINS test.coder.invalid
2+
Host coder-jetbrains--extra--test.coder.invalid
3+
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio extra
4+
ConnectTimeout 0
5+
StrictHostKeyChecking no
6+
UserKnownHostsFile /dev/null
7+
LogLevel ERROR
8+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
9+
ServerAliveInterval 5
10+
ServerAliveCountMax 3
11+
# --- END CODER JETBRAINS test.coder.invalid

src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt

+26-21
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package com.coder.gateway.cli
33
import com.coder.gateway.cli.ex.MissingVersionException
44
import com.coder.gateway.cli.ex.ResponseException
55
import com.coder.gateway.cli.ex.SSHConfigFormatException
6-
import com.coder.gateway.settings.CoderSettingsState
76
import com.coder.gateway.settings.CoderSettings
7+
import com.coder.gateway.settings.CoderSettingsState
88
import com.coder.gateway.util.InvalidVersionException
99
import com.coder.gateway.util.OS
1010
import com.coder.gateway.util.SemVer
@@ -238,34 +238,38 @@ internal class CoderCLIManagerTest {
238238
val input: String?,
239239
val output: String,
240240
val remove: String,
241-
val headerCommand: String?,
241+
val headerCommand: String = "",
242242
val disableAutostart: Boolean = false,
243-
val features: Features? = null,
243+
val features: Features = Features(),
244+
val extraConfig: String = "",
244245
)
245246

246247
@Test
247248
fun testConfigureSSH() {
248249
val tests = listOf(
249-
SSHTest(listOf("foo", "bar"), null,"multiple-workspaces", "blank", null),
250-
SSHTest(listOf("foo", "bar"), null,"multiple-workspaces", "blank", null),
251-
SSHTest(listOf("foo-bar"), "blank", "append-blank", "blank", null),
252-
SSHTest(listOf("foo-bar"), "blank-newlines", "append-blank-newlines", "blank", null),
253-
SSHTest(listOf("foo-bar"), "existing-end", "replace-end", "no-blocks", null),
254-
SSHTest(listOf("foo-bar"), "existing-end-no-newline", "replace-end-no-newline", "no-blocks", null),
255-
SSHTest(listOf("foo-bar"), "existing-middle", "replace-middle", "no-blocks", null),
256-
SSHTest(listOf("foo-bar"), "existing-middle-and-unrelated", "replace-middle-ignore-unrelated", "no-related-blocks", null),
257-
SSHTest(listOf("foo-bar"), "existing-only", "replace-only", "blank", null),
258-
SSHTest(listOf("foo-bar"), "existing-start", "replace-start", "no-blocks", null),
259-
SSHTest(listOf("foo-bar"), "no-blocks", "append-no-blocks", "no-blocks", null),
260-
SSHTest(listOf("foo-bar"), "no-related-blocks", "append-no-related-blocks", "no-related-blocks", null),
261-
SSHTest(listOf("foo-bar"), "no-newline", "append-no-newline", "no-blocks", null),
250+
SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank"),
251+
SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank"),
252+
SSHTest(listOf("foo-bar"), "blank", "append-blank", "blank"),
253+
SSHTest(listOf("foo-bar"), "blank-newlines", "append-blank-newlines", "blank"),
254+
SSHTest(listOf("foo-bar"), "existing-end", "replace-end", "no-blocks"),
255+
SSHTest(listOf("foo-bar"), "existing-end-no-newline", "replace-end-no-newline", "no-blocks"),
256+
SSHTest(listOf("foo-bar"), "existing-middle", "replace-middle", "no-blocks"),
257+
SSHTest(listOf("foo-bar"), "existing-middle-and-unrelated", "replace-middle-ignore-unrelated", "no-related-blocks"),
258+
SSHTest(listOf("foo-bar"), "existing-only", "replace-only", "blank"),
259+
SSHTest(listOf("foo-bar"), "existing-start", "replace-start", "no-blocks"),
260+
SSHTest(listOf("foo-bar"), "no-blocks", "append-no-blocks", "no-blocks"),
261+
SSHTest(listOf("foo-bar"), "no-related-blocks", "append-no-related-blocks", "no-related-blocks"),
262+
SSHTest(listOf("foo-bar"), "no-newline", "append-no-newline", "no-blocks"),
262263
if (getOS() == OS.WINDOWS) {
263264
SSHTest(listOf("header"), null, "header-command-windows", "blank", """"C:\Program Files\My Header Command\HeaderCommand.exe" --url="%CODER_URL%" --test="foo bar"""")
264265
} else {
265266
SSHTest(listOf("header"), null, "header-command", "blank", "my-header-command --url=\"\$CODER_URL\" --test=\"foo bar\" --literal='\$CODER_URL'")
266267
},
267-
SSHTest(listOf("foo"), null, "disable-autostart", "blank", null, true, Features(true)),
268-
SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", null, true, Features(false)),
268+
SSHTest(listOf("foo"), null, "disable-autostart", "blank", "", true, Features(true)),
269+
SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", "", true, Features(false)),
270+
SSHTest(listOf("extra"), null, "extra-config", "blank",
271+
extraConfig = listOf("ServerAliveInterval 5",
272+
"ServerAliveCountMax 3").joinToString(System.lineSeparator())),
269273
)
270274

271275
val newlineRe = "\r?\n".toRegex()
@@ -274,7 +278,8 @@ internal class CoderCLIManagerTest {
274278
val settings = CoderSettings(CoderSettingsState(
275279
disableAutostart = it.disableAutostart,
276280
dataDirectory = tmpdir.resolve("configure-ssh").toString(),
277-
headerCommand = it.headerCommand ?: ""),
281+
headerCommand = it.headerCommand,
282+
sshConfigOptions = it.extraConfig),
278283
sshConfigPath = tmpdir.resolve(it.input + "_to_" + it.output + ".conf"))
279284

280285
val ccm = CoderCLIManager(URL("https://test.coder.invalid"), settings)
@@ -295,12 +300,12 @@ internal class CoderCLIManagerTest {
295300
.replace("/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64", escape(ccm.localBinaryPath.toString()))
296301

297302
// Add workspaces.
298-
ccm.configSsh(it.workspaces.toSet(), it.features ?: Features())
303+
ccm.configSsh(it.workspaces.toSet(), it.features)
299304

300305
assertEquals(expectedConf, settings.sshConfigPath.toFile().readText())
301306

302307
// Remove configuration.
303-
ccm.configSsh(emptySet(), it.features ?: Features())
308+
ccm.configSsh(emptySet(), it.features)
304309

305310
// Remove is the configuration we expect after removing.
306311
assertEquals(

src/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt

+2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ internal class CoderSettingsTest {
183183
tlsCAPath = "tls ca path",
184184
tlsAlternateHostname = "tls alt hostname",
185185
disableAutostart = true,
186+
sshConfigOptions = "ssh config options",
186187
)
187188
)
188189

@@ -194,5 +195,6 @@ internal class CoderSettingsTest {
194195
assertEquals("tls ca path", settings.tls.caPath)
195196
assertEquals("tls alt hostname", settings.tls.altHostname)
196197
assertEquals(true, settings.disableAutostart)
198+
assertEquals("ssh config options", settings.sshConfigOptions)
197199
}
198200
}

0 commit comments

Comments
 (0)