config.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. package config
  2. import (
  3. "fmt"
  4. "path"
  5. "regexp"
  6. "strconv"
  7. "github.com/zricethezav/gitleaks/v5/options"
  8. "github.com/BurntSushi/toml"
  9. )
  10. // Whitelist is struct containing items that if encountered will whitelist
  11. // a commit/line of code that would be considered a leak.
  12. type Whitelist struct {
  13. Description string
  14. Regex *regexp.Regexp
  15. File *regexp.Regexp
  16. Path *regexp.Regexp
  17. }
  18. // Entropy represents an entropy range
  19. type Entropy struct {
  20. Min float64
  21. Max float64
  22. Group int
  23. }
  24. // Rule is a struct that contains information that is loaded from a gitleaks config.
  25. // This struct is used in the Config struct as an array of Rules and is iterated
  26. // over during an scan. Each rule will be checked. If a regex match is found AND
  27. // that match is not whitelisted (globally or locally), then a leak will be appended
  28. // to the final scan report.
  29. type Rule struct {
  30. Description string
  31. Regex *regexp.Regexp
  32. FileNameRegex *regexp.Regexp
  33. FilePathRegex *regexp.Regexp
  34. Tags []string
  35. Whitelist []Whitelist
  36. Entropies []Entropy
  37. }
  38. // Config is a composite struct of Rules and Whitelists
  39. // Each Rule contains a description, regular expression, tags, and whitelists if available
  40. type Config struct {
  41. Rules []Rule
  42. Whitelist struct {
  43. Description string
  44. Commits []string
  45. Files []*regexp.Regexp
  46. Paths []*regexp.Regexp
  47. Repos []*regexp.Regexp
  48. }
  49. }
  50. // TomlLoader gets loaded with the values from a gitleaks toml config
  51. // see the config in config/defaults.go for an example. TomlLoader is used
  52. // to generate Config values (compiling regexes, etc).
  53. type TomlLoader struct {
  54. Whitelist struct {
  55. Description string
  56. Commits []string
  57. Files []string
  58. Paths []string
  59. Repos []string
  60. }
  61. Rules []struct {
  62. Description string
  63. Regex string
  64. FileNameRegex string
  65. FilePathRegex string
  66. Tags []string
  67. Entropies []struct {
  68. Min string
  69. Max string
  70. Group string
  71. }
  72. Whitelist []struct {
  73. Description string
  74. Regex string
  75. File string
  76. Path string
  77. }
  78. }
  79. }
  80. // NewConfig will create a new config struct which contains
  81. // rules on how gitleaks will proceed with its scan.
  82. // If no options are passed via cli then NewConfig will return
  83. // a default config which can be seen in config.go
  84. func NewConfig(options options.Options) (Config, error) {
  85. var cfg Config
  86. tomlLoader := TomlLoader{}
  87. var err error
  88. if options.Config != "" {
  89. _, err = toml.DecodeFile(options.Config, &tomlLoader)
  90. // append a whitelist rule for whitelisting the config
  91. tomlLoader.Whitelist.Files = append(tomlLoader.Whitelist.Files, path.Base(options.Config))
  92. } else {
  93. _, err = toml.Decode(DefaultConfig, &tomlLoader)
  94. }
  95. if err != nil {
  96. return cfg, err
  97. }
  98. cfg, err = tomlLoader.Parse()
  99. if err != nil {
  100. return cfg, err
  101. }
  102. return cfg, nil
  103. }
  104. // Parse will parse the values set in a TomlLoader and use those values
  105. // to create compiled regular expressions and rules used in scans
  106. func (tomlLoader TomlLoader) Parse() (Config, error) {
  107. var cfg Config
  108. for _, rule := range tomlLoader.Rules {
  109. re, err := regexp.Compile(rule.Regex)
  110. if err != nil {
  111. return cfg, fmt.Errorf("problem loading config: %v", err)
  112. }
  113. fileNameRe, err := regexp.Compile(rule.FileNameRegex)
  114. if err != nil {
  115. return cfg, fmt.Errorf("problem loading config: %v", err)
  116. }
  117. filePathRe, err := regexp.Compile(rule.FilePathRegex)
  118. if err != nil {
  119. return cfg, fmt.Errorf("problem loading config: %v", err)
  120. }
  121. // rule specific whitelists
  122. var whitelists []Whitelist
  123. for _, wl := range rule.Whitelist {
  124. wlRe, err := regexp.Compile(wl.Regex)
  125. if err != nil {
  126. return cfg, fmt.Errorf("problem loading config: %v", err)
  127. }
  128. wlFileNameRe, err := regexp.Compile(wl.File)
  129. if err != nil {
  130. return cfg, fmt.Errorf("problem loading config: %v", err)
  131. }
  132. wlFilePathRe, err := regexp.Compile(wl.Path)
  133. if err != nil {
  134. return cfg, fmt.Errorf("problem loading config: %v", err)
  135. }
  136. whitelists = append(whitelists, Whitelist{
  137. Description: wl.Description,
  138. File: wlFileNameRe,
  139. Path: wlFilePathRe,
  140. Regex: wlRe,
  141. })
  142. }
  143. var entropies []Entropy
  144. for _, e := range rule.Entropies {
  145. min, err := strconv.ParseFloat(e.Min, 64)
  146. if err != nil {
  147. return cfg, err
  148. }
  149. max, err := strconv.ParseFloat(e.Max, 64)
  150. if err != nil {
  151. return cfg, err
  152. }
  153. if e.Group == "" {
  154. e.Group = "0"
  155. }
  156. group, err := strconv.ParseInt(e.Group, 10, 64)
  157. if err != nil {
  158. return cfg, err
  159. } else if int(group) >= len(re.SubexpNames()) {
  160. return cfg, fmt.Errorf("problem loading config: group cannot be higher than number of groups in regexp")
  161. } else if group < 0 {
  162. return cfg, fmt.Errorf("problem loading config: group cannot be lower than 0")
  163. } else if min > 8.0 || min < 0.0 || max > 8.0 || max < 0.0 {
  164. return cfg, fmt.Errorf("problem loading config: invalid entropy ranges, must be within 0.0-8.0")
  165. } else if min > max {
  166. return cfg, fmt.Errorf("problem loading config: entropy Min value cannot be higher than Max value")
  167. }
  168. entropies = append(entropies, Entropy{Min: min, Max: max, Group: int(group)})
  169. }
  170. cfg.Rules = append(cfg.Rules, Rule{
  171. Description: rule.Description,
  172. Regex: re,
  173. FileNameRegex: fileNameRe,
  174. FilePathRegex: filePathRe,
  175. Tags: rule.Tags,
  176. Whitelist: whitelists,
  177. Entropies: entropies,
  178. })
  179. }
  180. // global file name whitelists
  181. for _, wlFileName := range tomlLoader.Whitelist.Files {
  182. re, err := regexp.Compile(wlFileName)
  183. if err != nil {
  184. return cfg, fmt.Errorf("problem loading config: %v", err)
  185. }
  186. cfg.Whitelist.Files = append(cfg.Whitelist.Files, re)
  187. }
  188. // global file path whitelists
  189. for _, wlFilePath := range tomlLoader.Whitelist.Paths {
  190. re, err := regexp.Compile(wlFilePath)
  191. if err != nil {
  192. return cfg, fmt.Errorf("problem loading config: %v", err)
  193. }
  194. cfg.Whitelist.Paths = append(cfg.Whitelist.Paths, re)
  195. }
  196. // global repo whitelists
  197. for _, wlRepo := range tomlLoader.Whitelist.Repos {
  198. re, err := regexp.Compile(wlRepo)
  199. if err != nil {
  200. return cfg, fmt.Errorf("problem loading config: %v", err)
  201. }
  202. cfg.Whitelist.Repos = append(cfg.Whitelist.Repos, re)
  203. }
  204. cfg.Whitelist.Commits = tomlLoader.Whitelist.Commits
  205. cfg.Whitelist.Description = tomlLoader.Whitelist.Description
  206. return cfg, nil
  207. }