Skip to content

impl: verify cli signature #148

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

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4227ebd
impl: new UI setting for running unsigned binary execution
fioan89 Jul 8, 2025
021e53a
chore: refactor CLI downloading logic
fioan89 Jul 9, 2025
fb6e784
impl: support for downloading the cli signature
fioan89 Jul 9, 2025
dbf8560
impl: support for downloading the releases.coder.com signature
fioan89 Jul 10, 2025
6754300
fix: read fresh values from the config store
fioan89 Jul 10, 2025
8d768ee
impl: prompt user when running unsigned binaries
fioan89 Jul 10, 2025
ea3e379
fix: used proper result to verify if signature is downloaded
fioan89 Jul 10, 2025
3668d46
chore: compact code and run signature download on the IO thread
fioan89 Jul 10, 2025
a476364
chore: add support for bouncycastle
fioan89 Jul 10, 2025
45a72fb
chore: update i18n bundle with new strings related to signature verif…
fioan89 Jul 10, 2025
ad44346
impl: verify gpg signed cli binaries
fioan89 Jul 10, 2025
4cd5148
impl: embed the pgp public key as a plugin resource
fioan89 Jul 11, 2025
fbe68de
impl: load the public key from a resource file
fioan89 Jul 11, 2025
270b949
impl: run the signature verification on the IO thread
fioan89 Jul 11, 2025
d5ae289
fix: find the key id in multiple key rings
fioan89 Jul 11, 2025
96663e6
fix: remove the cli if it is not properly signed
fioan89 Jul 11, 2025
6a79995
fix: avoid out of memory when verifying signatures
fioan89 Jul 11, 2025
5fcb4b9
fix: don't run signature verification
fioan89 Jul 11, 2025
3543377
chore: fix UTs
fioan89 Jul 11, 2025
0a5de76
Merge branch 'main' into impl-verify-cli-signature
fioan89 Jul 11, 2025
97dbc8d
chore: next version is 0.5.0
fioan89 Jul 11, 2025
27066d8
fix: more UTs
fioan89 Jul 11, 2025
811fc85
fix: display errors that happened while handling URIs
fioan89 Jul 14, 2025
9851dec
impl: check if the cli exists before running it to spill out the version
fioan89 Jul 14, 2025
306848f
impl: download retroactive cli signatures from releases.coder.com/cod…
fioan89 Jul 14, 2025
5dcdff0
fix: UTs after fallback to signatures from releases.coder.com were pu…
fioan89 Jul 14, 2025
5bf0792
chore: refactor code around signature name
fioan89 Jul 14, 2025
bce103b
chore: remove code around URL building
fioan89 Jul 14, 2025
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 @@ -5,6 +5,7 @@
### Added

- support for matching workspace agent in the URI via the agent name
- support for checking if CLI is signed

### Removed

Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ dependencies {
ksp(libs.moshi.codegen)
implementation(libs.retrofit)
implementation(libs.retrofit.moshi)
implementation(libs.bundles.bouncycastle)
testImplementation(kotlin("test"))
testImplementation(libs.mokk)
testImplementation(libs.bundles.toolbox.plugin.api)
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
version=0.4.0
version=0.5.0
group=com.coder.toolbox
name=coder-toolbox
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ gettext = "0.7.0"
plugin-structure = "3.310"
mockk = "1.14.4"
detekt = "1.23.7"
bouncycastle = "1.81"

[libraries]
toolbox-core-api = { module = "com.jetbrains.toolbox:core-api", version.ref = "toolbox-plugin-api" }
Expand All @@ -34,10 +35,13 @@ retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.re
plugin-structure = { module = "org.jetbrains.intellij.plugins:structure-toolbox", version.ref = "plugin-structure" }
mokk = { module = "io.mockk:mockk", version.ref = "mockk" }
marketplace-client = { module = "org.jetbrains.intellij:plugin-repository-rest-client", version.ref = "marketplace-client" }
bouncycastle-bcpg = { module = "org.bouncycastle:bcpg-jdk18on", version.ref = "bouncycastle" }
bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "bouncycastle" }

[bundles]
serialization = ["serialization-core", "serialization-json", "serialization-json-okio"]
toolbox-plugin-api = ["toolbox-core-api", "toolbox-ui-api", "toolbox-remote-dev-api"]
bouncycastle = ["bouncycastle-bcpg", "bouncycastle-bcprov"]

[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
Expand Down
59 changes: 40 additions & 19 deletions src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.onTimeout
import kotlinx.coroutines.selects.select
import java.net.URI
import java.util.UUID
import kotlin.coroutines.cancellation.CancellationException
import kotlin.time.Duration.Companion.seconds
import kotlin.time.TimeSource
Expand Down Expand Up @@ -302,31 +303,51 @@ class CoderRemoteProvider(
* Handle incoming links (like from the dashboard).
*/
override suspend fun handleUri(uri: URI) {
linkHandler.handle(
uri, shouldDoAutoSetup(),
{
coderHeaderPage.isBusyCreatingNewEnvironment.update {
true
try {
linkHandler.handle(
uri, shouldDoAutoSetup(),
{
coderHeaderPage.isBusyCreatingNewEnvironment.update {
true
}
},
{
coderHeaderPage.isBusyCreatingNewEnvironment.update {
false
}
}
},
{
coderHeaderPage.isBusyCreatingNewEnvironment.update {
) { restClient, cli ->
// stop polling and de-initialize resources
close()
isInitialized.update {
false
}
// start initialization with the new settings
this@CoderRemoteProvider.client = restClient
coderHeaderPage.setTitle(context.i18n.pnotr(restClient.url.toString()))

environments.showLoadingMessage()
pollJob = poll(restClient, cli)
isInitialized.waitForTrue()
}
) { restClient, cli ->
// stop polling and de-initialize resources
close()
isInitialized.update {
} catch (ex: Exception) {
context.logger.error(ex, "")
val textError = if (ex is APIResponseException) {
if (!ex.reason.isNullOrBlank()) {
ex.reason
} else ex.message
} else ex.message

context.ui.showSnackbar(
UUID.randomUUID().toString(),
context.i18n.ptrl("Error encountered while handling Coder URI"),
context.i18n.pnotr(textError ?: ""),
context.i18n.ptrl("Dismiss")
)
} finally {
coderHeaderPage.isBusyCreatingNewEnvironment.update {
false
}
// start initialization with the new settings
this@CoderRemoteProvider.client = restClient
coderHeaderPage.setTitle(context.i18n.pnotr(restClient.url.toString()))

environments.showLoadingMessage()
pollJob = poll(restClient, cli)
isInitialized.waitForTrue()
}
}

Expand Down
Loading
Loading