config.go 5.8 KB

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