Просмотр исходного кода

fixing --commit bug, adding --files-at-commit option

zricethezav 6 лет назад
Родитель
Сommit
5a300c3c64
4 измененных файлов с 85 добавлено и 44 удалено
  1. 5 4
      audit/audit_test.go
  2. 6 13
      audit/repo.go
  3. 48 2
      audit/util.go
  4. 26 25
      options/options.go

+ 5 - 4
audit/audit_test.go

@@ -145,12 +145,13 @@ func TestAudit(t *testing.T) {
 			wantEmpty: true,
 		},
 		{
+					// TODO UPDATE TESTS
 			description: "test local repo one aws leak single commit",
 			opts: options.Options{
-				RepoPath:     "../test_data/test_repos/test_repo_1",
-				Report:       "../test_data/test_local_repo_one_aws_leak_commit.json.got",
-				Commit:       "6557c92612d3b35979bd426d429255b3bf9fab74",
-				ReportFormat: "json",
+				RepoPath:      "../test_data/test_repos/test_repo_1",
+				Report:        "../test_data/test_local_repo_one_aws_leak_commit.json.got",
+				FilesAtCommit: "6557c92612d3b35979bd426d429255b3bf9fab74",
+				ReportFormat:  "json",
 			},
 			wantPath: "../test_data/test_local_repo_one_aws_leak_commit.json",
 		},

+ 6 - 13
audit/repo.go

@@ -236,19 +236,12 @@ func (repo *Repo) Audit() error {
 
 	auditTimeStart := time.Now()
 
-	// audit single Commit
+	// audit commit patches OR all files at commit. See https://github.com/zricethezav/gitleaks/issues/326
+	// TODO having --commit= and --files-at-commit= set should probably be guarded against
 	if repo.Manager.Opts.Commit != "" {
-		h := plumbing.NewHash(repo.Manager.Opts.Commit)
-		c, err := repo.CommitObject(h)
-		if err != nil {
-			return err
-		}
-
-		err = inspectCommit(c, repo)
-		if err != nil {
-			return err
-		}
-		return nil
+		return inspectCommit(repo.Manager.Opts.Commit, repo, inspectCommitPatches)
+	} else if repo.Manager.Opts.FilesAtCommit != "" {
+		return inspectCommit(repo.Manager.Opts.FilesAtCommit, repo, inspectFilesAtCommit)
 	}
 
 	logOpts, err := getLogOptions(repo)
@@ -271,7 +264,7 @@ func (repo *Repo) Audit() error {
 
 		if len(c.ParentHashes) == 0 {
 			cc++
-			err = inspectCommit(c, repo)
+			err = inspectFilesAtCommit(c, repo)
 			if err != nil {
 				return err
 			}

+ 48 - 2
audit/util.go

@@ -255,11 +255,57 @@ func InspectString(content string, c *object.Commit, repo *Repo, filename string
 	}
 }
 
-// inspectCommit accepts a commit object and a repo. This function is only called when the --commit=
+type commitInspector func(c *object.Commit, repo *Repo) error
+
+func inspectCommit(hash string, repo *Repo, f commitInspector) error {
+	h := plumbing.NewHash(hash)
+	c, err := repo.CommitObject(h)
+	if err != nil {
+		return err
+	}
+	return f(c, repo)
+}
+
+// inspectCommitPatches accepts a commit object and a repo. This function is only called when the --commit=
+// option has been set. That option tells gitleaks to look only at a single commit and check the contents
+// of said commit. Similar to inspectPatch(), if the files contained in the commit are a binaries or if they are
+// whitelisted then those files will be skipped.
+func inspectCommitPatches(c *object.Commit, repo *Repo) error {
+	if len(c.ParentHashes) == 0 {
+		err := inspectFilesAtCommit(c, repo)
+		if err != nil {
+			return err
+		}
+	}
+
+	return c.Parents().ForEach(func(parent *object.Commit) error {
+		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.
+				// Once a fix has been merged I will remove this recover.
+				return
+			}
+		}()
+		if repo.timeoutReached() {
+			return nil
+		}
+		start := time.Now()
+		patch, err := c.Patch(parent)
+		if err != nil {
+			return fmt.Errorf("could not generate patch")
+		}
+		repo.Manager.RecordTime(manager.PatchTime(howLong(start)))
+		inspectPatch(patch, c, repo)
+		return nil
+	})
+}
+
+// inspectFilesAtCommit accepts a commit object and a repo. This function is only called when the --commit=
 // option has been set. That option tells gitleaks to look only at a single commit and check the contents
 // of said commit. Similar to inspectPatch(), if the files contained in the commit are a binaries or if they are
 // whitelisted then those files will be skipped.
