allowlist.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package config
  2. import (
  3. "fmt"
  4. "strings"
  5. "golang.org/x/exp/maps"
  6. "github.com/zricethezav/gitleaks/v8/regexp"
  7. )
  8. type AllowlistMatchCondition int
  9. const (
  10. AllowlistMatchOr AllowlistMatchCondition = iota
  11. AllowlistMatchAnd
  12. )
  13. func (a AllowlistMatchCondition) String() string {
  14. return [...]string{
  15. "OR",
  16. "AND",
  17. }[a]
  18. }
  19. // Allowlist allows a rule to be ignored for specific
  20. // regexes, paths, and/or commits
  21. type Allowlist struct {
  22. // Short human readable description of the allowlist.
  23. Description string
  24. // MatchCondition determines whether all criteria must match.
  25. MatchCondition AllowlistMatchCondition
  26. // Commits is a slice of commit SHAs that are allowed to be ignored. Defaults to "OR".
  27. Commits []string
  28. // Paths is a slice of path regular expressions that are allowed to be ignored.
  29. Paths []*regexp.Regexp
  30. // Regexes is slice of content regular expressions that are allowed to be ignored.
  31. Regexes []*regexp.Regexp
  32. // Can be `match` or `line`.
  33. //
  34. // If `match` the _Regexes_ will be tested against the match of the _Rule.Regex_.
  35. //
  36. // If `line` the _Regexes_ will be tested against the entire line.
  37. //
  38. // If RegexTarget is empty, it will be tested against the found secret.
  39. RegexTarget string
  40. // StopWords is a slice of stop words that are allowed to be ignored.
  41. // This targets the _secret_, not the content of the regex match like the
  42. // Regexes slice.
  43. StopWords []string
  44. }
  45. // CommitAllowed returns true if the commit is allowed to be ignored.
  46. func (a *Allowlist) CommitAllowed(c string) bool {
  47. if c == "" {
  48. return false
  49. }
  50. for _, commit := range a.Commits {
  51. if commit == c {
  52. return true
  53. }
  54. }
  55. return false
  56. }
  57. // PathAllowed returns true if the path is allowed to be ignored.
  58. func (a *Allowlist) PathAllowed(path string) bool {
  59. return anyRegexMatch(path, a.Paths)
  60. }
  61. // RegexAllowed returns true if the regex is allowed to be ignored.
  62. func (a *Allowlist) RegexAllowed(secret string) bool {
  63. return anyRegexMatch(secret, a.Regexes)
  64. }
  65. func (a *Allowlist) ContainsStopWord(s string) bool {
  66. s = strings.ToLower(s)
  67. for _, stopWord := range a.StopWords {
  68. if strings.Contains(s, strings.ToLower(stopWord)) {
  69. return true
  70. }
  71. }
  72. return false
  73. }
  74. func (a *Allowlist) Validate() error {
  75. // Disallow empty allowlists.
  76. if len(a.Commits) == 0 &&
  77. len(a.Paths) == 0 &&
  78. len(a.Regexes) == 0 &&
  79. len(a.StopWords) == 0 {
  80. return fmt.Errorf("[[rules.allowlists]] must contain at least one check for: commits, paths, regexes, or stopwords")
  81. }
  82. // Deduplicate commits and stopwords.
  83. if len(a.Commits) > 0 {
  84. uniqueCommits := make(map[string]struct{})
  85. for _, commit := range a.Commits {
  86. uniqueCommits[commit] = struct{}{}
  87. }
  88. a.Commits = maps.Keys(uniqueCommits)
  89. }
  90. if len(a.StopWords) > 0 {
  91. uniqueStopwords := make(map[string]struct{})
  92. for _, stopWord := range a.StopWords {
  93. uniqueStopwords[stopWord] = struct{}{}
  94. }
  95. a.StopWords = maps.Keys(uniqueStopwords)
  96. }
  97. return nil
  98. }