fix: infer workspace from env in coder support bundle (#24617)

When running `coder support bundle` inside a workspace without arguments, the command now infers the workspace and agent from the `CODER_WORKSPACE_NAME`, `CODER_WORKSPACE_OWNER_NAME`, and `CODER_WORKSPACE_AGENT_NAME` environment variables set by the workspace agent.

Previously, running without arguments inside a workspace produced an incomplete bundle with no workspace info, agent logs, or connection diagnostics, despite the environment having all the information needed to resolve the current workspace.

Also updates the usage string from `<workspace>` to `[<workspace>]` to reflect that the argument has always been optional.

Closes #24615
This commit is contained in:
Ehab Younes
2026-04-22 17:21:28 +03:00
committed by GitHub
parent 9b5d09ebdc
commit 3362b5ae7e
4 changed files with 77 additions and 7 deletions
+34 -2
View File
@@ -71,9 +71,9 @@ func (r *RootCmd) supportBundle() *serpent.Command {
var templateName string
var pprof bool
cmd := &serpent.Command{
Use: "bundle <workspace> [<agent>]",
Use: "bundle [<workspace>] [<agent>]",
Short: "Generate a support bundle to troubleshoot issues connecting to a workspace.",
Long: `This command generates a file containing detailed troubleshooting information about the Coder deployment and workspace connections. You must specify a single workspace (and optionally an agent name).`,
Long: `This command generates a file containing detailed troubleshooting information about the Coder deployment and workspace connections. You may specify a single workspace (and optionally an agent name). When run inside a workspace, the workspace and agent are inferred from the environment if not provided.`,
Middleware: serpent.Chain(
serpent.RequireRangeArgs(0, 2),
),
@@ -149,6 +149,38 @@ func (r *RootCmd) supportBundle() *serpent.Command {
templateID uuid.UUID
)
if len(inv.Args) == 0 {
// When running inside a workspace, infer the workspace
// and agent from environment variables set by the agent.
// Prefer CODER_WORKSPACE_ID for a direct UUID lookup;
// fall back to owner/name for older agents that do not
// set the ID variable.
if inv.Environ.Get("CODER") == "true" {
var wsArg string
if v := inv.Environ.Get("CODER_WORKSPACE_ID"); v != "" {
wsArg = v
} else {
wsOwner := inv.Environ.Get("CODER_WORKSPACE_OWNER_NAME")
wsName := inv.Environ.Get("CODER_WORKSPACE_NAME")
if wsOwner != "" && wsName != "" {
wsArg = wsOwner + "/" + wsName
}
}
agtName := inv.Environ.Get("CODER_WORKSPACE_AGENT_NAME")
if wsArg != "" {
cliLog.Info(inv.Context(), "detected workspace from environment",
slog.F("workspace_arg", wsArg),
slog.F("agent_name", agtName),
)
cliui.Info(inv.Stderr, "Detected workspace from environment: "+wsArg)
inv.Args = append(inv.Args, wsArg)
if agtName != "" {
inv.Args = append(inv.Args, agtName)
}
}
}
}
if len(inv.Args) == 0 {
cliLog.Warn(inv.Context(), "no workspace specified")
cliui.Warn(inv.Stderr, "No workspace specified. This will result in incomplete information.")
+37
View File
@@ -118,6 +118,43 @@ func TestSupportBundle(t *testing.T) {
assertBundleContents(t, path, false, false, []string{secretValue})
})
t.Run("InferWorkspaceFromEnvByID", func(t *testing.T) {
t.Parallel()
d := t.TempDir()
path := filepath.Join(d, "bundle.zip")
// No workspace arg, but set env vars as if inside a workspace.
inv, root := clitest.New(t, "support", "bundle", "--output-file", path, "--yes")
inv.Environ.Set("CODER", "true")
inv.Environ.Set("CODER_WORKSPACE_ID", workspaceWithoutAgent.Workspace.ID.String())
inv.Environ.Set("CODER_WORKSPACE_AGENT_NAME", "dev")
//nolint: gocritic // requires owner privilege
clitest.SetupConfig(t, client, root)
err := inv.Run()
require.NoError(t, err)
// The workspace should be resolved, but there is no running agent.
assertBundleContents(t, path, true, false, []string{secretValue})
})
t.Run("InferWorkspaceFromEnvByName", func(t *testing.T) {
t.Parallel()
d := t.TempDir()
path := filepath.Join(d, "bundle.zip")
// No workspace arg and no CODER_WORKSPACE_ID; fall back to
// owner/name resolution for older agents.
inv, root := clitest.New(t, "support", "bundle", "--output-file", path, "--yes")
inv.Environ.Set("CODER", "true")
inv.Environ.Set("CODER_WORKSPACE_NAME", workspaceWithoutAgent.Workspace.Name)
inv.Environ.Set("CODER_WORKSPACE_OWNER_NAME", coderdtest.FirstUserParams.Username)
inv.Environ.Set("CODER_WORKSPACE_AGENT_NAME", "dev")
//nolint: gocritic // requires owner privilege
clitest.SetupConfig(t, client, root)
err := inv.Run()
require.NoError(t, err)
assertBundleContents(t, path, true, false, []string{secretValue})
})
t.Run("NoAgent", func(t *testing.T) {
t.Parallel()
d := t.TempDir()
+4 -3
View File
@@ -1,13 +1,14 @@
coder v0.0.0-devel
USAGE:
coder support bundle [flags] <workspace> [<agent>]
coder support bundle [flags] [<workspace>] [<agent>]
Generate a support bundle to troubleshoot issues connecting to a workspace.
This command generates a file containing detailed troubleshooting information
about the Coder deployment and workspace connections. You must specify a
single workspace (and optionally an agent name).
about the Coder deployment and workspace connections. You may specify a single
workspace (and optionally an agent name). When run inside a workspace, the
workspace and agent are inferred from the environment if not provided.
OPTIONS:
-O, --output-file string, $CODER_SUPPORT_BUNDLE_OUTPUT_FILE
+2 -2
View File
@@ -6,13 +6,13 @@ Generate a support bundle to troubleshoot issues connecting to a workspace.
## Usage
```console
coder support bundle [flags] <workspace> [<agent>]
coder support bundle [flags] [<workspace>] [<agent>]
```
## Description
```console
This command generates a file containing detailed troubleshooting information about the Coder deployment and workspace connections. You must specify a single workspace (and optionally an agent name).
This command generates a file containing detailed troubleshooting information about the Coder deployment and workspace connections. You may specify a single workspace (and optionally an agent name). When run inside a workspace, the workspace and agent are inferred from the environment if not provided.
```
## Options