Skip to content

Commit dd2a098

Browse files
committed
Feat: Add redaction patterns for cloud credentials
- Expands scrubber to cover Azure, GCP, Stripe, Twilio, and other sensitive keys for enhanced security. - Updates tests for new redaction markers. - Adds AGENTS.md for project guidelines.
1 parent 2244fb2 commit dd2a098

3 files changed

Lines changed: 134 additions & 9 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ PR_DESCRIPTION.md
2929
commit
3030
test.txt
3131
AGENTS.md
32+
commit~

internal/scrubber/scrubber.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ var (
258258
},
259259
{
260260
Name: "SSH Public Key (ED25519)",
261-
Pattern: regexp.MustCompile(`(?i)(ssh[_-]?ed25519[_-]?public[_-]?key|SSH_ED25519_PUBLIC_KEY)\s*[=:]\s*["\']?(ssh-ed25519 [a-zA-Z0-9]+ [a-zA-Z0-9._@-]+)["\']?`),
261+
Pattern: regexp.MustCompile(`(?i)(ssh[_-]?ed25519[_-]?public[_-]?key|SSH_ED25519_PUBLIC_KEY)\s*[=:]\s*["\']?(ssh-ed25519 [a-zA-Z0-9+/]+ [a-zA-Z0-9._@-]+)["\']?`),
262262
Redact: "${1}=\"[REDACTED_SSH_ED25519_PUBLIC_KEY]\"",
263263
},
264264
{

internal/scrubber/scrubber_test.go

Lines changed: 132 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -397,29 +397,153 @@ func TestScrubEmailInCredentials(t *testing.T) {
397397
}
398398

399399
func TestScrubCreditCard(t *testing.T) {
400+
tests := []struct {
401+
name string
402+
input string
403+
expected string
404+
}{
405+
{
406+
name: "Credit card with spaces",
407+
input: "4111 1111 1111 1111",
408+
expected: "[REDACTED_CREDIT_CARD]",
409+
},
410+
{
411+
name: "Credit card with dashes",
412+
input: "4111-1111-1111-1111",
413+
expected: "[REDACTED_CREDIT_CARD]",
414+
},
415+
{
416+
name: "Credit card no separators",
417+
input: "4111111111111111",
418+
expected: "[REDACTED_CREDIT_CARD]",
419+
},
420+
}
421+
422+
for _, tt := range tests {
423+
t.Run(tt.name, func(t *testing.T) {
424+
result := ScrubDiff(tt.input)
425+
if !strings.Contains(result, "[REDACTED_CREDIT_CARD]") {
426+
t.Errorf("ScrubDiff() failed to redact credit card.\nInput: %s\nOutput: %s", tt.input, result)
427+
}
428+
})
429+
}
430+
}
431+
432+
func TestScrubAzureCredentials(t *testing.T) {
400433
tests := []struct {
401434
name string
402435
input string
403436
}{
404437
{
405-
name: "Credit card with spaces",
406-
input: `card: "4532 1234 5678 9010"`,
438+
name: "Azure Client Secret",
439+
input: `AZURE_CLIENT_SECRET="abc123def456ghi789jkl012mno345pqr"`,
407440
},
408441
{
409-
name: "Credit card with dashes",
410-
input: `4532-1234-5678-9010`,
442+
name: "Azure Subscription Key",
443+
input: `azure_subscription_key: "abcdefghijklmnopqrstuvwxyz123456"`,
411444
},
412445
{
413-
name: "Credit card no separators",
414-
input: `4532123456789010`,
446+
name: "Azure Storage Key",
447+
input: `AccountKey="abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890123456789012345678901234567890123456789012345678901234567890"`,
415448
},
416449
}
417450

418451
for _, tt := range tests {
419452
t.Run(tt.name, func(t *testing.T) {
420453
result := ScrubDiff(tt.input)
421-
if strings.Contains(result, "4532") && strings.Contains(result, "9010") {
422-
t.Errorf("ScrubDiff() failed to redact credit card.\nInput: %s\nOutput: %s", tt.input, result)
454+
if !strings.Contains(result, "[REDACTED_AZURE") {
455+
t.Errorf("ScrubDiff() failed to redact Azure credentials.\nInput: %s\nOutput: %s", tt.input, result)
456+
}
457+
})
458+
}
459+
}
460+
461+
func TestScrubGoogleCloudCredentials(t *testing.T) {
462+
tests := []struct {
463+
name string
464+
input string
465+
}{
466+
{
467+
name: "Google Cloud Service Account Key",
468+
input: `GOOGLE_APPLICATION_CREDENTIALS="my-service-account-key.json"`,
469+
},
470+
{
471+
name: "Google Cloud API Key",
472+
input: `gcp_api_key="abcdefghijklmnopqrstuvwxyz1234567890123456789"`,
473+
},
474+
{
475+
name: "Google Cloud JSON Credentials",
476+
input: `"type": "service_account",\n"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5\n-----END PRIVATE KEY-----"`,
477+
},
478+
}
479+
480+
for _, tt := range tests {
481+
t.Run(tt.name, func(t *testing.T) {
482+
result := ScrubDiff(tt.input)
483+
if !strings.Contains(result, "[REDACTED_") {
484+
t.Errorf("ScrubDiff() failed to redact Google Cloud credentials.\nInput: %s\nOutput: %s", tt.input, result)
485+
}
486+
})
487+
}
488+
}
489+
490+
func TestScrubAdditionalAPIKeys(t *testing.T) {
491+
tests := []struct {
492+
name string
493+
input string
494+
}{
495+
{
496+
name: "Stripe API Key",
497+
input: `STRIPE_API_KEY="sk_live_1234567890abcdefghijklmnopqrstuvwxyz"`,
498+
},
499+
{
500+
name: "Twilio Auth Token",
501+
input: `twilio_auth_token: "1234567890abcdef1234567890abcdef"`,
502+
},
503+
{
504+
name: "DigitalOcean API Key",
505+
input: `digitalocean_api_key="1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"`,
506+
},
507+
{
508+
name: "SendGrid API Key",
509+
input: `SENDGRID_API_KEY="SG.1234567890abcdef1234567890abcdef.1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12345678"`,
510+
},
511+
}
512+
513+
for _, tt := range tests {
514+
t.Run(tt.name, func(t *testing.T) {
515+
result := ScrubDiff(tt.input)
516+
if !strings.Contains(result, "[REDACTED_") {
517+
t.Errorf("ScrubDiff() failed to redact additional API keys.\nInput: %s\nOutput: %s", tt.input, result)
518+
}
519+
})
520+
}
521+
}
522+
523+
func TestScrubSSHKeys(t *testing.T) {
524+
tests := []struct {
525+
name string
526+
input string
527+
}{
528+
{
529+
name: "OpenSSH Private Key",
530+
input: `-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn\nNhAAAAAwEAAQAAAIEA2K8Qv8a4a5K6B2J8RiQzL1h4w0F2R3B4C5D6E7F8G9H0I1J2K3L4\n-----END OPENSSH PRIVATE KEY-----`,
531+
},
532+
{
533+
name: "SSH RSA Public Key",
534+
input: `ssh_rsa_public_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCeStA8tG2r5a user@hostname"`,
535+
},
536+
{
537+
name: "SSH ED25519 Public Key",
538+
input: `SSH_ED25519_PUBLIC_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGbWQrKyUBUHvL3+d1H5Q8UQrBw6M5J user@example.com"`,
539+
},
540+
}
541+
542+
for _, tt := range tests {
543+
t.Run(tt.name, func(t *testing.T) {
544+
result := ScrubDiff(tt.input)
545+
if !strings.Contains(result, "[REDACTED_") {
546+
t.Errorf("ScrubDiff() failed to redact SSH keys.\nInput: %s\nOutput: %s", tt.input, result)
423547
}
424548
})
425549
}

0 commit comments

Comments
 (0)