🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

Commit c15ae01

Browse files
fix: redact env var values in agent debug manifest endpoint (#26904) (#27880)
Backport of #26904 Original PR: #26904 — fix: redact env var values in agent debug manifest endpoint Merge commit: b33ff2d Requested by: @jdomeracki-coder <details> <summary>Conflict resolution notes</summary> The cherry-pick conflicted in `agent/agent.go` because the new `redactedManifestEnvValue` constant landed where `release/2.34` has the `HandleHTTPDebugLogs` handler. Resolved by keeping both: the existing handler and the new constant. The manifest env-redaction block applied cleanly. The `./agent/...` package builds successfully. </details> --- _Opened by Coder Agents on behalf of @jdomeracki-coder._ Co-authored-by: Jon Ayers <jon@coder.com>
1 parent 85bcd5d commit c15ae01

2 files changed

Lines changed: 55 additions & 1 deletion

File tree

agent/agent.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2148,8 +2148,26 @@ func (a *agent) HandleHTTPDebugManifest(w http.ResponseWriter, r *http.Request)
21482148
return
21492149
}
21502150

2151+
// Redact env values. This endpoint is unauthenticated on loopback,
2152+
// reachable by any process regardless of Unix user. Keys are preserved
2153+
// so operators can still see which variables are configured.
2154+
debugManifest := *sdkManifest
2155+
if len(sdkManifest.EnvironmentVariables) > 0 {
2156+
envs := make(map[string]string, len(sdkManifest.EnvironmentVariables))
2157+
for k, v := range sdkManifest.EnvironmentVariables {
2158+
// Preserve empty values, which carry no secret, matching
2159+
// sanitizeEnv in support/support.go.
2160+
if v == "" {
2161+
envs[k] = v
2162+
continue
2163+
}
2164+
envs[k] = redactedManifestEnvValue
2165+
}
2166+
debugManifest.EnvironmentVariables = envs
2167+
}
2168+
21512169
w.WriteHeader(http.StatusOK)
2152-
if err := json.NewEncoder(w).Encode(sdkManifest); err != nil {
2170+
if err := json.NewEncoder(w).Encode(debugManifest); err != nil {
21532171
a.logger.Error(a.hardCtx, "write debug manifest", slog.Error(err))
21542172
}
21552173
}
@@ -2174,6 +2192,10 @@ func (a *agent) HandleHTTPDebugLogs(w http.ResponseWriter, r *http.Request) {
21742192
}
21752193
}
21762194

2195+
// redactedManifestEnvValue matches the marker used by sanitizeEnv in
2196+
// support/support.go so a support bundle and this endpoint agree.
2197+
const redactedManifestEnvValue = "***REDACTED***"
2198+
21772199
func (a *agent) HTTPDebug() http.Handler {
21782200
r := chi.NewRouter()
21792201

agent/agent_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,6 +3519,10 @@ func TestAgent_DebugServer(t *testing.T) {
35193519
//nolint:dogsled
35203520
conn, _, _, _, agnt := setupAgentWithSecrets(t, agentsdk.Manifest{
35213521
DERPMap: derpMap,
3522+
EnvironmentVariables: map[string]string{
3523+
"AWS_SECRET_ACCESS_KEY": "env-value-should-be-redacted-67890",
3524+
"EMPTY_VAR": "",
3525+
},
35223526
}, []agentsdk.WorkspaceSecret{
35233527
{EnvName: "DEBUG_SECRET", Value: []byte("super-secret-value-12345")},
35243528
}, 0, func(c *agenttest.Client, o *agent.Options) {
@@ -3647,6 +3651,34 @@ func TestAgent_DebugServer(t *testing.T) {
36473651
require.NoError(t, json.Unmarshal(body, &v))
36483652
})
36493653

3654+
t.Run("ManifestEnvVarValuesRedacted", func(t *testing.T) {
3655+
t.Parallel()
3656+
3657+
ctx := testutil.Context(t, testutil.WaitLong)
3658+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/debug/manifest", nil)
3659+
require.NoError(t, err)
3660+
3661+
res, err := srv.Client().Do(req)
3662+
require.NoError(t, err)
3663+
defer res.Body.Close()
3664+
require.Equal(t, http.StatusOK, res.StatusCode)
3665+
3666+
body, err := io.ReadAll(res.Body)
3667+
require.NoError(t, err)
3668+
3669+
require.NotContains(t, string(body), "env-value-should-be-redacted-67890")
3670+
3671+
var v agentsdk.Manifest
3672+
require.NoError(t, json.Unmarshal(body, &v))
3673+
3674+
require.Contains(t, v.EnvironmentVariables, "AWS_SECRET_ACCESS_KEY")
3675+
require.Equal(t, "***REDACTED***", v.EnvironmentVariables["AWS_SECRET_ACCESS_KEY"])
3676+
3677+
// Empty values carry no secret and are preserved as empty.
3678+
require.Contains(t, v.EnvironmentVariables, "EMPTY_VAR")
3679+
require.Equal(t, "", v.EnvironmentVariables["EMPTY_VAR"])
3680+
})
3681+
36503682
t.Run("Logs", func(t *testing.T) {
36513683
t.Parallel()
36523684

0 commit comments

Comments
 (0)