filesatcommit.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. offender := rule.Inspect(line)
  73. if offender == "" {
  74. continue
  75. }
  76. if fs.cfg.Allowlist.RegexAllowed(line) ||
  77. rule.AllowList.FileAllowed(filepath.Base(f.Name)) ||
  78. rule.AllowList.PathAllowed(f.Name) ||
  79. rule.AllowList.CommitAllowed(fs.commit.Hash.String()) {
  80. continue
  81. }
  82. if rule.File.String() != "" && !rule.HasFileLeak(filepath.Base(f.Name)) {
  83. continue
  84. }
  85. if rule.Path.String() != "" && !rule.HasFilePathLeak(f.Name) {
  86. continue
  87. }
  88. leak := NewLeak(line, offender, defaultLineNumber).WithCommit(fs.commit)
  89. leak.File = f.Name
  90. leak.LineNumber = i + 1
  91. leak.RepoURL = fs.opts.RepoURL
  92. leak.Repo = fs.repoName
  93. leak.LeakURL = leak.URL()
  94. leak.Rule = rule.Description
  95. leak.Tags = strings.Join(rule.Tags, ", ")
  96. if fs.opts.Verbose {
  97. leak.Log(fs.opts.Redact)
  98. }
  99. scannerReport.Leaks = append(scannerReport.Leaks, leak)
  100. }
  101. }
  102. return nil
  103. })
  104. scannerReport.Commits = 1
  105. return scannerReport, err
  106. }