rule.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package rules
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strings"
  6. "github.com/rs/zerolog/log"
  7. "github.com/zricethezav/gitleaks/v8/config"
  8. "github.com/zricethezav/gitleaks/v8/detect"
  9. )
  10. const (
  11. // case insensitive prefix
  12. caseInsensitive = `(?i)`
  13. // identifier prefix (just an ignore group)
  14. identifierPrefix = `(?:`
  15. identifierSuffix = `)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}`
  16. // commonly used assignment operators or function call
  17. operator = `(?:=|>|:=|\|\|:|<=|=>|:)`
  18. // boundaries for the secret
  19. // \x60 = `
  20. secretPrefixUnique = `\b(`
  21. secretPrefix = `(?:'|\"|\s|=|\x60){0,5}(`
  22. secretSuffix = `)(?:['|\"|\n|\r|\s|\x60]|$)`
  23. )
  24. func generateSemiGenericRegex(identifiers []string, secretRegex string) *regexp.Regexp {
  25. var sb strings.Builder
  26. sb.WriteString(caseInsensitive)
  27. sb.WriteString(identifierPrefix)
  28. sb.WriteString(strings.Join(identifiers, "|"))
  29. sb.WriteString(identifierSuffix)
  30. sb.WriteString(operator)
  31. sb.WriteString(secretPrefix)
  32. sb.WriteString(secretRegex)
  33. sb.WriteString(secretSuffix)
  34. return regexp.MustCompile(sb.String())
  35. }
  36. func generateUniqueTokenRegex(secretRegex string) *regexp.Regexp {
  37. var sb strings.Builder
  38. sb.WriteString(caseInsensitive)
  39. sb.WriteString(secretPrefixUnique)
  40. sb.WriteString(secretRegex)
  41. sb.WriteString(secretSuffix)
  42. return regexp.MustCompile(sb.String())
  43. }
  44. func generateSampleSecret(identifier string, secret string) string {
  45. return fmt.Sprintf("%s_api_token = \"%s\"", identifier, secret)
  46. }
  47. func validate(r config.Rule, truePositives []string, falsePositives []string) *config.Rule {
  48. // normalize keywords like in the config package
  49. var keywords []string
  50. for _, k := range r.Keywords {
  51. keywords = append(keywords, strings.ToLower(k))
  52. }
  53. r.Keywords = keywords
  54. d := detect.NewDetector(config.Config{
  55. Rules: []*config.Rule{&r},
  56. Keywords: keywords,
  57. })
  58. for _, tp := range truePositives {
  59. if len(d.DetectString(tp)) != 1 {
  60. log.Fatal().Msgf("Failed to validate (tp) %s %s", r.RuleID, tp)
  61. }
  62. }
  63. for _, fp := range falsePositives {
  64. if len(d.DetectString(fp)) != 0 {
  65. log.Fatal().Msgf("Failed to validate (fp) %s", r.RuleID)
  66. }
  67. }
  68. return &r
  69. }
  70. func numeric(size string) string {
  71. return fmt.Sprintf(`[0-9]{%s}`, size)
  72. }
  73. func hex(size string) string {
  74. return fmt.Sprintf(`[a-f0-9]{%s}`, size)
  75. }
  76. func alphaNumeric(size string) string {
  77. return fmt.Sprintf(`[a-z0-9]{%s}`, size)
  78. }
  79. func alphaNumericExtended(size string) string {
  80. return fmt.Sprintf(`[a-z0-9=_\-]{%s}`, size)
  81. }