multica/server/pkg/redact/redact_test.go
Jiayuan 0491350f1b feat(security): add agent output redaction and private agent assignment enforcement
- Add redact package to detect and mask secrets (AWS keys, private keys,
  API tokens, bearer tokens, credentials, home paths) in agent output
  before posting as comments in TaskService
- Enforce agent visibility on issue assignment: private agents can only
  be assigned by their owner or workspace admins
- Add visibility picker (workspace/private) to CreateAgentDialog,
  default to private
- Grey out unassignable private agents in the assignee picker with
  lock icon indicator
2026-03-30 22:22:04 +08:00

139 lines
3.8 KiB
Go

package redact
import (
"strings"
"testing"
)
func TestRedactAWSAccessKey(t *testing.T) {
t.Parallel()
input := "Found key AKIAIOSFODNN7EXAMPLE in config"
got := Text(input)
if strings.Contains(got, "AKIAIOSFODNN7EXAMPLE") {
t.Fatalf("AWS key not redacted: %s", got)
}
if !strings.Contains(got, "[REDACTED AWS KEY]") {
t.Fatalf("expected [REDACTED AWS KEY] placeholder, got: %s", got)
}
}
func TestRedactAWSSecretKey(t *testing.T) {
t.Parallel()
input := "aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
got := Text(input)
if strings.Contains(got, "wJalrXUtnFEMI") {
t.Fatalf("AWS secret not redacted: %s", got)
}
}
func TestRedactPrivateKey(t *testing.T) {
t.Parallel()
input := "Here is the key:\n-----BEGIN RSA PRIVATE KEY-----\nMIIEow...\n-----END RSA PRIVATE KEY-----\nDone."
got := Text(input)
if strings.Contains(got, "MIIEow") {
t.Fatalf("private key content not redacted: %s", got)
}
if !strings.Contains(got, "[REDACTED PRIVATE KEY]") {
t.Fatalf("expected [REDACTED PRIVATE KEY] placeholder, got: %s", got)
}
}
func TestRedactGitHubToken(t *testing.T) {
t.Parallel()
input := "export GITHUB_TOKEN=ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"
got := Text(input)
if strings.Contains(got, "ghp_") {
t.Fatalf("GitHub token not redacted: %s", got)
}
}
func TestRedactOpenAIKey(t *testing.T) {
t.Parallel()
input := "OPENAI_API_KEY=sk-proj-abc123def456ghi789jkl012mno345"
got := Text(input)
if strings.Contains(got, "sk-proj-abc123") {
t.Fatalf("OpenAI key not redacted: %s", got)
}
}
func TestRedactSlackToken(t *testing.T) {
t.Parallel()
input := "token: xoxb-123456789012-1234567890123-AbCdEfGhIjKl"
got := Text(input)
if strings.Contains(got, "xoxb-") {
t.Fatalf("Slack token not redacted: %s", got)
}
}
func TestRedactBearerToken(t *testing.T) {
t.Parallel()
input := "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abc123"
got := Text(input)
if strings.Contains(got, "eyJhbGci") {
t.Fatalf("Bearer token not redacted: %s", got)
}
}
func TestRedactGenericCredentials(t *testing.T) {
t.Parallel()
cases := []struct {
name string
input string
}{
{"API_KEY", "API_KEY=mysupersecretkey123"},
{"DATABASE_URL", "DATABASE_URL=postgres://user:pass@host/db"},
{"DB_PASSWORD", "DB_PASSWORD: hunter2"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := Text(tc.input)
if !strings.Contains(got, "[REDACTED CREDENTIAL]") {
t.Fatalf("expected credential redaction for %s, got: %s", tc.name, got)
}
})
}
}
func TestRedactHomeDirectory(t *testing.T) {
t.Parallel()
if homeDir == "" || username == "" {
t.Skip("cannot determine home dir or username")
}
input := "Reading file at " + homeDir + "/Documents/secret.txt"
got := Text(input)
if strings.Contains(got, username) {
t.Fatalf("home directory username not redacted: %s", got)
}
if !strings.Contains(got, "****") {
t.Fatalf("expected **** in path, got: %s", got)
}
}
func TestNoFalsePositivesOnNormalText(t *testing.T) {
t.Parallel()
inputs := []string{
"This is a normal commit message about fixing a bug",
"The function returns skip-navigation as the class name",
"Created PR #42 for the authentication feature",
"Running tests in /tmp/test-workspace/project",
"The API endpoint /api/issues/123 was updated",
}
for _, input := range inputs {
got := Text(input)
if got != input {
t.Fatalf("false positive redaction:\n input: %s\n output: %s", input, got)
}
}
}
func TestRedactMultipleSecrets(t *testing.T) {
t.Parallel()
input := "Keys: AKIAIOSFODNN7EXAMPLE and ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"
got := Text(input)
if strings.Contains(got, "AKIAIOSFODNN7EXAMPLE") {
t.Fatal("AWS key not redacted in multi-secret text")
}
if strings.Contains(got, "ghp_") {
t.Fatal("GitHub token not redacted in multi-secret text")
}
}