filesatcommit.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package scan
  2. import (
  3. "path/filepath"
  4. "strings"
  5. "github.com/zricethezav/gitleaks/v7/config"
  6. "github.com/zricethezav/gitleaks/v7/options"
  7. "github.com/go-git/go-git/v5"
  8. "github.com/go-git/go-git/v5/plumbing/object"
  9. )
  10. // FilesAtCommitScanner is a files at commit scanner. This differs from CommitScanner
  11. // as CommitScanner generates patches that are scanned. FilesAtCommitScanner instead looks at
  12. // files available at a commit's worktree and scans the entire content of said files.
  13. // Apologies for the awful struct name...
  14. type FilesAtCommitScanner struct {
  15. opts options.Options
  16. cfg config.Config
  17. repo *git.Repository
  18. commit *object.Commit
  19. repoName string
  20. }
  21. // NewFilesAtCommitScanner creates and returns a files at commit scanner
  22. func NewFilesAtCommitScanner(opts options.Options, cfg config.Config, repo *git.Repository, commit *object.Commit) *FilesAtCommitScanner {
  23. fs := &FilesAtCommitScanner{
  24. opts: opts,
  25. cfg: cfg,
  26. repo: repo,
  27. commit: commit,
  28. repoName: getRepoName(opts),
  29. }
  30. return fs
  31. }
  32. // Scan kicks off a FilesAtCommitScanner Scan
  33. func (fs *FilesAtCommitScanner) Scan() (Report, error) {
  34. var scannerReport Report
  35. fIter, err := fs.commit.Files()
  36. if err != nil {
  37. return scannerReport, err
  38. }
  39. err = fIter.ForEach(func(f *object.File) error {
  40. bin, err := f.IsBinary()
  41. if bin {
  42. return nil
  43. } else if err != nil {
  44. return err
  45. }
  46. content, err := f.Contents()
  47. if err != nil {
  48. return err
  49. }
  50. // Check individual file path ONLY rules
  51. for _, rule := range fs.cfg.Rules {
  52. if rule.CommitAllowed(fs.commit.Hash.String()) {
  53. continue
  54. }
  55. if rule.HasFileOrPathLeakOnly(f.Name) {
  56. leak := NewLeak("", "Filename or path offender: "+f.Name, defaultLineNumber).WithCommit(fs.commit)
  57. leak.Repo = fs.repoName
  58. leak.File = f.Name
  59. leak.RepoURL = fs.opts.RepoURL
  60. leak.LeakURL = leak.URL()
  61. leak.Rule = rule.Description
  62. leak.Tags = strings.Join(rule.Tags, ", ")
  63. if fs.opts.Verbose {
  64. leak.Log(fs.opts.Redact)
  65. }
  66. scannerReport.Leaks = append(scannerReport.Leaks, leak)
  67. continue
  68. }
  69. }
  70. for i, line := range strings.Split(content, "\n") {
  71. for _, rule := range fs.cfg.Rules {
  72. if rule.AllowList.FileAllowed(filepath.Base(f.Name)) ||
  73. rule.AllowList.PathAllowed(f.Name) ||
  74. rule.AllowList.CommitAllowed(fs.commit.Hash.String()) {
  75. continue
  76. }
  77. offender := rule.Inspect(line)
  78. if offender == "" {
  79. continue
  80. }
  81. if fs.cfg.Allowlist.RegexAllowed(line) {
  82. continue
  83. }
  84. if rule.File.String() != "" && !rule.HasFileLeak(filepath.Base(f.Name)) {
  85. continue
  86. }
  87. if rule.Path.String() != "" && !rule.HasFilePathLeak(f.Name) {
  88. continue
  89. }
  90. leak := NewLeak(line, offender, defaultLineNumber).WithCommit(fs.commit)
  91. leak.File = f.Name
  92. leak.LineNumber = i + 1
  93. leak.RepoURL = fs.opts.RepoURL
  94. leak.Repo = fs.repoName
  95. leak.LeakURL = leak.URL()
  96. leak.Rule = rule.Description
  97. leak.Tags = strings.Join(rule.Tags, ", ")
  98. if fs.opts.Verbose {
  99. leak.Log(fs.opts.Redact)
  100. }
  101. scannerReport.Leaks = append(scannerReport.Leaks, leak)
  102. }
  103. }
  104. return nil
  105. })
  106. scannerReport.Commits = 1
  107. return scannerReport, err
  108. }