Files
zero/internal/tools/bash_secrets_test.go
KRATOSandKRATOS df56b0dd9e Tool quality: per-tool denial categorization + secret scanning (#137)
* [LOCAL PR-Z] Agent: structured per-tool denial categorization

Adds ToolResult.DenialReason (DenialCategory: filtered / permission_denied / sandbox_violation) so a surface can tell precisely why a call was blocked instead of parsing Output. Set in the not-enabled path and deniedPermissionResult (sandbox-violation denials categorized distinctly from approval-declined). Tested.

* [LOCAL PR-Z] Secrets: scan + redact leaked secrets in bash output

New internal/secrets package: a dependency-free, precision-first scanner for high-confidence secret shapes (AWS/Google keys, GitHub/Slack tokens, private-key blocks, JWTs). bash output now runs through secrets.Redact so a command that prints a secret has it replaced with a typed placeholder + a redaction notice, instead of echoing it back into the model context (additive to the configured-key scrub at the registry boundary). A built-in regex scanner fits the CLI without the heavy gitleaks dependency. Tested: detection, no-false-positives on ordinary text, redaction, and the bash wiring.

* Tool quality: redact full private-key blocks + use DenialReason in retry classification

CodeRabbit critical: the private_key_block pattern matched only the BEGIN header, so Redact left the PEM/OpenSSH key BODY in the output — defeating the redaction. It now matches the entire BEGIN…END block (body included) so the key material is removed. Test asserts the body is gone.

CodeRabbit minor: isRetriableToolError now treats a structured ToolResult.DenialReason (filtered/permission/sandbox) as non-retriable, independent of message wording; the text checks remain a fallback for results lacking the field.

---------

Co-authored-by: KRATOS <[email protected]>
2026-06-08 09:08:51 +05:30

27 lines
785 B
Go

package tools
import (
"strings"
"testing"
)
func TestFormatBashOutputRedactsSecrets(t *testing.T) {
out := formatBashOutput("aws key: AKIAIOSFODNN7EXAMPLE\n", "", 0)
if strings.Contains(out, "AKIAIOSFODNN7EXAMPLE") {
t.Fatalf("bash output leaked a secret: %q", out)
}
if !strings.Contains(out, "[REDACTED:aws_access_key_id]") {
t.Fatalf("expected typed redaction placeholder, got %q", out)
}
if !strings.Contains(out, "redacted 1 likely secret") {
t.Fatalf("expected a redaction notice, got %q", out)
}
}
func TestFormatBashOutputLeavesCleanOutputAlone(t *testing.T) {
out := formatBashOutput("build succeeded\n", "", 0)
if strings.Contains(out, "REDACTED") || strings.Contains(out, "redacted") {
t.Fatalf("clean output should not be altered, got %q", out)
}
}