config.go 5.0 KB

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