From 54f3404e848a6dc8a0ea89cdc9265bee5e61cea5 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Wed, 5 Mar 2025 16:57:10 -0800 Subject: [PATCH 1/2] Retrieve workspace directly in link handler when using wildcardSSH feature Instead of listing all workspaces matching the filter, get info about the specific workspace the user is trying to connect to. This lets jetbrains-gateway:// links to others' workspaces work without needing to modify the workspace filter parameter. --- .../com/coder/gateway/sdk/CoderRestClient.kt | 13 ++++++ .../coder/gateway/sdk/v2/CoderV2RestFacade.kt | 10 +++++ .../com/coder/gateway/util/LinkHandler.kt | 40 ++++++++++--------- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt index 40d5934a3..71c6e1baf 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt @@ -176,6 +176,19 @@ open class CoderRestClient( return workspacesResponse.body()!!.workspaces } + /** + * Retrieves a specific workspace by owner and name. + * @throws [APIResponseException]. + */ + fun workspaceByOwnerAndName(owner: String, workspaceName: String): Workspace { + val workspaceResponse = retroRestClient.workspaceByOwnerAndName(owner, workspaceName).execute() + if (!workspaceResponse.isSuccessful) { + throw APIResponseException("retrieve workspace", url, workspaceResponse) + } + + return workspaceResponse.body()!! + } + /** * Retrieves all the agent names for all workspaces, including those that * are off. Meant to be used when configuring SSH. diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt index b610a3147..81976ed89 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt @@ -4,6 +4,7 @@ import com.coder.gateway.sdk.v2.models.BuildInfo import com.coder.gateway.sdk.v2.models.CreateWorkspaceBuildRequest import com.coder.gateway.sdk.v2.models.Template import com.coder.gateway.sdk.v2.models.User +import com.coder.gateway.sdk.v2.models.Workspace import com.coder.gateway.sdk.v2.models.WorkspaceBuild import com.coder.gateway.sdk.v2.models.WorkspaceResource import com.coder.gateway.sdk.v2.models.WorkspacesResponse @@ -22,6 +23,15 @@ interface CoderV2RestFacade { @GET("api/v2/users/me") fun me(): Call + /** + * Retrieves a specific workspace by owner and name. + */ + @GET("api/v2/users/{user}/workspace/{workspace}") + fun workspaceByOwnerAndName( + @Path("user") user: String, + @Path("workspace") workspace: String, + ): Call + /** * Retrieves all workspaces the authenticated user has access to. */ diff --git a/src/main/kotlin/com/coder/gateway/util/LinkHandler.kt b/src/main/kotlin/com/coder/gateway/util/LinkHandler.kt index fbd5584bb..c32a136e0 100644 --- a/src/main/kotlin/com/coder/gateway/util/LinkHandler.kt +++ b/src/main/kotlin/com/coder/gateway/util/LinkHandler.kt @@ -57,11 +57,27 @@ open class LinkHandler( // owner is included, assume the current user. val owner = (parameters.owner() ?: client.me.username).ifBlank { client.me.username } - val workspaces = client.workspaces() - val workspace = - workspaces.firstOrNull { - it.ownerName == owner && it.name == workspaceName - } ?: throw IllegalArgumentException("The workspace $workspaceName does not exist") + val cli = + ensureCLI( + deploymentURL.toURL(), + client.buildInfo().version, + settings, + indicator, + ) + + var workspace : Workspace + var workspaces : List = emptyList() + var workspacesAndAgents : Set> = emptySet() + if (cli.features.wildcardSSH) { + workspace = client.workspaceByOwnerAndName(owner, workspaceName) + } else { + workspaces = client.workspaces() + workspace = + workspaces.firstOrNull { + it.ownerName == owner && it.name == workspaceName + } ?: throw IllegalArgumentException("The workspace $workspaceName does not exist") + workspacesAndAgents = client.withAgents(workspaces) + } when (workspace.latestBuild.status) { WorkspaceStatus.PENDING, WorkspaceStatus.STARTING -> @@ -96,14 +112,6 @@ open class LinkHandler( throw IllegalArgumentException("The agent \"${agent.name}\" has a status of \"${status.toString().lowercase()}\"; unable to connect") } - val cli = - ensureCLI( - deploymentURL.toURL(), - client.buildInfo().version, - settings, - indicator, - ) - // We only need to log in if we are using token-based auth. if (client.token != null) { indicator?.invoke("Authenticating Coder CLI...") @@ -111,11 +119,7 @@ open class LinkHandler( } indicator?.invoke("Configuring Coder CLI...") - if (cli.features.wildcardSSH) { - cli.configSsh(workspacesAndAgents = emptySet(), currentUser = client.me) - } else { - cli.configSsh(workspacesAndAgents = client.withAgents(workspaces), currentUser = client.me) - } + cli.configSsh(workspacesAndAgents, currentUser = client.me) val openDialog = parameters.ideProductCode().isNullOrBlank() || From 6722a557b5f2ddb39f8559e82cb5ea08630a149f Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 6 Mar 2025 21:43:05 -0600 Subject: [PATCH 2/2] changelog update --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52baa52ff..5782292d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ## Unreleased +### Changed + +Retrieve workspace directly in link handler when using wildcardSSH feature + ## 2.19.0 - 2025-02-21 ### Added