-func inspectCommit(c *object.Commit, repo *Repo) error {
+func inspectFilesAtCommit(c *object.Commit, repo *Repo) error {
 	fIter, err := c.Files()
 	if err != nil {
 		return err

+ 26 - 25
options/options.go

@@ -27,31 +27,32 @@ const (
 
 // Options stores values of command line options
 type Options struct {
-	Verbose      bool   `short:"v" long:"verbose" description:"Show verbose output from audit"`
-	Repo         string `short:"r" long:"repo" description:"Target repository"`
-	Config       string `long:"config" description:"config path"`
-	Disk         bool   `long:"disk" description:"Clones repo(s) to disk"`
-	Version      bool   `long:"version" description:"version number"`
-	Username     string `long:"username" description:"Username for git repo"`
-	Password     string `long:"password" description:"Password for git repo"`
-	AccessToken  string `long:"access-token" description:"Access token for git repo"`
-	Commit       string `long:"commit" description:"sha of commit to audit"`
-	Threads      int    `long:"threads" description:"Maximum number of threads gitleaks spawns"`
-	SSH          string `long:"ssh-key" description:"path to ssh key used for auth"`
-	Uncommited   bool   `long:"uncommitted" description:"run gitleaks on uncommitted code"`
-	RepoPath     string `long:"repo-path" description:"Path to repo"`
-	OwnerPath    string `long:"owner-path" description:"Path to owner directory (repos discovered)"`
-	Branch       string `long:"branch" description:"Branch to audit"`
-	Report       string `long:"report" description:"path to write json leaks file"`
-	ReportFormat string `long:"report-format" default:"json" description:"json or csv"`
-	Redact       bool   `long:"redact" description:"redact secrets from log messages and leaks"`
-	Debug        bool   `long:"debug" description:"log debug messages"`
-	RepoConfig   bool   `long:"repo-config" description:"Load config from target repo. Config file must be \".gitleaks.toml\" or \"gitleaks.toml\""`
-	PrettyPrint  bool   `long:"pretty" description:"Pretty print json if leaks are present"`
-	CommitFrom   string `long:"commit-from" description:"Commit to start audit from"`
-	CommitTo     string `long:"commit-to" description:"Commit to stop audit"`
-	Timeout      string `long:"timeout" description:"Time allowed per audit. Ex: 10us, 30s, 1m, 1h10m1s"`
-	Depth        int    `long:"depth" description:"Number of commits to audit"`
+	Verbose       bool   `short:"v" long:"verbose" description:"Show verbose output from audit"`
+	Repo          string `short:"r" long:"repo" description:"Target repository"`
+	Config        string `long:"config" description:"config path"`
+	Disk          bool   `long:"disk" description:"Clones repo(s) to disk"`
+	Version       bool   `long:"version" description:"version number"`
+	Username      string `long:"username" description:"Username for git repo"`
+	Password      string `long:"password" description:"Password for git repo"`
+	AccessToken   string `long:"access-token" description:"Access token for git repo"`
+	Commit        string `long:"commit" description:"sha of commit to audit"`
+	FilesAtCommit string `long:"files-at-commit" description:"sha of commit to audit all files at commit"`
+	Threads       int    `long:"threads" description:"Maximum number of threads gitleaks spawns"`
+	SSH           string `long:"ssh-key" description:"path to ssh key used for auth"`
+	Uncommited    bool   `long:"uncommitted" description:"run gitleaks on uncommitted code"`
+	RepoPath      string `long:"repo-path" description:"Path to repo"`
+	OwnerPath     string `long:"owner-path" description:"Path to owner directory (repos discovered)"`
+	Branch        string `long:"branch" description:"Branch to audit"`
+	Report        string `long:"report" description:"path to write json leaks file"`
+	ReportFormat  string `long:"report-format" default:"json" description:"json or csv"`
+	Redact        bool   `long:"redact" description:"redact secrets from log messages and leaks"`
+	Debug         bool   `long:"debug" description:"log debug messages"`
+	RepoConfig    bool   `long:"repo-config" description:"Load config from target repo. Config file must be \".gitleaks.toml\" or \"gitleaks.toml\""`
+	PrettyPrint   bool   `long:"pretty" description:"Pretty print json if leaks are present"`
+	CommitFrom    string `long:"commit-from" description:"Commit to start audit from"`
+	CommitTo      string `long:"commit-to" description:"Commit to stop audit"`
+	Timeout       string `long:"timeout" description:"Time allowed per audit. Ex: 10us, 30s, 1m, 1h10m1s"`
+	Depth         int    `long:"depth" description:"Number of commits to audit"`
 
 	// Hosts
 	Host         string `long:"host" description:"git hosting service like gitlab or github. Supported hosts include: Github, Gitlab"`