package scanning import ( "regexp" "testing" ) func TestPatternsCompile(t *testing.T) { for _, p := range Patterns { _, err := regexp.Compile(p.Raw) if err != nil { t.Errorf("pattern %q failed to compile: %v", p.Name, err) } } } func TestPatternsHaveNames(t *testing.T) { for _, p := range Patterns { if p.Name == "" { t.Error("pattern with empty name") } if p.Description == "" { t.Errorf("pattern %q has empty description", p.Name) } if p.Severity != "high" && p.Severity != "medium" && p.Severity != "low" { t.Errorf("pattern %q has invalid severity %q", p.Name, p.Severity) } } } func TestAWSAccessKey(t *testing.T) { re := regexp.MustCompile(`AKIA[0-9A-Z]{16}`) cases := []struct { input string match bool }{ {"AKIAIOSFODNN7EXAMPLE", true}, {"AKIA1234567890123456", true}, {"not-a-key", false}, {"SKIA1234567890123456", false}, } for _, tc := range cases { got := re.MatchString(tc.input) if got != tc.match { t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match) } } } func TestGitHubToken(t *testing.T) { re := regexp.MustCompile(`gh[pousr]_[A-Za-z0-9_]{36,}`) cases := []struct { input string match bool }{ {"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true}, {"gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true}, {"ghu_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true}, {"ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true}, {"ghr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true}, {"not-a-token", false}, {"ghp_short", false}, } for _, tc := range cases { got := re.MatchString(tc.input) if got != tc.match { t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match) } } } func TestPrivateKey(t *testing.T) { re := regexp.MustCompile(`-----BEGIN\s+(RSA|EC|OPENSSH|DSA|PRIVATE)(\s+PRIVATE)?\s+KEY-----`) cases := []struct { input string match bool }{ {"-----BEGIN RSA PRIVATE KEY-----", true}, {"-----BEGIN EC PRIVATE KEY-----", true}, {"-----BEGIN OPENSSH PRIVATE KEY-----", true}, {"-----BEGIN DSA PRIVATE KEY-----", true}, {"-----BEGIN PRIVATE KEY-----", true}, {"-----BEGIN CERTIFICATE-----", false}, {"public key is here", false}, } for _, tc := range cases { got := re.MatchString(tc.input) if got != tc.match { t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match) } } } func TestJWT(t *testing.T) { re := regexp.MustCompile(`eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}`) cases := []struct { input string match bool }{ {"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNnZctV9XjvP_oGZQZxGdAqVxQ", true}, {"not-a-jwt", false}, } for _, tc := range cases { got := re.MatchString(tc.input) if got != tc.match { t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match) } } } func TestTruncate(t *testing.T) { if truncate("hello", 10) != "hello" { t.Error("should not truncate short strings") } if truncate("hello world this is long", 10) != "hello worl..." { t.Errorf("got %q", truncate("hello world this is long", 10)) } }