commit.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package scan
  2. import (
  3. "fmt"
  4. "github.com/zricethezav/gitleaks/v7/report"
  5. "github.com/go-git/go-git/v5"
  6. fdiff "github.com/go-git/go-git/v5/plumbing/format/diff"
  7. "github.com/go-git/go-git/v5/plumbing/object"
  8. )
  9. // CommitScanner is a commit scanner
  10. type CommitScanner struct {
  11. BaseScanner
  12. repo *git.Repository
  13. repoName string
  14. commit *object.Commit
  15. }
  16. // NewCommitScanner creates and returns a commit scanner
  17. func NewCommitScanner(base BaseScanner, repo *git.Repository, commit *object.Commit) *CommitScanner {
  18. cs := &CommitScanner{
  19. BaseScanner: base,
  20. repo: repo,
  21. commit: commit,
  22. repoName: getRepoName(base.opts),
  23. }
  24. cs.scannerType = typeCommitScanner
  25. return cs
  26. }
  27. // Scan kicks off a CommitScanner Scan
  28. func (cs *CommitScanner) Scan() (report.Report, error) {
  29. var scannerReport report.Report
  30. if len(cs.commit.ParentHashes) == 0 {
  31. facScanner := NewFilesAtCommitScanner(cs.BaseScanner, cs.repo, cs.commit)
  32. return facScanner.Scan()
  33. }
  34. err := cs.commit.Parents().ForEach(func(parent *object.Commit) error {
  35. defer func() {
  36. if err := recover(); err != nil {
  37. // sometimes the Patch generation will fail due to a known bug in
  38. // sergi's go-diff: https://github.com/sergi/go-diff/issues/89.
  39. // Once a fix has been merged I will remove this recover.
  40. return
  41. }
  42. }()
  43. if parent == nil {
  44. return nil
  45. }
  46. patch, err := parent.Patch(cs.commit)
  47. if err != nil {
  48. return fmt.Errorf("could not generate Patch")
  49. }
  50. patchContent := patch.String()
  51. for _, f := range patch.FilePatches() {
  52. if f.IsBinary() {
  53. continue
  54. }
  55. for _, chunk := range f.Chunks() {
  56. if chunk.Type() == fdiff.Add {
  57. _, to := f.Files()
  58. leaks := checkRules(cs.BaseScanner, cs.commit, cs.repoName, to.Path(), chunk.Content())
  59. lineLookup := make(map[string]bool)
  60. for _, leak := range leaks {
  61. leak.LineNumber = extractLine(patchContent, leak, lineLookup)
  62. leak.LeakURL = leakURL(leak)
  63. scannerReport.Leaks = append(scannerReport.Leaks, leak)
  64. if cs.opts.Verbose {
  65. logLeak(leak, cs.opts.Redact)
  66. }
  67. }
  68. }
  69. }
  70. }
  71. return nil
  72. })
  73. scannerReport.Commits = 1
  74. return scannerReport, err
  75. }