From 3639ea1892fb68272f12b3875a0d47811b712a6b Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 21 May 2026 06:43:44 +0000 Subject: [PATCH] fix: redact reflector stderr on failure --- internal/reflector/reflector.go | 3 ++- internal/reflector/reflector_test.go | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/reflector/reflector.go b/internal/reflector/reflector.go index bc6dafc..c5323c4 100644 --- a/internal/reflector/reflector.go +++ b/internal/reflector/reflector.go @@ -68,7 +68,8 @@ func (ExecRunner) Run(ctx context.Context, command string, args []string) (strin cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - return "", fmt.Errorf("run reflector command: %w: %s", err, truncate(stderr.String(), 2048)) + redactedStderr := truncate(Redact(stderr.String()), 2048) + return "", fmt.Errorf("run reflector command: %w: %s", err, redactedStderr) } return stdout.String(), nil } diff --git a/internal/reflector/reflector_test.go b/internal/reflector/reflector_test.go index 619f6dc..45905d2 100644 --- a/internal/reflector/reflector_test.go +++ b/internal/reflector/reflector_test.go @@ -174,6 +174,26 @@ func TestExecRunnerMarksReflectorActive(t *testing.T) { } } +func TestExecRunnerRedactsStderrOnFailure(t *testing.T) { + _, err := ExecRunner{}.Run(context.Background(), "sh", []string{ + "-c", + "printf 'reflector failed with CUSTOM_SECRET=not-for-logs and API_KEY=test-api-key-value' >&2; exit 7", + }) + if err == nil { + t.Fatal("Run returned nil error, want failure") + } + + errorText := err.Error() + for _, leaked := range []string{"not-for-logs", "test-api-key-value"} { + if strings.Contains(errorText, leaked) { + t.Fatalf("error leaked %q: %s", leaked, errorText) + } + } + if !strings.Contains(errorText, "CUSTOM_SECRET=") || !strings.Contains(errorText, "API_KEY=") { + t.Fatalf("error did not preserve redacted stderr context: %s", errorText) + } +} + type fakeRunner struct { command string args []string