| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- package scan
- import (
- "fmt"
- "path/filepath"
- "strings"
- "github.com/zricethezav/gitleaks/v7/config"
- "github.com/zricethezav/gitleaks/v7/options"
- "github.com/go-git/go-git/v5"
- fdiff "github.com/go-git/go-git/v5/plumbing/format/diff"
- "github.com/go-git/go-git/v5/plumbing/object"
- )
- // CommitScanner is a commit scanner
- type CommitScanner struct {
- cfg config.Config
- opts options.Options
- repo *git.Repository
- repoName string
- commit *object.Commit
- }
- // NewCommitScanner creates and returns a commit scanner
- func NewCommitScanner(opts options.Options, cfg config.Config, repo *git.Repository, commit *object.Commit) *CommitScanner {
- cs := &CommitScanner{
- cfg: cfg,
- opts: opts,
- repo: repo,
- commit: commit,
- repoName: getRepoName(opts),
- }
- return cs
- }
- // SetRepoName sets the repo name of the scanner.
- func (cs *CommitScanner) SetRepoName(repoName string) {
- cs.repoName = repoName
- }
- // Scan kicks off a CommitScanner Scan
- func (cs *CommitScanner) Scan() (Report, error) {
- var scannerReport Report
- defer func() {
- if err := recover(); err != nil {
- // sometimes the Patch generation will fail due to a known bug in
- // sergi's go-diff: https://github.com/sergi/go-diff/issues/89.
- return
- }
- }()
- if cs.cfg.Allowlist.CommitAllowed(cs.commit.Hash.String()) {
- return scannerReport, nil
- }
- if len(cs.commit.ParentHashes) == 0 {
- facScanner := NewFilesAtCommitScanner(cs.opts, cs.cfg, cs.repo, cs.commit)
- return facScanner.Scan()
- }
- parent, err := cs.commit.Parent(0)
- if err != nil {
- return scannerReport, err
- }
- if parent == nil {
- return scannerReport, nil
- }
- patch, err := parent.Patch(cs.commit)
- if err != nil || patch == nil {
- return scannerReport, fmt.Errorf("could not generate Patch")
- }
- patchContent := patch.String()
- for _, f := range patch.FilePatches() {
- if f.IsBinary() {
- continue
- }
- for _, chunk := range f.Chunks() {
- if chunk.Type() == fdiff.Add {
- _, to := f.Files()
- if cs.cfg.Allowlist.FileAllowed(filepath.Base(to.Path())) ||
- cs.cfg.Allowlist.PathAllowed(to.Path()) {
- continue
- }
- // Check individual file path ONLY rules
- for _, rule := range cs.cfg.Rules {
- if rule.CommitAllowed(cs.commit.Hash.String()) {
- continue
- }
- if rule.HasFileOrPathLeakOnly(to.Path()) {
- leak := NewLeak("", "Filename or path offender: "+to.Path(), defaultLineNumber).WithCommit(cs.commit)
- leak.Repo = cs.repoName
- leak.File = to.Path()
- leak.RepoURL = cs.opts.RepoURL
- leak.LeakURL = leak.URL()
- leak.Rule = rule.Description
- leak.Tags = strings.Join(rule.Tags, ", ")
- leak.Log(cs.opts)
- scannerReport.Leaks = append(scannerReport.Leaks, leak)
- continue
- }
- }
- lineLookup := make(map[string]bool)
- // Check the actual content
- for _, line := range strings.Split(chunk.Content(), "\n") {
- for _, rule := range cs.cfg.Rules {
- if rule.AllowList.FileAllowed(filepath.Base(to.Path())) ||
- rule.AllowList.PathAllowed(to.Path()) ||
- rule.AllowList.CommitAllowed(cs.commit.Hash.String()) {
- continue
- }
- offender := rule.Inspect(line)
- if offender == "" {
- continue
- }
- if cs.cfg.Allowlist.RegexAllowed(line) {
- continue
- }
- if rule.File.String() != "" && !rule.HasFileLeak(filepath.Base(to.Path())) {
- continue
- }
- if rule.Path.String() != "" && !rule.HasFilePathLeak(to.Path()) {
- continue
- }
- leak := NewLeak(line, offender, defaultLineNumber).WithCommit(cs.commit)
- leak.File = to.Path()
- leak.LineNumber = extractLine(patchContent, leak, lineLookup)
- leak.RepoURL = cs.opts.RepoURL
- leak.Repo = cs.repoName
- leak.LeakURL = leak.URL()
- leak.Rule = rule.Description
- leak.Tags = strings.Join(rule.Tags, ", ")
- leak.Log(cs.opts)
- scannerReport.Leaks = append(scannerReport.Leaks, leak)
- }
- }
- }
- }
- }
- scannerReport.Commits = 1
- return scannerReport, nil
- }
|