Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- support for configuring the SSH config path, letting Toolbox manage a separate SSH config file instead of always
writing to `~/.ssh/config`
- the header command falls back to the `CODER_HEADER_COMMAND` environment variable when the setting is blank, matching the Coder CLI and the VS Code extension

## 0.9.3 - 2026-08-11

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ explicit entry per resolved workspace/agent using
expansion.

- `Header command` command that outputs additional HTTP headers. Each line of output must be in the format key=value.
The environment variable CODER_URL will be available to the command process.
When this setting is left blank, the `CODER_HEADER_COMMAND` environment variable is used instead, if set.

- `lastDeploymentURL` the last Coder deployment URL that Coder Toolbox successfully authenticated to.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ interface ReadOnlyCoderSettings {
/**
* An external command that outputs additional HTTP headers added to all
* requests. The command must output each header as `key=value` on its own
* line. The following environment variables will be available to the
* process: CODER_URL.
* line. When this setting is blank, the CODER_HEADER_COMMAND environment
* variable (the same variable the Coder CLI reads) is used instead, if set.
*/
val headerCommand: String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ class CoderSettingsStore(
override val globalDataDirectory: String get() = getDefaultGlobalDataDir().normalize().toString()
override val globalConfigDir: String get() = getDefaultGlobalConfigDir().normalize().toString()
override val enableDownloads: Boolean get() = store[ENABLE_DOWNLOADS]?.toBooleanStrictOrNull() ?: true
override val headerCommand: String? get() = store[HEADER_COMMAND]
override val headerCommand: String?
get() = store[HEADER_COMMAND].takeUnless { it.isNullOrEmpty() }
?: env.get(CODER_HEADER_COMMAND).takeUnless { it.isEmpty() }
override val tls: ReadOnlyTLSSettings
get() = TLSSettings(
certPath = store[TLS_CERT_PATH],
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.coder.toolbox.store

internal const val CODER_SSH_CONFIG_OPTIONS = "CODER_SSH_CONFIG_OPTIONS"

internal const val CODER_HEADER_COMMAND = "CODER_HEADER_COMMAND"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: at some point we should split the env keys from the persisted store keys.


internal const val LAST_USED_URL = "lastDeploymentURL"

internal const val DEFAULT_URL = "defaultURL"
Expand Down
25 changes: 25 additions & 0 deletions src/test/kotlin/com/coder/toolbox/settings/CoderSettingsTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.coder.toolbox.settings

import com.coder.toolbox.store.CODER_HEADER_COMMAND
import com.coder.toolbox.store.CODER_SSH_CONFIG_OPTIONS
import com.coder.toolbox.store.CoderSettingsStore
import com.coder.toolbox.store.DISABLE_AUTOSTART
Expand Down Expand Up @@ -236,6 +237,30 @@ internal class CoderSettingsTest {
assertEquals(Pair("http://test.toolbox.coder.com$expected", null), got)
}

@Test
fun testHeaderCommand() {
var settings = CoderSettingsStore(
pluginTestSettingsStore(HEADER_COMMAND to "header command from state"),
Environment(), logger
)
assertEquals("header command from state", settings.readOnly().headerCommand)

settings = CoderSettingsStore(
pluginTestSettingsStore(),
env = Environment(mapOf(CODER_HEADER_COMMAND to "header command from env")),
logger
)
assertEquals("header command from env", settings.readOnly().headerCommand)

// State has precedence.
settings = CoderSettingsStore(
pluginTestSettingsStore(HEADER_COMMAND to "header command from state"),
env = Environment(mapOf(CODER_HEADER_COMMAND to "header command from env")),
logger
)
assertEquals("header command from state", settings.readOnly().headerCommand)
}

@Test
fun testSSHConfigOptions() {
var settings = CoderSettingsStore(
Expand Down
Loading