git.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package detect
  2. import (
  3. "strings"
  4. "sync"
  5. "time"
  6. "github.com/gitleaks/go-gitdiff/gitdiff"
  7. "github.com/rs/zerolog/log"
  8. "github.com/zricethezav/gitleaks/v8/config"
  9. "github.com/zricethezav/gitleaks/v8/report"
  10. godocutil "golang.org/x/tools/godoc/util"
  11. )
  12. // FromGit accepts a gitdiff.File channel (structure output from `git log -p`) and a configuration
  13. // struct. Files from the gitdiff.File channel are then checked against each rule in the configuration to
  14. // check for secrets. If any secrets are found, they are added to the list of findings.
  15. func FromGit(files <-chan *gitdiff.File, cfg config.Config, outputOptions Options) []*report.Finding {
  16. var findings []*report.Finding
  17. mu := sync.Mutex{}
  18. wg := sync.WaitGroup{}
  19. commitMap := make(map[string]bool)
  20. for f := range files {
  21. // keep track of commits for logging
  22. if f.PatchHeader != nil {
  23. commitMap[f.PatchHeader.SHA] = true
  24. }
  25. wg.Add(1)
  26. go func(f *gitdiff.File) {
  27. defer wg.Done()
  28. if f.IsBinary {
  29. return
  30. }
  31. if f.IsDelete {
  32. return
  33. }
  34. commitSHA := ""
  35. // Check if commit is allowed
  36. if f.PatchHeader != nil {
  37. commitSHA = f.PatchHeader.SHA
  38. if cfg.Allowlist.CommitAllowed(f.PatchHeader.SHA) {
  39. return
  40. }
  41. }
  42. for _, tf := range f.TextFragments {
  43. if f.TextFragments == nil {
  44. // TODO fix this in gitleaks gitdiff fork
  45. // https://github.com/gitleaks/gitleaks/issues/11
  46. continue
  47. }
  48. if !godocutil.IsText([]byte(tf.Raw(gitdiff.OpAdd))) {
  49. continue
  50. }
  51. for _, fi := range DetectFindings(cfg, []byte(tf.Raw(gitdiff.OpAdd)), f.NewName, commitSHA) {
  52. // don't add to start/end lines if finding is from a file only rule
  53. if !strings.HasPrefix(fi.Match, "file detected") {
  54. fi.StartLine += int(tf.NewPosition)
  55. fi.EndLine += int(tf.NewPosition)
  56. }
  57. if f.PatchHeader != nil {
  58. fi.Commit = f.PatchHeader.SHA
  59. fi.Message = f.PatchHeader.Message()
  60. if f.PatchHeader.Author != nil {
  61. fi.Author = f.PatchHeader.Author.Name
  62. fi.Email = f.PatchHeader.Author.Email
  63. }
  64. fi.Date = f.PatchHeader.AuthorDate.UTC().Format(time.RFC3339)
  65. }
  66. if outputOptions.Redact {
  67. fi.Redact()
  68. }
  69. if outputOptions.Verbose {
  70. printFinding(fi)
  71. }
  72. mu.Lock()
  73. findings = append(findings, &fi)
  74. mu.Unlock()
  75. }
  76. }
  77. }(f)
  78. }
  79. wg.Wait()
  80. log.Debug().Msgf("%d commits scanned. Note: this number might be smaller than expected due to commits with no additions", len(commitMap))
  81. return findings
  82. }