Skip to content

impl: ssh config improvements #41

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

Merged
merged 21 commits into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1788632
impl: custom ssh config header block for toolbox plugin
fioan89 Mar 21, 2025
2a86abe
impl: report workspace usage under toolbox
fioan89 Mar 21, 2025
270fa89
impl: change hostname in ssh config to reflect toolbox plugin
fioan89 Mar 21, 2025
d3968ae
fix: update tests with to reflect the changes to the ssh parameters
fioan89 Mar 21, 2025
6a3491d
fix: ssh header block as `JETBRAINS TOOLBOX`
fioan89 Mar 24, 2025
3a8738c
refactor: expose typed settings and secrets store
fioan89 Mar 24, 2025
1da3f4b
impl: don't start the workspace automatically if disable-autostart is…
fioan89 Mar 24, 2025
a104721
fix: force window to show when error dialogs pops-up
fioan89 Mar 24, 2025
d885c60
fix: resiliency when REST call to start the workspace fail
fioan89 Mar 24, 2025
0bdd3ff
fix: resiliency when workspace agent is not ready
fioan89 Mar 24, 2025
2929b0e
refactor: reuse block of code
fioan89 Mar 24, 2025
1708944
impl: rework the settings models
fioan89 Mar 26, 2025
a47e4b2
impl: support for ssh wildcard config
fioan89 Mar 26, 2025
b183af0
fix: missing i18n strings
fioan89 Mar 26, 2025
de8f9f0
impl: change plugin's display name
fioan89 Mar 26, 2025
71cabd1
chore: revert --usage-app
fioan89 Mar 26, 2025
67ec906
fix: test exercising the features available
fioan89 Mar 26, 2025
76bb8b8
fix: test assert raw string paths on different platforms
fioan89 Mar 26, 2025
a53684d
fix: add support for Toolbox 2.6.0.39689
fioan89 Mar 27, 2025
fd860d1
impl: enable wildcard config by default
fioan89 Mar 27, 2025
81eacfb
fix: provide the correct ssh host when wildcard ssh config is enabled
fioan89 Mar 27, 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
5 changes: 3 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ val extension = ExtensionJson(

version = properties("version"),
meta = ExtensionJsonMeta(
name = "Coder Toolbox",
name = "Coder",
description = "Connects your JetBrains IDE to Coder workspaces",
vendor = "Coder",
url = "https://github.com/coder/coder-jetbrains-toolbox-plugin",
Expand Down Expand Up @@ -145,7 +145,8 @@ fun CopySpec.fromCompileDependencies() {
"core-api",
"ui-api",
"annotations",
"localization-api"
"localization-api",
"slf4j-api"
).any { file.name.contains(it) }
}
},
Expand Down
7 changes: 6 additions & 1 deletion src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ class CoderRemoteEnvironment(
* have to do is provide it a host name.
*/
override suspend
fun getContentsView(): EnvironmentContentsView = EnvironmentView(client.url, workspace, agent)
fun getContentsView(): EnvironmentContentsView = EnvironmentView(
context.settingsStore.readOnly(),
client.url,
workspace,
agent
)

override val connectionRequest: MutableStateFlow<Boolean>? = MutableStateFlow(false)

Expand Down
47 changes: 21 additions & 26 deletions src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ package com.coder.toolbox
import com.coder.toolbox.cli.CoderCLIManager
import com.coder.toolbox.sdk.CoderRestClient
import com.coder.toolbox.sdk.v2.models.WorkspaceStatus
import com.coder.toolbox.services.CoderSecretsService
import com.coder.toolbox.services.CoderSettingsService
import com.coder.toolbox.settings.CoderSettings
import com.coder.toolbox.settings.Source
import com.coder.toolbox.settings.SettingSource
import com.coder.toolbox.util.CoderProtocolHandler
import com.coder.toolbox.util.DialogUi
import com.coder.toolbox.views.Action
Expand Down Expand Up @@ -46,12 +43,11 @@ class CoderRemoteProvider(
private var pollJob: Job? = null
private var lastEnvironments: Set<CoderRemoteEnvironment>? = null

private val cSettings = context.settingsStore.readOnly()

// Create our services from the Toolbox ones.
private val settingsService = CoderSettingsService(context.settingsStore)
private val settings: CoderSettings = CoderSettings(settingsService, context.logger)
private val secrets: CoderSecretsService = CoderSecretsService(context.secretsStore)
private val settingsPage: CoderSettingsPage = CoderSettingsPage(context, settingsService)
private val dialogUi = DialogUi(context, settings)
private val settingsPage: CoderSettingsPage = CoderSettingsPage(context)
private val dialogUi = DialogUi(context)

// The REST client, if we are signed in
private var client: CoderRestClient? = null
Expand All @@ -65,7 +61,7 @@ class CoderRemoteProvider(
private var firstRun = true
private val isInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
private var coderHeaderPage = NewEnvironmentPage(context, context.i18n.pnotr(getDeploymentURL()?.first ?: ""))
private val linkHandler = CoderProtocolHandler(context, settings, httpClient, dialogUi, isInitialized)
private val linkHandler = CoderProtocolHandler(context, httpClient, dialogUi, isInitialized)
override val environments: MutableStateFlow<LoadableState<List<RemoteProviderEnvironment>>> = MutableStateFlow(
LoadableState.Value(emptyList())
)
Expand Down Expand Up @@ -151,7 +147,7 @@ class CoderRemoteProvider(
private fun logout() {
// Keep the URL and token to make it easy to log back in, but set
// rememberMe to false so we do not try to automatically log in.
secrets.rememberMe = "false"
context.secrets.rememberMe = "false"
close()
}

Expand Down Expand Up @@ -272,9 +268,9 @@ class CoderRemoteProvider(
// When coming back to the application, authenticate immediately.
val autologin = shouldDoAutoLogin()
var autologinEx: Exception? = null
secrets.lastToken.let { lastToken ->
secrets.lastDeploymentURL.let { lastDeploymentURL ->
if (autologin && lastDeploymentURL.isNotBlank() && (lastToken.isNotBlank() || !settings.requireTokenAuth)) {
context.secrets.lastToken.let { lastToken ->
context.secrets.lastDeploymentURL.let { lastDeploymentURL ->
if (autologin && lastDeploymentURL.isNotBlank() && (lastToken.isNotBlank() || !cSettings.requireTokenAuth)) {
try {
return createConnectPage(URL(lastDeploymentURL), lastToken)
} catch (ex: Exception) {
Expand Down Expand Up @@ -309,7 +305,7 @@ class CoderRemoteProvider(
return null
}

private fun shouldDoAutoLogin(): Boolean = firstRun && secrets.rememberMe == "true"
private fun shouldDoAutoLogin(): Boolean = firstRun && context.secrets.rememberMe == "true"

/**
* Create a connect page that starts polling and resets the UI on success.
Expand All @@ -318,15 +314,14 @@ class CoderRemoteProvider(
context,
deploymentURL,
token,
settings,
httpClient,
::goToEnvironmentsPage,
) { client, cli ->
// Store the URL and token for use next time.
secrets.lastDeploymentURL = client.url.toString()
secrets.lastToken = client.token ?: ""
context.secrets.lastDeploymentURL = client.url.toString()
context.secrets.lastToken = client.token ?: ""
// Currently we always remember, but this could be made an option.
secrets.rememberMe = "true"
context.secrets.rememberMe = "true"
this.client = client
pollError = null
pollJob?.cancel()
Expand All @@ -343,11 +338,11 @@ class CoderRemoteProvider(
* 2. Token on disk for this deployment.
* 3. Global token for Coder, if it matches the deployment.
*/
private fun getToken(deploymentURL: URL): Pair<String, Source>? = secrets.lastToken.let {
if (it.isNotBlank() && secrets.lastDeploymentURL == deploymentURL.toString()) {
it to Source.LAST_USED
private fun getToken(deploymentURL: URL): Pair<String, SettingSource>? = context.secrets.lastToken.let {
if (it.isNotBlank() && context.secrets.lastDeploymentURL == deploymentURL.toString()) {
it to SettingSource.LAST_USED
} else {
settings.token(deploymentURL)
cSettings.token(deploymentURL)
}
}

Expand All @@ -361,11 +356,11 @@ class CoderRemoteProvider(
* 3. CODER_URL.
* 4. URL in global cli config.
*/
private fun getDeploymentURL(): Pair<String, Source>? = secrets.lastDeploymentURL.let {
private fun getDeploymentURL(): Pair<String, SettingSource>? = context.secrets.lastDeploymentURL.let {
if (it.isNotBlank()) {
it to Source.LAST_USED
it to SettingSource.LAST_USED
} else {
settings.defaultURL()
context.settingsStore.defaultURL()
}
}
}
8 changes: 4 additions & 4 deletions src/main/kotlin/com/coder/toolbox/CoderToolboxContext.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.coder.toolbox

import com.jetbrains.toolbox.api.core.PluginSecretStore
import com.jetbrains.toolbox.api.core.PluginSettingsStore
import com.coder.toolbox.store.CoderSecretsStore
import com.coder.toolbox.store.CoderSettingsStore
import com.jetbrains.toolbox.api.core.diagnostics.Logger
import com.jetbrains.toolbox.api.localization.LocalizableStringFactory
import com.jetbrains.toolbox.api.remoteDev.connection.ClientHelper
Expand All @@ -18,6 +18,6 @@ data class CoderToolboxContext(
val cs: CoroutineScope,
val logger: Logger,
val i18n: LocalizableStringFactory,
val settingsStore: PluginSettingsStore,
val secretsStore: PluginSecretStore
val settingsStore: CoderSettingsStore,
val secrets: CoderSecretsStore
)
8 changes: 6 additions & 2 deletions src/main/kotlin/com/coder/toolbox/CoderToolboxExtension.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.coder.toolbox

import com.coder.toolbox.settings.Environment
import com.coder.toolbox.store.CoderSecretsStore
import com.coder.toolbox.store.CoderSettingsStore
import com.jetbrains.toolbox.api.core.PluginSecretStore
import com.jetbrains.toolbox.api.core.PluginSettingsStore
import com.jetbrains.toolbox.api.core.ServiceLocator
Expand All @@ -20,6 +23,7 @@ import okhttp3.OkHttpClient
class CoderToolboxExtension : RemoteDevExtension {
// All services must be passed in here and threaded as necessary.
override fun createRemoteProviderPluginInstance(serviceLocator: ServiceLocator): RemoteProvider {
val logger = serviceLocator.getService(Logger::class.java)
return CoderRemoteProvider(
CoderToolboxContext(
serviceLocator.getService(ToolboxUi::class.java),
Expand All @@ -29,8 +33,8 @@ class CoderToolboxExtension : RemoteDevExtension {
serviceLocator.getService(CoroutineScope::class.java),
serviceLocator.getService(Logger::class.java),
serviceLocator.getService(LocalizableStringFactory::class.java),
serviceLocator.getService(PluginSettingsStore::class.java),
serviceLocator.getService(PluginSecretStore::class.java),
CoderSettingsStore(serviceLocator.getService(PluginSettingsStore::class.java), Environment(), logger),
CoderSecretsStore(serviceLocator.getService(PluginSecretStore::class.java)),
),
OkHttpClient(),
)
Expand Down
Loading
Loading