Skip to content

Commit f57c07d

Browse files
committed
impl: introduce signature fallback setting
We are going to ask the user only once during the initial login screen if he wants to fallback on releases.coder.com when signatures are not present in the coder deployment. However, we still want to leave him the option to later change his mind the in Settings page.
1 parent aeb79e5 commit f57c07d

File tree

7 files changed

+57
-24
lines changed

7 files changed

+57
-24
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.coder.toolbox.cli.gpg.VerificationResult.Failed
1414
import com.coder.toolbox.cli.gpg.VerificationResult.Invalid
1515
import com.coder.toolbox.sdk.v2.models.Workspace
1616
import com.coder.toolbox.sdk.v2.models.WorkspaceAgent
17+
import com.coder.toolbox.settings.SignatureFallbackStrategy.ALLOW
1718
import com.coder.toolbox.util.CoderHostnameVerifier
1819
import com.coder.toolbox.util.InvalidVersionException
1920
import com.coder.toolbox.util.SemVer
@@ -188,10 +189,10 @@ class CoderCLIManager(
188189
}
189190
}
190191

191-
// if we could not find any signature and the user wants to explicitly
192+
// if we could not find any signature (404 or error) and the user wants to explicitly
192193
// confirm whether we run an unsigned cli
193194
if (signatureResult.isNotDownloaded()) {
194-
if (context.settingsStore.allowUnsignedBinaryWithoutPrompt) {
195+
if (context.settingsStore.fallbackOnCoderForSignatures == ALLOW) {
195196
context.logger.warn("Running unsigned CLI from ${cliResult.source}")
196197
downloader.commit()
197198
return true

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.coder.toolbox.settings
22

33
import java.net.URL
44
import java.nio.file.Path
5+
import java.util.Locale.getDefault
56

67
/**
78
* Read-only interface for accessing Coder settings
@@ -28,10 +29,9 @@ interface ReadOnlyCoderSettings {
2829
val binaryDirectory: String?
2930

3031
/**
31-
* Controls whether we run the unsigned binary or we prompt
32-
* the user for input.
32+
* Controls whether we fall back release.coder.com
3333
*/
34-
val allowUnsignedBinaryWithoutPrompt: Boolean
34+
val fallbackOnCoderForSignatures: SignatureFallbackStrategy
3535

3636
/**
3737
* Default CLI binary name based on OS and architecture
@@ -178,4 +178,32 @@ interface ReadOnlyTLSSettings {
178178
* Coder service does not match the hostname in the TLS certificate.
179179
*/
180180
val altHostname: String?
181+
}
182+
183+
enum class SignatureFallbackStrategy {
184+
/**
185+
* User has not yet decided whether he wants to fallback on releases.coder.com for signatures
186+
*/
187+
NOT_CONFIGURED,
188+
189+
/**
190+
* Can fall back on releases.coder.com for signatures.
191+
*/
192+
ALLOW,
193+
194+
/**
195+
* Can't fall back on releases.coder.com for signatures.
196+
*/
197+
FORBIDDEN;
198+
199+
fun isAllowed(): Boolean = this == ALLOW
200+
201+
companion object {
202+
fun fromValue(value: String?): SignatureFallbackStrategy = when (value?.lowercase(getDefault())) {
203+
"not_configured" -> NOT_CONFIGURED
204+
"allow" -> ALLOW
205+
"forbidden" -> FORBIDDEN
206+
else -> NOT_CONFIGURED
207+
}
208+
}
181209
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.coder.toolbox.store
33
import com.coder.toolbox.settings.Environment
44
import com.coder.toolbox.settings.ReadOnlyCoderSettings
55
import com.coder.toolbox.settings.ReadOnlyTLSSettings
6+
import com.coder.toolbox.settings.SignatureFallbackStrategy
67
import com.coder.toolbox.util.Arch
78
import com.coder.toolbox.util.OS
89
import com.coder.toolbox.util.expand
@@ -37,8 +38,8 @@ class CoderSettingsStore(
3738
override val defaultURL: String get() = store[DEFAULT_URL] ?: "https://dev.coder.com"
3839
override val binarySource: String? get() = store[BINARY_SOURCE]
3940
override val binaryDirectory: String? get() = store[BINARY_DIRECTORY]
40-
override val allowUnsignedBinaryWithoutPrompt: Boolean
41-
get() = store[ALLOW_UNSIGNED_BINARY_EXEC]?.toBooleanStrictOrNull() ?: false
41+
override val fallbackOnCoderForSignatures: SignatureFallbackStrategy
42+
get() = SignatureFallbackStrategy.fromValue(store[FALLBACK_ON_CODER_FOR_SIGNATURES])
4243
override val defaultCliBinaryNameByOsAndArch: String get() = getCoderCLIForOS(getOS(), getArch())
4344
override val binaryName: String get() = store[BINARY_NAME] ?: getCoderCLIForOS(getOS(), getArch())
4445
override val defaultSignatureNameByOsAndArch: String get() = getCoderSignatureForOS(getOS(), getArch())
@@ -161,8 +162,11 @@ class CoderSettingsStore(
161162
store[ENABLE_DOWNLOADS] = shouldEnableDownloads.toString()
162163
}
163164

164-
fun updateAllowUnsignedBinaryExec(allowUnsignedBinaryExec: Boolean) {
165-
store[ALLOW_UNSIGNED_BINARY_EXEC] = allowUnsignedBinaryExec.toString()
165+
fun updateSignatureFallbackStrategy(fallback: Boolean) {
166+
store[FALLBACK_ON_CODER_FOR_SIGNATURES] = when (fallback) {
167+
true -> SignatureFallbackStrategy.ALLOW.toString()
168+
else -> SignatureFallbackStrategy.FORBIDDEN.toString()
169+
}
166170
}
167171

168172
fun updateBinaryDirectoryFallback(shouldEnableBinDirFallback: Boolean) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal const val BINARY_SOURCE = "binarySource"
1010

1111
internal const val BINARY_DIRECTORY = "binaryDirectory"
1212

13-
internal const val ALLOW_UNSIGNED_BINARY_EXEC = "allowUnsignedBinaryExec"
13+
internal const val FALLBACK_ON_CODER_FOR_SIGNATURES = "signatureFallbackStrategy"
1414

1515
internal const val BINARY_NAME = "binaryName"
1616

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ class CoderSettingsPage(context: CoderToolboxContext, triggerSshConfig: Channel<
3232
TextField(context.i18n.ptrl("Data directory"), settings.dataDirectory ?: "", TextType.General)
3333
private val enableDownloadsField =
3434
CheckboxField(settings.enableDownloads, context.i18n.ptrl("Enable downloads"))
35-
private val allowUnsignedBinaryExecField =
35+
private val signatureFallbackStrategyField =
3636
CheckboxField(
37-
settings.allowUnsignedBinaryWithoutPrompt,
38-
context.i18n.ptrl("Allow unsigned binary execution without prompt")
37+
settings.fallbackOnCoderForSignatures.isAllowed(),
38+
context.i18n.ptrl("Fallback on releases.coder.com when CLI signatures can't be found")
3939
)
4040
private val enableBinaryDirectoryFallbackField =
4141
CheckboxField(
@@ -71,7 +71,7 @@ class CoderSettingsPage(context: CoderToolboxContext, triggerSshConfig: Channel<
7171
enableDownloadsField,
7272
binaryDirectoryField,
7373
enableBinaryDirectoryFallbackField,
74-
allowUnsignedBinaryExecField,
74+
signatureFallbackStrategyField,
7575
dataDirectoryField,
7676
headerCommandField,
7777
tlsCertPathField,
@@ -93,7 +93,7 @@ class CoderSettingsPage(context: CoderToolboxContext, triggerSshConfig: Channel<
9393
context.settingsStore.updateBinaryDirectory(binaryDirectoryField.textState.value)
9494
context.settingsStore.updateDataDirectory(dataDirectoryField.textState.value)
9595
context.settingsStore.updateEnableDownloads(enableDownloadsField.checkedState.value)
96-
context.settingsStore.updateAllowUnsignedBinaryExec(allowUnsignedBinaryExecField.checkedState.value)
96+
context.settingsStore.updateSignatureFallbackStrategy(signatureFallbackStrategyField.checkedState.value)
9797
context.settingsStore.updateBinaryDirectoryFallback(enableBinaryDirectoryFallbackField.checkedState.value)
9898
context.settingsStore.updateHeaderCommand(headerCommandField.textState.value)
9999
context.settingsStore.updateCertPath(tlsCertPathField.textState.value)

src/main/resources/localization/defaultMessages.po

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ msgstr ""
7979
msgid "Enable downloads"
8080
msgstr ""
8181

82-
msgid "Allow unsigned binary execution without prompt"
82+
msgid "Fallback on releases.coder.com when CLI signatures can't be found"
8383
msgstr ""
8484

8585
msgid "Enable binary directory fallback"

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import com.coder.toolbox.cli.ex.SSHConfigFormatException
77
import com.coder.toolbox.sdk.DataGen.Companion.workspace
88
import com.coder.toolbox.sdk.v2.models.Workspace
99
import com.coder.toolbox.settings.Environment
10-
import com.coder.toolbox.store.ALLOW_UNSIGNED_BINARY_EXEC
1110
import com.coder.toolbox.store.BINARY_DIRECTORY
1211
import com.coder.toolbox.store.BINARY_NAME
1312
import com.coder.toolbox.store.BINARY_SOURCE
@@ -18,6 +17,7 @@ import com.coder.toolbox.store.DATA_DIRECTORY
1817
import com.coder.toolbox.store.DISABLE_AUTOSTART
1918
import com.coder.toolbox.store.ENABLE_BINARY_DIR_FALLBACK
2019
import com.coder.toolbox.store.ENABLE_DOWNLOADS
20+
import com.coder.toolbox.store.FALLBACK_ON_CODER_FOR_SIGNATURES
2121
import com.coder.toolbox.store.HEADER_COMMAND
2222
import com.coder.toolbox.store.NETWORK_INFO_DIR
2323
import com.coder.toolbox.store.SSH_CONFIG_OPTIONS
@@ -226,7 +226,7 @@ internal class CoderCLIManagerTest {
226226
settingsStore = CoderSettingsStore(
227227
pluginTestSettingsStore(
228228
DATA_DIRECTORY to tmpdir.resolve("real-cli").toString(),
229-
ALLOW_UNSIGNED_BINARY_EXEC to "true",
229+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow",
230230
),
231231
Environment(),
232232
context.logger
@@ -257,7 +257,7 @@ internal class CoderCLIManagerTest {
257257
pluginTestSettingsStore(
258258
BINARY_NAME to "coder.bat",
259259
DATA_DIRECTORY to tmpdir.resolve("mock-cli").toString(),
260-
ALLOW_UNSIGNED_BINARY_EXEC to "true",
260+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow",
261261
),
262262
Environment(),
263263
context.logger,
@@ -279,7 +279,7 @@ internal class CoderCLIManagerTest {
279279
pluginTestSettingsStore(
280280
BINARY_SOURCE to "/bin/override",
281281
DATA_DIRECTORY to tmpdir.resolve("mock-cli").toString(),
282-
ALLOW_UNSIGNED_BINARY_EXEC to "true",
282+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow",
283283
),
284284
Environment(),
285285
context.logger
@@ -322,7 +322,7 @@ internal class CoderCLIManagerTest {
322322
context.copy(
323323
settingsStore = CoderSettingsStore(
324324
pluginTestSettingsStore(
325-
ALLOW_UNSIGNED_BINARY_EXEC to "true",
325+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow",
326326
DATA_DIRECTORY to tmpdir.resolve("overwrite-cli").toString(),
327327
),
328328
Environment(),
@@ -356,7 +356,7 @@ internal class CoderCLIManagerTest {
356356
val settings = CoderSettingsStore(
357357
pluginTestSettingsStore(
358358
DATA_DIRECTORY to tmpdir.resolve("clobber-cli").toString(),
359-
ALLOW_UNSIGNED_BINARY_EXEC to "true"
359+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow"
360360
),
361361
Environment(),
362362
context.logger
@@ -869,7 +869,7 @@ internal class CoderCLIManagerTest {
869869
ENABLE_BINARY_DIR_FALLBACK to it.enableFallback.toString(),
870870
DATA_DIRECTORY to tmpdir.resolve("ensure-data-dir").toString(),
871871
BINARY_DIRECTORY to tmpdir.resolve("ensure-bin-dir").toString(),
872-
ALLOW_UNSIGNED_BINARY_EXEC to "true"
872+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow"
873873
),
874874
Environment(),
875875
context.logger
@@ -970,7 +970,7 @@ internal class CoderCLIManagerTest {
970970
pluginTestSettingsStore(
971971
BINARY_NAME to "coder.bat",
972972
DATA_DIRECTORY to tmpdir.resolve("features").toString(),
973-
ALLOW_UNSIGNED_BINARY_EXEC to "true"
973+
FALLBACK_ON_CODER_FOR_SIGNATURES to "allow"
974974
),
975975
Environment(),
976976
context.logger,

0 commit comments

Comments
 (0)