filesatcommit.go 3.0 KB

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