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

Empty repo audit (#364)

* bump to go 1.14 and alpine to 3.11

* audit before commit

* adding test

* rm hooks in test repo
Zachary Rice 5 лет назад
Родитель
Сommit
212232f80a

+ 34 - 15
audit/audit_test.go

@@ -383,22 +383,39 @@ func TestAuditUncommited(t *testing.T) {
 			fileToChange: "server.test.py",
 			addition:     "nothing bad",
 		},
+		{
+			description: "test audit repo with no commits",
+			opts: options.Options{
+				RepoPath:     "../test_data/test_repos/test_repo_7",
+				Report:       "../test_data/test_local_repo_seven_aws_leak_uncommitted.json.got",
+				Uncommited:   true,
+				ReportFormat: "json",
+			},
+			wantPath: "../test_data/test_local_repo_seven_aws_leak_uncommitted.json",
+		},
 	}
 	for _, test := range tests {
+		var (
+			old []byte
+			err error
+		)
 		fmt.Println(test.description)
-		old, err := ioutil.ReadFile(fmt.Sprintf("%s/%s", test.opts.RepoPath, test.fileToChange))
-		if err != nil {
-			t.Error(err)
-		}
-		altered, err := os.OpenFile(fmt.Sprintf("%s/%s", test.opts.RepoPath, test.fileToChange),
-			os.O_WRONLY|os.O_APPEND, 0644)
-		if err != nil {
-			t.Error(err)
-		}
+		if test.fileToChange != "" {
+			old, err = ioutil.ReadFile(fmt.Sprintf("%s/%s", test.opts.RepoPath, test.fileToChange))
+			if err != nil {
+				t.Error(err)
+			}
+			altered, err := os.OpenFile(fmt.Sprintf("%s/%s", test.opts.RepoPath, test.fileToChange),
+				os.O_WRONLY|os.O_APPEND, 0644)
+			if err != nil {
+				t.Error(err)
+			}
+
+			_, err = altered.WriteString(test.addition)
+			if err != nil {
+				t.Error(err)
+			}
 
-		_, err = altered.WriteString(test.addition)
-		if err != nil {
-			t.Error(err)
 		}
 
 		cfg, err := config.NewConfig(test.opts)
@@ -418,9 +435,11 @@ func TestAuditUncommited(t *testing.T) {
 			t.Error(err)
 		}
 
-		err = ioutil.WriteFile(fmt.Sprintf("%s/%s", test.opts.RepoPath, test.fileToChange), old, 0)
-		if err != nil {
-			t.Error(err)
+		if test.fileToChange != "" {
+			err = ioutil.WriteFile(fmt.Sprintf("%s/%s", test.opts.RepoPath, test.fileToChange), old, 0)
+			if err != nil {
+				t.Error(err)
+			}
 		}
 
 		if test.wantEmpty {

+ 42 - 3
audit/repo.go

@@ -87,6 +87,42 @@ func (repo *Repo) Clone(cloneOption *git.CloneOptions) error {
 	return nil
 }
 
+func emptyCommit() *object.Commit {
+	return &object.Commit{
+		Hash:    plumbing.Hash{},
+		Message: "***STAGED CHANGES***",
+		Author: object.Signature{
+			Name:  "",
+			Email: "",
+			When:  time.Unix(0, 0).UTC(),
+		},
+	}
+}
+
+// auditEmpty audits an empty repo without any commits. See https://github.com/zricethezav/gitleaks/issues/352
+func (repo *Repo) auditEmpty() error {
+	auditTimeStart := time.Now()
+	wt, err := repo.Worktree()
+	if err != nil {
+		return err
+	}
+
+	status, err := wt.Status()
+	for fn := range status {
+		workTreeBuf := bytes.NewBuffer(nil)
+		workTreeFile, err := wt.Filesystem.Open(fn)
+		if err != nil {
+			continue
+		}
+		if _, err := io.Copy(workTreeBuf, workTreeFile); err != nil {
+			return err
+		}
+		InspectFile(workTreeBuf.String(), workTreeFile.Name(), emptyCommit(), repo)
+	}
+	repo.Manager.RecordTime(manager.AuditTime(howLong(auditTimeStart)))
+	return nil
+}
+
 // AuditUncommitted will do a `git diff` and scan changed files that are being tracked. This is useful functionality
 // for a pre-commit hook so you can make sure your code does not have any leaks before committing.
 func (repo *Repo) AuditUncommitted() error {
@@ -103,13 +139,16 @@ func (repo *Repo) AuditUncommitted() error {
 		return err
 	}
 
-	auditTimeStart := time.Now()
-
 	r, err := repo.Head()
-	if err != nil {
+	if err == plumbing.ErrReferenceNotFound {
+		// possibly an empty repo, or maybe its not, either way lets scan all the files in the directory
+		return repo.auditEmpty()
+	} else if err != nil {
 		return err
 	}
 
+	auditTimeStart := time.Now()
+
 	c, err := repo.CommitObject(r.Hash())
 	if err != nil {
 		return err

+ 15 - 0
test_data/test_local_repo_seven_aws_leak_uncommitted.json

@@ -0,0 +1,15 @@
+[
+ {
+  "line": "AKIAIO5FODNN7EXAMPLE",
+  "offender": "AKIAIO5FODNN7EXAMPLE",
+  "commit": "0000000000000000000000000000000000000000",
+  "repo": "test_repo_7",
+  "rule": "AWS Manager ID",
+  "commitMessage": "***STAGED CHANGES***",
+  "author": "",
+  "email": "",
+  "file": "file",
+  "date": "1970-01-01T00:00:00Z",
+  "tags": "key, AWS"
+ }
+]

+ 1 - 0
test_data/test_repos/test_repo_7/dotGit/HEAD

@@ -0,0 +1 @@
+ref: refs/heads/master

+ 7 - 0
test_data/test_repos/test_repo_7/dotGit/config

@@ -0,0 +1,7 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = false
+	logallrefupdates = true
+	ignorecase = true
+	precomposeunicode = true

+ 1 - 0
test_data/test_repos/test_repo_7/dotGit/description

@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.

+ 6 - 0
test_data/test_repos/test_repo_7/dotGit/info/exclude

@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~

+ 6 - 0
test_data/test_repos/test_repo_7/file

@@ -0,0 +1,6 @@
+This repo has no commits in it
+
+but it does have an AWS key
+
+AKIAIO5FODNN7EXAMPLE
+