|
|
@@ -34,7 +34,9 @@ import (
|
|
|
git "gopkg.in/src-d/go-git.v4"
|
|
|
)
|
|
|
|
|
|
-// Leak represents a leaked secret or regex match. This will be output to stdout and/or the report
|
|
|
+// Leak represents a leaked secret or regex match.
|
|
|
+// Output to stdout as json if the --verbose option is set or
|
|
|
+// as a csv if the --csv and --report options are set.
|
|
|
type Leak struct {
|
|
|
Line string `json:"line"`
|
|
|
Commit string `json:"commit"`
|
|
|
@@ -47,23 +49,15 @@ type Leak struct {
|
|
|
Repo string `json:"repo"`
|
|
|
}
|
|
|
|
|
|
-// Repo contains the actual git repository and meta data about the repo
|
|
|
-type Repo struct {
|
|
|
+// RepoDescriptor contains a src-d git repository and other data about the repo
|
|
|
+type RepoDescriptor struct {
|
|
|
path string
|
|
|
url string
|
|
|
name string
|
|
|
- leaks []Leak
|
|
|
repository *git.Repository
|
|
|
err error
|
|
|
}
|
|
|
|
|
|
-// Owner contains a collection of repos. This could represent an org or user.
|
|
|
-type Owner struct {
|
|
|
- path string
|
|
|
- url string
|
|
|
- repos []Repo
|
|
|
-}
|
|
|
-
|
|
|
// Options for gitleaks
|
|
|
type Options struct {
|
|
|
// remote target options
|
|
|
@@ -118,8 +112,16 @@ type Config struct {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+type gitDiff struct {
|
|
|
+ content string
|
|
|
+ commit *object.Commit
|
|
|
+ filePath string
|
|
|
+ branchName string
|
|
|
+ repoName string
|
|
|
+}
|
|
|
+
|
|
|
const defaultGithubURL = "https://api.github.com/"
|
|
|
-const version = "1.7.2"
|
|
|
+const version = "1.7.3"
|
|
|
const errExit = 2
|
|
|
const leakExit = 1
|
|
|
const defaultConfig = `
|
|
|
@@ -211,6 +213,7 @@ func main() {
|
|
|
|
|
|
// run parses options and kicks off the audit
|
|
|
func run() ([]Leak, error) {
|
|
|
+ var leaks []Leak
|
|
|
setLogs()
|
|
|
err := optsGuard()
|
|
|
if err != nil {
|
|
|
@@ -235,52 +238,42 @@ func run() ([]Leak, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
}
|
|
|
- return startAudits()
|
|
|
-}
|
|
|
|
|
|
-func startAudits() ([]Leak, error) {
|
|
|
- var leaks []Leak
|
|
|
// start audits
|
|
|
if opts.Repo != "" || opts.RepoPath != "" {
|
|
|
- repo, err := getRepo()
|
|
|
+ // Audit a single remote repo or a local repo.
|
|
|
+ repo, err := cloneRepo()
|
|
|
if err != nil {
|
|
|
return leaks, err
|
|
|
}
|
|
|
- return auditRepo(repo)
|
|
|
+ return auditGitRepo(repo)
|
|
|
} else if opts.OwnerPath != "" {
|
|
|
+ // Audit local repos. Gitleaks will look for all child directories of OwnerPath for
|
|
|
+ // git repos and perform an audit on said repos.
|
|
|
repos, err := discoverRepos(opts.OwnerPath)
|
|
|
if err != nil {
|
|
|
return leaks, err
|
|
|
}
|
|
|
for _, repo := range repos {
|
|
|
- leaksFromRepo, err := auditRepo(repo)
|
|
|
+ leaksFromRepo, err := auditGitRepo(repo)
|
|
|
if err != nil {
|
|
|
return leaks, err
|
|
|
}
|
|
|
leaks = append(leaksFromRepo, leaks...)
|
|
|
}
|
|
|
} else if opts.GithubOrg != "" || opts.GithubUser != "" {
|
|
|
- githubRepos, err := getGithubRepos()
|
|
|
+ // Audit a github owner -- a user or organization. If you want to include
|
|
|
+ // private repos you must pass a --private/-p option and have your ssh keys set
|
|
|
+ leaks, err = auditGithubRepos()
|
|
|
if err != nil {
|
|
|
return leaks, err
|
|
|
}
|
|
|
- for _, githubRepo := range githubRepos {
|
|
|
- leaksFromRepo, err := auditGithubRepo(githubRepo)
|
|
|
- if len(leaksFromRepo) == 0 {
|
|
|
- log.Infof("no leaks found for repo %s", *githubRepo.Name)
|
|
|
- } else {
|
|
|
- log.Warnf("leaks found for repo %s", *githubRepo.Name)
|
|
|
- }
|
|
|
- if err != nil {
|
|
|
- log.Warn(err)
|
|
|
- }
|
|
|
- leaks = append(leaks, leaksFromRepo...)
|
|
|
- }
|
|
|
}
|
|
|
return leaks, nil
|
|
|
}
|
|
|
|
|
|
-// writeReport writes a report to opts.Report in JSON.
|
|
|
+// writeReport writes a report to a file specified in the --report= option.
|
|
|
+// Default format for report is JSON. You can use the --csv option to write the report as a csv
|
|
|
func writeReport(leaks []Leak) error {
|
|
|
var err error
|
|
|
log.Infof("writing report to %s", opts.Report)
|
|
|
@@ -303,9 +296,10 @@ func writeReport(leaks []Leak) error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-// getRepo is responsible for cloning a repo in-memory or to disk, or opening a local repo and creating
|
|
|
-// a repo object
|
|
|
-func getRepo() (Repo, error) {
|
|
|
+// cloneRepo clones a repo to memory(default) or to disk if the --disk option is set. If you want to
|
|
|
+// clone a private repo you must set the --private/-p option, use a ssh target, and have your ssh keys
|
|
|
+// configured. If you want to audit a local repo, getRepo will load up a repo located at --repo-path
|
|
|
+func cloneRepo() (*RepoDescriptor, error) {
|
|
|
var (
|
|
|
err error
|
|
|
repo *git.Repository
|
|
|
@@ -326,7 +320,6 @@ func getRepo() (Repo, error) {
|
|
|
})
|
|
|
}
|
|
|
} else if opts.RepoPath != "" {
|
|
|
- // use existing repo
|
|
|
log.Infof("opening %s", opts.Repo)
|
|
|
repo, err = git.PlainOpen(opts.RepoPath)
|
|
|
} else {
|
|
|
@@ -344,7 +337,7 @@ func getRepo() (Repo, error) {
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
- return Repo{
|
|
|
+ return &RepoDescriptor{
|
|
|
repository: repo,
|
|
|
path: opts.RepoPath,
|
|
|
url: opts.Repo,
|
|
|
@@ -353,10 +346,66 @@ func getRepo() (Repo, error) {
|
|
|
}, nil
|
|
|
}
|
|
|
|
|
|
-// auditRef audits a git reference
|
|
|
-// TODO: need to add a layer of parallelism here and a cache for parent+child commits so we don't
|
|
|
-// double dip
|
|
|
-func auditRef(repo Repo, ref *plumbing.Reference) []Leak {
|
|
|
+// auditGitRepo beings an audit on a git repository by checking the default HEAD branch, all branches, or
|
|
|
+// a single branch depending on what gitleaks is configured to do. Note when I say branch I really
|
|
|
+// mean reference as these branches are read only.
|
|
|
+func auditGitRepo(repo *RepoDescriptor) ([]Leak, error) {
|
|
|
+ var (
|
|
|
+ err error
|
|
|
+ leaks []Leak
|
|
|
+ )
|
|
|
+ ref, err := repo.repository.Head()
|
|
|
+ if err != nil {
|
|
|
+ return leaks, err
|
|
|
+ }
|
|
|
+
|
|
|
+ if opts.AuditAllRefs {
|
|
|
+ skipBranch := false
|
|
|
+ refs, err := repo.repository.Storer.IterReferences()
|
|
|
+ if err != nil {
|
|
|
+ return leaks, err
|
|
|
+ }
|
|
|
+ err = refs.ForEach(func(ref *plumbing.Reference) error {
|
|
|
+ for _, b := range whiteListBranches {
|
|
|
+ if strings.HasSuffix(string(ref.Name()), b) {
|
|
|
+ skipBranch = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if skipBranch {
|
|
|
+ skipBranch = false
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ branchLeaks := auditGitReference(repo, ref)
|
|
|
+ for _, leak := range branchLeaks {
|
|
|
+ leaks = append(leaks, leak)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ if opts.Branch != "" {
|
|
|
+ foundBranch := false
|
|
|
+ refs, _ := repo.repository.Storer.IterReferences()
|
|
|
+ branch := strings.Split(opts.Branch, "/")[len(strings.Split(opts.Branch, "/"))-1]
|
|
|
+ err = refs.ForEach(func(refBranch *plumbing.Reference) error {
|
|
|
+ if strings.Split(refBranch.Name().String(), "/")[len(strings.Split(refBranch.Name().String(), "/"))-1] == branch {
|
|
|
+ foundBranch = true
|
|
|
+ ref = refBranch
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ if foundBranch == false {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ leaks = auditGitReference(repo, ref)
|
|
|
+ }
|
|
|
+ return leaks, err
|
|
|
+}
|
|
|
+
|
|
|
+// auditGitReference beings the audit for a git reference. This function will
|
|
|
+// traverse the git reference and audit each line of each diff. Set maximum concurrency with
|
|
|
+// the --max-go option (default is set to the number of cores on your cpu).
|
|
|
+func auditGitReference(repo *RepoDescriptor, ref *plumbing.Reference) []Leak {
|
|
|
var (
|
|
|
err error
|
|
|
prevCommit *object.Commit
|
|
|
@@ -398,6 +447,11 @@ func auditRef(repo Repo, ref *plumbing.Reference) []Leak {
|
|
|
log.Warnf("recoverying from panic on commit %s, likely large diff causing panic", c.Hash.String())
|
|
|
}
|
|
|
}()
|
|
|
+ diff := gitDiff{
|
|
|
+ commit: prevCommit,
|
|
|
+ branchName: string(ref.Name()),
|
|
|
+ repoName: repoName,
|
|
|
+ }
|
|
|
|
|
|
if prevCommit == nil {
|
|
|
t, _ := c.Tree()
|
|
|
@@ -407,7 +461,10 @@ func auditRef(repo Repo, ref *plumbing.Reference) []Leak {
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- chunkLeaks := checkDiff(content, c, file.Name, string(ref.Name()), repoName)
|
|
|
+ diff.filePath = file.Name
|
|
|
+ diff.content = content
|
|
|
+ diff.commit = c
|
|
|
+ chunkLeaks := inspect(diff)
|
|
|
for _, leak := range chunkLeaks {
|
|
|
mutex.Lock()
|
|
|
leaks = append(leaks, leak)
|
|
|
@@ -434,6 +491,7 @@ func auditRef(repo Repo, ref *plumbing.Reference) []Leak {
|
|
|
} else if to != nil {
|
|
|
filePath = to.Path()
|
|
|
}
|
|
|
+ diff.filePath = filePath
|
|
|
for _, re := range whiteListFiles {
|
|
|
if re.FindString(filePath) != "" {
|
|
|
skipFile = true
|
|
|
@@ -446,8 +504,8 @@ func auditRef(repo Repo, ref *plumbing.Reference) []Leak {
|
|
|
chunks := f.Chunks()
|
|
|
for _, chunk := range chunks {
|
|
|
if chunk.Type() == 1 || chunk.Type() == 2 {
|
|
|
- // only check if adding or removing
|
|
|
- chunkLeaks := checkDiff(chunk.Content(), prevCommit, filePath, string(ref.Name()), repoName)
|
|
|
+ diff.content = chunk.Content()
|
|
|
+ chunkLeaks := inspect(diff)
|
|
|
for _, leak := range chunkLeaks {
|
|
|
mutex.Lock()
|
|
|
leaks = append(leaks, leak)
|
|
|
@@ -465,66 +523,12 @@ func auditRef(repo Repo, ref *plumbing.Reference) []Leak {
|
|
|
return leaks
|
|
|
}
|
|
|
|
|
|
-// auditRepo performs an audit on a repository checking for regex matching and ignoring
|
|
|
-// files and regexes that are whitelisted
|
|
|
-func auditRepo(repo Repo) ([]Leak, error) {
|
|
|
- var (
|
|
|
- err error
|
|
|
- leaks []Leak
|
|
|
- )
|
|
|
-
|
|
|
- ref, err := repo.repository.Head()
|
|
|
- if err != nil {
|
|
|
- return leaks, err
|
|
|
- }
|
|
|
-
|
|
|
- if opts.AuditAllRefs {
|
|
|
- skipBranch := false
|
|
|
- refs, err := repo.repository.Storer.IterReferences()
|
|
|
- if err != nil {
|
|
|
- return leaks, err
|
|
|
- }
|
|
|
- err = refs.ForEach(func(ref *plumbing.Reference) error {
|
|
|
- for _, b := range whiteListBranches {
|
|
|
- if strings.HasSuffix(string(ref.Name()), b) {
|
|
|
- skipBranch = true
|
|
|
- }
|
|
|
- }
|
|
|
- if skipBranch {
|
|
|
- skipBranch = false
|
|
|
- return nil
|
|
|
- }
|
|
|
- branchLeaks := auditRef(repo, ref)
|
|
|
- for _, leak := range branchLeaks {
|
|
|
- leaks = append(leaks, leak)
|
|
|
- }
|
|
|
- return nil
|
|
|
- })
|
|
|
- } else {
|
|
|
- if opts.Branch != "" {
|
|
|
- foundBranch := false
|
|
|
- refs, _ := repo.repository.Storer.IterReferences()
|
|
|
- branch := strings.Split(opts.Branch, "/")[len(strings.Split(opts.Branch, "/"))-1]
|
|
|
- err = refs.ForEach(func(refBranch *plumbing.Reference) error {
|
|
|
- if strings.Split(refBranch.Name().String(), "/")[len(strings.Split(refBranch.Name().String(), "/"))-1] == branch {
|
|
|
- foundBranch = true
|
|
|
- ref = refBranch
|
|
|
- }
|
|
|
- return nil
|
|
|
- })
|
|
|
- if foundBranch == false {
|
|
|
- return nil, nil
|
|
|
- }
|
|
|
- }
|
|
|
- leaks = auditRef(repo, ref)
|
|
|
- }
|
|
|
- return leaks, err
|
|
|
-}
|
|
|
-
|
|
|
-// checkDiff accepts a string diff and commit object then performs a
|
|
|
-// regex check
|
|
|
-func checkDiff(diff string, commit *object.Commit, filePath string, branch string, repo string) []Leak {
|
|
|
- lines := strings.Split(diff, "\n")
|
|
|
+// inspect will parse each line of the git diff's content against a set of regexes or
|
|
|
+// a set of regexes set by the config (see gitleaks.toml for example). This function
|
|
|
+// will skip lines that include a whitelisted regex. A list of leaks is returned.
|
|
|
+// If verbose mode (-v/--verbose) is set, then checkDiff will log leaks as they are discovered.
|
|
|
+func inspect(diff gitDiff) []Leak {
|
|
|
+ lines := strings.Split(diff.content, "\n")
|
|
|
var (
|
|
|
leaks []Leak
|
|
|
skipLine bool
|
|
|
@@ -552,14 +556,14 @@ func checkDiff(diff string, commit *object.Commit, filePath string, branch strin
|
|
|
|
|
|
leak := Leak{
|
|
|
Line: line,
|
|
|
- Commit: commit.Hash.String(),
|
|
|
+ Commit: diff.commit.Hash.String(),
|
|
|
Offender: match,
|
|
|
Type: leakType,
|
|
|
- Message: commit.Message,
|
|
|
- Author: commit.Author.String(),
|
|
|
- File: filePath,
|
|
|
- Branch: branch,
|
|
|
- Repo: repo,
|
|
|
+ Message: diff.commit.Message,
|
|
|
+ Author: diff.commit.Author.String(),
|
|
|
+ File: diff.filePath,
|
|
|
+ Branch: diff.branchName,
|
|
|
+ Repo: diff.repoName,
|
|
|
}
|
|
|
if opts.Redact {
|
|
|
leak.Offender = "REDACTED"
|
|
|
@@ -574,16 +578,22 @@ func checkDiff(diff string, commit *object.Commit, filePath string, branch strin
|
|
|
return leaks
|
|
|
}
|
|
|
|
|
|
-// auditOwner audits all of the owner's(user or org) repos
|
|
|
-func getGithubRepos() ([]*github.Repository, error) {
|
|
|
+// auditGithubRepos kicks off audits if --github-user or --github-org options are set.
|
|
|
+// First, we gather all the github repositories from the github api (this doesnt actually clone the repo).
|
|
|
+// After all the repos have been pulled from github's api we proceed to audit the repos by calling auditGithubRepo.
|
|
|
+// If an error occurs during an audit of a repo, that error is logged but won't break the execution cycle.
|
|
|
+func auditGithubRepos() ([]Leak, error) {
|
|
|
var (
|
|
|
err error
|
|
|
githubRepos []*github.Repository
|
|
|
- rs []*github.Repository
|
|
|
+ pagedGithubRepos []*github.Repository
|
|
|
resp *github.Response
|
|
|
githubClient *github.Client
|
|
|
githubOrgOptions *github.RepositoryListByOrgOptions
|
|
|
githubOptions *github.RepositoryListOptions
|
|
|
+ done bool
|
|
|
+ leaks []Leak
|
|
|
+ ownerDir string
|
|
|
)
|
|
|
ctx := context.Background()
|
|
|
|
|
|
@@ -612,56 +622,87 @@ func getGithubRepos() ([]*github.Repository, error) {
|
|
|
}
|
|
|
|
|
|
for {
|
|
|
+ if done {
|
|
|
+ break
|
|
|
+ }
|
|
|
if opts.GithubUser != "" {
|
|
|
if opts.IncludePrivate {
|
|
|
- rs, resp, err = githubClient.Repositories.List(ctx, "", githubOptions)
|
|
|
+ pagedGithubRepos, resp, err = githubClient.Repositories.List(ctx, "", githubOptions)
|
|
|
} else {
|
|
|
- rs, resp, err = githubClient.Repositories.List(ctx, opts.GithubUser, githubOptions)
|
|
|
+ pagedGithubRepos, resp, err = githubClient.Repositories.List(ctx, opts.GithubUser, githubOptions)
|
|
|
}
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ done = true
|
|
|
}
|
|
|
githubOptions.Page = resp.NextPage
|
|
|
- githubRepos = append(githubRepos, rs...)
|
|
|
+ githubRepos = append(githubRepos, pagedGithubRepos...)
|
|
|
if resp.NextPage == 0 {
|
|
|
- return githubRepos, err
|
|
|
+ done = true
|
|
|
}
|
|
|
} else if opts.GithubOrg != "" {
|
|
|
- rs, resp, err = githubClient.Repositories.ListByOrg(ctx, opts.GithubOrg, githubOrgOptions)
|
|
|
+ pagedGithubRepos, resp, err = githubClient.Repositories.ListByOrg(ctx, opts.GithubOrg, githubOrgOptions)
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ done = true
|
|
|
}
|
|
|
githubOrgOptions.Page = resp.NextPage
|
|
|
- githubRepos = append(githubRepos, rs...)
|
|
|
+ githubRepos = append(githubRepos, pagedGithubRepos...)
|
|
|
if resp.NextPage == 0 {
|
|
|
- return githubRepos, err
|
|
|
+ done = true
|
|
|
}
|
|
|
}
|
|
|
if opts.Log == "Debug" || opts.Log == "debug" {
|
|
|
- for _, githubRepo := range rs {
|
|
|
+ for _, githubRepo := range pagedGithubRepos {
|
|
|
log.Debugf("staging repos %s", *githubRepo.Name)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ if opts.Disk {
|
|
|
+ ownerDir, err = ioutil.TempDir(dir, opts.GithubUser)
|
|
|
+ os.RemoveAll(ownerDir)
|
|
|
+ }
|
|
|
+ for _, githubRepo := range githubRepos {
|
|
|
+ repo, err := cloneGithubRepo(githubRepo)
|
|
|
+ if err != nil {
|
|
|
+ log.Warn(err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ leaksFromRepo, err := auditGitRepo(repo)
|
|
|
+ if opts.Disk {
|
|
|
+ os.RemoveAll(fmt.Sprintf("%s/%s", ownerDir, *githubRepo.Name))
|
|
|
+ }
|
|
|
+ if len(leaksFromRepo) == 0 {
|
|
|
+ log.Infof("no leaks found for repo %s", *githubRepo.Name)
|
|
|
+ } else {
|
|
|
+ log.Warnf("leaks found for repo %s", *githubRepo.Name)
|
|
|
+ }
|
|
|
+ if err != nil {
|
|
|
+ log.Warn(err)
|
|
|
+ }
|
|
|
+ leaks = append(leaks, leaksFromRepo...)
|
|
|
+ }
|
|
|
+ return leaks, nil
|
|
|
}
|
|
|
|
|
|
-// auditGithubRepo clones repos from github
|
|
|
-func auditGithubRepo(githubRepo *github.Repository) ([]Leak, error) {
|
|
|
+// cloneGithubRepo clones a repo from the url parsed from a github repo. The repo
|
|
|
+// will be cloned to disk if --disk is set. If the repo is private, you must include the
|
|
|
+// --private/-p option. After the repo is clone, an audit will begin.
|
|
|
+func cloneGithubRepo(githubRepo *github.Repository) (*RepoDescriptor, error) {
|
|
|
var (
|
|
|
- leaks []Leak
|
|
|
- repo *git.Repository
|
|
|
- err error
|
|
|
+ repo *git.Repository
|
|
|
+ err error
|
|
|
)
|
|
|
log.Infof("cloning: %s", *githubRepo.Name)
|
|
|
if opts.Disk {
|
|
|
ownerDir, err := ioutil.TempDir(dir, opts.GithubUser)
|
|
|
- defer os.RemoveAll(fmt.Sprintf("%s/%s", ownerDir, *githubRepo.Name))
|
|
|
if err != nil {
|
|
|
- return leaks, fmt.Errorf("unable to generater owner temp dir: %v", err)
|
|
|
+ return nil, fmt.Errorf("unable to generater owner temp dir: %v", err)
|
|
|
}
|
|
|
if opts.IncludePrivate {
|
|
|
if sshAuth == nil {
|
|
|
- return leaks, fmt.Errorf("no ssh auth available")
|
|
|
+ return nil, fmt.Errorf("no ssh auth available")
|
|
|
}
|
|
|
repo, err = git.PlainClone(fmt.Sprintf("%s/%s", ownerDir, *githubRepo.Name), false, &git.CloneOptions{
|
|
|
URL: *githubRepo.SSHURL,
|
|
|
@@ -675,7 +716,7 @@ func auditGithubRepo(githubRepo *github.Repository) ([]Leak, error) {
|
|
|
} else {
|
|
|
if opts.IncludePrivate {
|
|
|
if sshAuth == nil {
|
|
|
- return leaks, fmt.Errorf("no ssh auth available")
|
|
|
+ return nil, fmt.Errorf("no ssh auth available")
|
|
|
}
|
|
|
repo, err = git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
|
|
|
URL: *githubRepo.SSHURL,
|
|
|
@@ -688,15 +729,16 @@ func auditGithubRepo(githubRepo *github.Repository) ([]Leak, error) {
|
|
|
}
|
|
|
}
|
|
|
if err != nil {
|
|
|
- return leaks, err
|
|
|
+ return nil, err
|
|
|
}
|
|
|
- return auditRepo(Repo{
|
|
|
+ return &RepoDescriptor{
|
|
|
repository: repo,
|
|
|
name: *githubRepo.Name,
|
|
|
- })
|
|
|
+ }, nil
|
|
|
}
|
|
|
|
|
|
-// githubToken returns a oauth2 client for the github api to consume
|
|
|
+// githubToken returns an oauth2 client for the github api to consume. This token is necessary
|
|
|
+// if you are running audits with --github-user or --github-org
|
|
|
func githubToken() *http.Client {
|
|
|
githubToken := os.Getenv("GITHUB_TOKEN")
|
|
|
if githubToken == "" {
|
|
|
@@ -709,11 +751,11 @@ func githubToken() *http.Client {
|
|
|
}
|
|
|
|
|
|
// discoverRepos walks all the children of `path`. If a child directory
|
|
|
-// contain a .git file then that repo will be added
|
|
|
-func discoverRepos(ownerPath string) ([]Repo, error) {
|
|
|
+// contain a .git file then that repo will be added to the list of repos returned
|
|
|
+func discoverRepos(ownerPath string) ([]*RepoDescriptor, error) {
|
|
|
var (
|
|
|
err error
|
|
|
- repos []Repo
|
|
|
+ repos []*RepoDescriptor
|
|
|
)
|
|
|
files, err := ioutil.ReadDir(ownerPath)
|
|
|
if err != nil {
|
|
|
@@ -726,7 +768,7 @@ func discoverRepos(ownerPath string) ([]Repo, error) {
|
|
|
if err != nil {
|
|
|
continue
|
|
|
}
|
|
|
- repos = append(repos, Repo{
|
|
|
+ repos = append(repos, &RepoDescriptor{
|
|
|
repository: r,
|
|
|
name: f.Name(),
|
|
|
path: repoPath,
|
|
|
@@ -797,9 +839,11 @@ func optsGuard() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-// loadToml loads of the toml config containing regexes and whitelists
|
|
|
-// 1. look for config path
|
|
|
-// 2. two, look for gitleaks config env var
|
|
|
+// loadToml loads of the toml config containing regexes and whitelists.
|
|
|
+// This function will first look if the configPath is set and load the config
|
|
|
+// from that file. Otherwise will then look for the path set by the GITHLEAKS_CONIFG
|
|
|
+// env var. If that is not set, then gitleaks will continue with the default configs
|
|
|
+// specified by the const var at the top `defaultConfig`
|
|
|
func loadToml() error {
|
|
|
var (
|
|
|
config Config
|
|
|
@@ -826,9 +870,7 @@ func loadToml() error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // load up regexes
|
|
|
if singleSearchRegex != nil {
|
|
|
- // single search takes precedence over default regex
|
|
|
regexes["singleSearch"] = singleSearchRegex
|
|
|
} else {
|
|
|
for _, regex := range config.Regexes {
|
|
|
@@ -850,7 +892,9 @@ func loadToml() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-// getSSHAuth generates ssh auth
|
|
|
+// getSSHAuth return an ssh auth use by go-git to clone repos behind authentication.
|
|
|
+// If --ssh-key is set then it will attempt to load the key from that path. If not,
|
|
|
+// gitleaks will use the default $HOME/.ssh/id_rsa key
|
|
|
func getSSHAuth() (*ssh.PublicKeys, error) {
|
|
|
var (
|
|
|
sshKeyPath string
|