nogit.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package scan
  2. import (
  3. "bufio"
  4. "context"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "sync"
  9. log "github.com/sirupsen/logrus"
  10. "golang.org/x/sync/errgroup"
  11. "github.com/zricethezav/gitleaks/v7/config"
  12. "github.com/zricethezav/gitleaks/v7/options"
  13. )
  14. // NoGitScanner is a scanner that absolutely despises git
  15. type NoGitScanner struct {
  16. opts options.Options
  17. cfg config.Config
  18. throttle *Throttle
  19. mtx *sync.Mutex
  20. }
  21. // NewNoGitScanner creates and returns a nogit scanner. This is used for scanning files and directories
  22. func NewNoGitScanner(opts options.Options, cfg config.Config) *NoGitScanner {
  23. ngs := &NoGitScanner{
  24. opts: opts,
  25. cfg: cfg,
  26. throttle: NewThrottle(opts),
  27. mtx: &sync.Mutex{},
  28. }
  29. // no-git scans should ignore .git folders by default
  30. // issue: https://github.com/zricethezav/gitleaks/issues/474
  31. // ngs.cfg.Allowlist
  32. err := ngs.cfg.Allowlist.IgnoreDotGit()
  33. if err != nil {
  34. log.Error(err)
  35. return nil
  36. }
  37. return ngs
  38. }
  39. // Scan kicks off a NoGitScanner Scan
  40. func (ngs *NoGitScanner) Scan() (Report, error) {
  41. var scannerReport Report
  42. g, _ := errgroup.WithContext(context.Background())
  43. paths := make(chan string)
  44. g.Go(func() error {
  45. defer close(paths)
  46. return filepath.Walk(ngs.opts.Path,
  47. func(path string, fInfo os.FileInfo, err error) error {
  48. if err != nil {
  49. return err
  50. }
  51. if fInfo.Mode().IsRegular() {
  52. paths <- path
  53. }
  54. return nil
  55. })
  56. })
  57. for path := range paths {
  58. p := path
  59. ngs.throttle.Limit()
  60. g.Go(func() error {
  61. defer ngs.throttle.Release()
  62. if ngs.cfg.Allowlist.FileAllowed(filepath.Base(p)) ||
  63. ngs.cfg.Allowlist.PathAllowed(p) {
  64. return nil
  65. }
  66. for _, rule := range ngs.cfg.Rules {
  67. if rule.HasFileOrPathLeakOnly(p) {
  68. leak := NewLeak("", "Filename or path offender: "+p, defaultLineNumber)
  69. relPath, err := filepath.Rel(ngs.opts.Path, p)
  70. if err != nil {
  71. leak.File = p
  72. } else {
  73. leak.File = relPath
  74. }
  75. leak.Rule = rule.Description
  76. leak.Tags = strings.Join(rule.Tags, ", ")
  77. leak.Log(ngs.opts)
  78. ngs.mtx.Lock()
  79. scannerReport.Leaks = append(scannerReport.Leaks, leak)
  80. ngs.mtx.Unlock()
  81. }
  82. }
  83. f, err := os.Open(p) // #nosec
  84. if err != nil {
  85. return err
  86. }
  87. scanner := bufio.NewScanner(f)
  88. lineNumber := 0
  89. for scanner.Scan() {
  90. lineNumber++
  91. for _, rule := range ngs.cfg.Rules {
  92. line := scanner.Text()
  93. if rule.AllowList.FileAllowed(filepath.Base(p)) ||
  94. rule.AllowList.PathAllowed(p) {
  95. continue
  96. }
  97. offender := rule.Inspect(line)
  98. if offender.IsEmpty() {
  99. continue
  100. }
  101. if ngs.cfg.Allowlist.RegexAllowed(line) {
  102. continue
  103. }
  104. if rule.File.String() != "" && !rule.HasFileLeak(filepath.Base(p)) {
  105. continue
  106. }
  107. if rule.Path.String() != "" && !rule.HasFilePathLeak(p) {
  108. continue
  109. }
  110. leak := NewLeak(line, offender.ToString(), defaultLineNumber).WithEntropy(offender.EntropyLevel)
  111. relPath, err := filepath.Rel(ngs.opts.Path, p)
  112. if err != nil {
  113. leak.File = p
  114. } else {
  115. leak.File = relPath
  116. }
  117. leak.LineNumber = lineNumber
  118. leak.Rule = rule.Description
  119. leak.Tags = strings.Join(rule.Tags, ", ")
  120. leak.Log(ngs.opts)
  121. ngs.mtx.Lock()
  122. scannerReport.Leaks = append(scannerReport.Leaks, leak)
  123. ngs.mtx.Unlock()
  124. }
  125. }
  126. return f.Close()
  127. })
  128. }
  129. if err := g.Wait(); err != nil {
  130. log.Error(err)
  131. }
  132. return scannerReport, nil
  133. }