Skip to content

Commit a47e4b2

Browse files
committed
impl: support for ssh wildcard config
- resolves #46 - it is configurable in the Coder's plugin setting page
1 parent 1708944 commit a47e4b2

File tree

5 files changed

+53
-12
lines changed

5 files changed

+53
-12
lines changed

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

+38-11
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ fun ensureCLI(
112112
data class Features(
113113
val disableAutostart: Boolean = false,
114114
val reportWorkspaceUsage: Boolean = false,
115+
val wildcardSsh: Boolean = false,
115116
)
116117

117118
/**
@@ -282,7 +283,37 @@ class CoderCLIManager(
282283
} else {
283284
""
284285
}
285-
val blockContent =
286+
val options = """
287+
ConnectTimeout 0
288+
StrictHostKeyChecking no
289+
UserKnownHostsFile /dev/null
290+
LogLevel ERROR
291+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
292+
""".trimIndent()
293+
294+
val blockContent = if (settings.isSshWildcardConfigEnabled && feats.wildcardSsh) {
295+
startBlock + System.lineSeparator() +
296+
"""
297+
Host ${getWildcardHost(deploymentURL)}--*
298+
ProxyCommand ${proxyArgs.joinToString(" ")} --ssh-host-prefix ${getWildcardHost(deploymentURL)}-- %h
299+
""".trimIndent()
300+
.plus("\n" + options.prependIndent(" "))
301+
.plus(extraConfig)
302+
.plus("\n\n")
303+
.plus(
304+
"""
305+
Host ${getWildcardHost(deploymentURL)}-bg--*
306+
ProxyCommand ${backgroundProxyArgs.joinToString(" ")} --ssh-host-prefix ${
307+
getWildcardHost(
308+
deploymentURL
309+
)
310+
}-bg-- %h
311+
""".trimIndent()
312+
.plus("\n" + options.prependIndent(" "))
313+
.plus(extraConfig),
314+
).replace("\n", System.lineSeparator()) +
315+
System.lineSeparator() + endBlock
316+
} else {
286317
workspaceNames.joinToString(
287318
System.lineSeparator(),
288319
startBlock + System.lineSeparator(),
@@ -291,28 +322,21 @@ class CoderCLIManager(
291322
"""
292323
Host ${getHostName(deploymentURL, it)}
293324
ProxyCommand ${proxyArgs.joinToString(" ")} $it
294-
ConnectTimeout 0
295-
StrictHostKeyChecking no
296-
UserKnownHostsFile /dev/null
297-
LogLevel ERROR
298-
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
299325
""".trimIndent()
326+
.plus("\n" + options.prependIndent(" "))
300327
.plus(extraConfig)
301328
.plus("\n")
302329
.plus(
303330
"""
304331
Host ${getBackgroundHostName(deploymentURL, it)}
305332
ProxyCommand ${backgroundProxyArgs.joinToString(" ")} $it
306-
ConnectTimeout 0
307-
StrictHostKeyChecking no
308-
UserKnownHostsFile /dev/null
309-
LogLevel ERROR
310-
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
311333
""".trimIndent()
334+
.plus("\n" + options.prependIndent(" "))
312335
.plus(extraConfig),
313336
).replace("\n", System.lineSeparator())
314337
},
315338
)
339+
}
316340

317341
if (contents == null) {
318342
logger.info("No existing SSH config to modify")
@@ -475,13 +499,16 @@ class CoderCLIManager(
475499
Features(
476500
disableAutostart = version >= SemVer(2, 5, 0),
477501
reportWorkspaceUsage = version >= SemVer(2, 13, 0),
502+
version >= SemVer(2, 19, 0),
478503
)
479504
}
480505
}
481506

482507
companion object {
483508
private val tokenRegex = "--token [^ ]+".toRegex()
484509

510+
fun getWildcardHost(url: URL): String = "coder-jetbrains-toolbox--${url.safeHost()}"
511+
485512
@JvmStatic
486513
fun getHostName(
487514
url: URL,

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

+2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ data class CoderSettings(
8686
*/
8787
val disableAutostart: Boolean,
8888

89+
val isSshWildcardConfigEnabled: Boolean,
90+
8991
/**
9092
* The location of the SSH config. Defaults to ~/.ssh/config.
9193
*/

src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class CoderSettingsStore(
3737
altHostname = store[TLS_ALTERNATE_HOSTNAME]
3838
),
3939
disableAutostart = store[DISABLE_AUTOSTART]?.toBooleanStrictOrNull() ?: (getOS() == OS.MAC),
40-
40+
isSshWildcardConfigEnabled = store[ENABLE_SSH_WILDCARD_CONFIG]?.toBooleanStrictOrNull() ?: false,
4141
sshConfigPath = store[SSH_CONFIG_PATH].takeUnless { it.isNullOrEmpty() }
4242
?: Path.of(System.getProperty("user.home")).resolve(".ssh/config").normalize().toString(),
4343
sshLogDirectory = store[SSH_LOG_DIR],
@@ -124,6 +124,11 @@ class CoderSettingsStore(
124124
store[DISABLE_AUTOSTART] = shouldDisableAutostart.toString()
125125
}
126126

127+
fun updateEnableSshWildcardConfig(enable: Boolean) {
128+
backingSettings = backingSettings.copy(isSshWildcardConfigEnabled = enable)
129+
store[ENABLE_SSH_WILDCARD_CONFIG] = enable.toString()
130+
}
131+
127132
fun updateSshLogDir(path: String) {
128133
backingSettings = backingSettings.copy(sshLogDirectory = path)
129134
store[SSH_LOG_DIR] = path

src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ internal const val TLS_ALTERNATE_HOSTNAME = "tlsAlternateHostname"
3030

3131
internal const val DISABLE_AUTOSTART = "disableAutostart"
3232

33+
internal const val ENABLE_SSH_WILDCARD_CONFIG = "enableSshWildcardConfig"
34+
3335
internal const val SSH_CONFIG_PATH = "sshConfigPath"
3436

3537
internal const val SSH_LOG_DIR = "sshLogDir"

src/main/kotlin/com/coder/toolbox/views/CoderSettingsPage.kt

+5
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class CoderSettingsPage(context: CoderToolboxContext) : CoderPage(context, conte
4545
TextField(context.i18n.ptrl("TLS alternate hostname"), settings.tls.altHostname ?: "", TextType.General)
4646
private val disableAutostartField =
4747
CheckboxField(settings.disableAutostart, context.i18n.ptrl("Disable autostart"))
48+
49+
private val enableSshWildCardConfig =
50+
CheckboxField(settings.isSshWildcardConfigEnabled, context.i18n.ptrl("Enable SSH wildcard config"))
4851
private val sshExtraArgs =
4952
TextField(context.i18n.ptrl("Extra SSH options"), settings.sshConfigOptions ?: "", TextType.General)
5053
private val sshLogDirField =
@@ -64,6 +67,7 @@ class CoderSettingsPage(context: CoderToolboxContext) : CoderPage(context, conte
6467
tlsCAPathField,
6568
tlsAlternateHostnameField,
6669
disableAutostartField,
70+
enableSshWildCardConfig,
6771
sshLogDirField,
6872
sshExtraArgs,
6973
)
@@ -83,6 +87,7 @@ class CoderSettingsPage(context: CoderToolboxContext) : CoderPage(context, conte
8387
context.settingsStore.updateCAPath(tlsCAPathField.textState.value)
8488
context.settingsStore.updateAltHostname(tlsAlternateHostnameField.textState.value)
8589
context.settingsStore.updateDisableAutostart(disableAutostartField.checkedState.value)
90+
context.settingsStore.updateEnableSshWildcardConfig(enableSshWildCardConfig.checkedState.value)
8691
context.settingsStore.updateSshLogDir(sshLogDirField.textState.value)
8792
context.settingsStore.updateSshConfigOptions(sshExtraArgs.textState.value)
8893
}

0 commit comments

Comments
 (0)