[oc-147] - Add context to all git methods (#901)
* Add context to all git methods. * remove logrus. * Add ctx. * Address comments. * Add error to clone failing. * Return error.
This commit is contained in:
@@ -162,7 +162,7 @@ func main() {
|
|||||||
defer sem.Release(1)
|
defer sem.Release(1)
|
||||||
defer wgChunkers.Done()
|
defer wgChunkers.Done()
|
||||||
log.Infof("cloning %s", r)
|
log.Infof("cloning %s", r)
|
||||||
path, repo, err := git.CloneRepoUsingUnauthenticated(r)
|
path, repo, err := git.CloneRepoUsingUnauthenticated(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ func run(state overseer.State) {
|
|||||||
var remote bool
|
var remote bool
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case gitScan.FullCommand():
|
case gitScan.FullCommand():
|
||||||
repoPath, remote, err = git.PrepareRepoSinceCommit(*gitScanURI, *gitScanSinceCommit)
|
repoPath, remote, err = git.PrepareRepoSinceCommit(ctx, *gitScanURI, *gitScanSinceCommit)
|
||||||
if err != nil || repoPath == "" {
|
if err != nil || repoPath == "" {
|
||||||
logrus.WithError(err).Fatal("error preparing git repo for scanning")
|
logrus.WithError(err).Fatal("error preparing git repo for scanning")
|
||||||
}
|
}
|
||||||
@@ -282,7 +282,7 @@ func run(state overseer.State) {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case *jsonLegacy:
|
case *jsonLegacy:
|
||||||
output.PrintLegacyJSON(&r)
|
output.PrintLegacyJSON(ctx, &r)
|
||||||
case *jsonOut:
|
case *jsonOut:
|
||||||
output.PrintJSON(&r)
|
output.PrintJSON(&r)
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ type expResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGitEngine(t *testing.T) {
|
func TestGitEngine(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
repoUrl := "https://github.com/dustin-decker/secretsandstuff.git"
|
repoUrl := "https://github.com/dustin-decker/secretsandstuff.git"
|
||||||
path, _, err := git.PrepareRepo(repoUrl)
|
path, _, err := git.PrepareRepo(ctx, repoUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -89,8 +90,9 @@ func TestGitEngine(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGitEngine(b *testing.B) {
|
func BenchmarkGitEngine(b *testing.B) {
|
||||||
|
ctx := context.Background()
|
||||||
repoUrl := "https://github.com/dustin-decker/secretsandstuff.git"
|
repoUrl := "https://github.com/dustin-decker/secretsandstuff.git"
|
||||||
path, _, err := git.PrepareRepo(repoUrl)
|
path, _, err := git.PrepareRepo(ctx, repoUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ import (
|
|||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrintLegacyJSON(r *detectors.ResultWithMetadata) {
|
func PrintLegacyJSON(ctx context.Context, r *detectors.ResultWithMetadata) {
|
||||||
var repo string
|
var repo string
|
||||||
switch r.SourceType {
|
switch r.SourceType {
|
||||||
case sourcespb.SourceType_SOURCE_TYPE_GIT:
|
case sourcespb.SourceType_SOURCE_TYPE_GIT:
|
||||||
@@ -32,7 +34,7 @@ func PrintLegacyJSON(r *detectors.ResultWithMetadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cloning the repo again here is not great and only works with unauthed repos
|
// cloning the repo again here is not great and only works with unauthed repos
|
||||||
repoPath, remote, err := git.PrepareRepo(repo)
|
repoPath, remote, err := git.PrepareRepo(ctx, repo)
|
||||||
if err != nil || repoPath == "" {
|
if err != nil || repoPath == "" {
|
||||||
logrus.WithError(err).Fatal("error preparing git repo for scanning")
|
logrus.WithError(err).Fatal("error preparing git repo for scanning")
|
||||||
}
|
}
|
||||||
|
|||||||
+72
-70
@@ -20,8 +20,6 @@ import (
|
|||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/google/go-github/v42/github"
|
"github.com/google/go-github/v42/github"
|
||||||
"github.com/rs/zerolog"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
@@ -140,7 +138,7 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := func(repoURI string) error {
|
err := func(repoURI string) error {
|
||||||
path, repo, err := CloneRepoUsingToken(token, repoURI, user)
|
path, repo, err := CloneRepoUsingToken(ctx, token, repoURI, user)
|
||||||
defer os.RemoveAll(path)
|
defer os.RemoveAll(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -158,7 +156,7 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := func(repoURI string) error {
|
err := func(repoURI string) error {
|
||||||
path, repo, err := CloneRepoUsingUnauthenticated(repoURI)
|
path, repo, err := CloneRepoUsingUnauthenticated(ctx, repoURI)
|
||||||
defer os.RemoveAll(path)
|
defer os.RemoveAll(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -176,7 +174,7 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := func(repoURI string) error {
|
err := func(repoURI string) error {
|
||||||
path, repo, err := CloneRepoUsingSSH(repoURI)
|
path, repo, err := CloneRepoUsingSSH(ctx, repoURI)
|
||||||
defer os.RemoveAll(path)
|
defer os.RemoveAll(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -217,6 +215,8 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.Logger().V(1).Info("Git source finished scanning", "repo-count", len(s.conn.Repositories))
|
||||||
s.SetProgressComplete(len(s.conn.Repositories), len(s.conn.Repositories), fmt.Sprintf("Completed scanning source %s", s.name), "")
|
s.SetProgressComplete(len(s.conn.Repositories), len(s.conn.Repositories), fmt.Sprintf("Completed scanning source %s", s.name), "")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -246,14 +246,13 @@ func gitURLParse(gitURL string) (*url.URL, error) {
|
|||||||
return parsedURL, nil
|
return parsedURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CloneRepo(userInfo *url.Userinfo, gitUrl string, args ...string) (clonePath string, repo *git.Repository, err error) {
|
func CloneRepo(ctx context.Context, userInfo *url.Userinfo, gitUrl string, args ...string) (string, *git.Repository, error) {
|
||||||
if err = GitCmdCheck(); err != nil {
|
if err := gitCmdCheck(); err != nil {
|
||||||
return
|
return "", nil, err
|
||||||
}
|
}
|
||||||
clonePath, err = ioutil.TempDir(os.TempDir(), "trufflehog")
|
clonePath, err := ioutil.TempDir(os.TempDir(), "trufflehog")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.New(err)
|
return "", nil, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer CleanOnError(&err, clonePath)
|
defer CleanOnError(&err, clonePath)
|
||||||
cloneURL, err := gitURLParse(gitUrl)
|
cloneURL, err := gitURLParse(gitUrl)
|
||||||
@@ -279,38 +278,40 @@ func CloneRepo(userInfo *url.Userinfo, gitUrl string, args ...string) (clonePath
|
|||||||
if cloneCmd.ProcessState != nil && cloneCmd.ProcessState.ExitCode() != 0 {
|
if cloneCmd.ProcessState != nil && cloneCmd.ProcessState.ExitCode() != 0 {
|
||||||
safeUrl, err := stripPassword(gitUrl)
|
safeUrl, err := stripPassword(gitUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Errorf("failed to strip credentials from git url")
|
ctx.Logger().V(1).Info("error stripping password from git url", "error", err)
|
||||||
}
|
}
|
||||||
log.WithField("exit_code", cloneCmd.ProcessState.ExitCode()).WithField("repo", safeUrl).WithField("output", string(output)).Errorf("failed to clone repo")
|
ctx.Logger().V(1).Info("git clone failed", "error", err, "repo", safeUrl, "output", string(output))
|
||||||
return "", nil, fmt.Errorf("could not clone repo: %s", safeUrl)
|
return "", nil, fmt.Errorf("could not clone repo: %s, %w", safeUrl, err)
|
||||||
}
|
}
|
||||||
repo, err = git.PlainOpen(clonePath)
|
|
||||||
|
repo, err := git.PlainOpen(clonePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.WrapPrefix(err, "could not open cloned repo", 0)
|
return "", nil, fmt.Errorf("could not open cloned repo: %w", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
log.WithField("clone_path", clonePath).WithField("repo", gitUrl).Debug("cloned repo")
|
|
||||||
return
|
ctx.Logger().V(1).Info("cloned repo", "repo", gitUrl, "clone-path", clonePath)
|
||||||
|
return clonePath, repo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneRepoUsingToken clones a repo using a provided token.
|
// CloneRepoUsingToken clones a repo using a provided token.
|
||||||
func CloneRepoUsingToken(token, gitUrl, user string, args ...string) (string, *git.Repository, error) {
|
func CloneRepoUsingToken(ctx context.Context, token, gitUrl, user string, args ...string) (string, *git.Repository, error) {
|
||||||
userInfo := url.UserPassword(user, token)
|
userInfo := url.UserPassword(user, token)
|
||||||
return CloneRepo(userInfo, gitUrl, args...)
|
return CloneRepo(ctx, userInfo, gitUrl, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneRepoUsingUnauthenticated clones a repo with no authentication required.
|
// CloneRepoUsingUnauthenticated clones a repo with no authentication required.
|
||||||
func CloneRepoUsingUnauthenticated(url string, args ...string) (string, *git.Repository, error) {
|
func CloneRepoUsingUnauthenticated(ctx context.Context, url string, args ...string) (string, *git.Repository, error) {
|
||||||
return CloneRepo(nil, url, args...)
|
return CloneRepo(ctx, nil, url, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneRepoUsingUnauthenticated clones a repo with no authentication required.
|
// CloneRepoUsingSSH clones a repo using SSH.
|
||||||
func CloneRepoUsingSSH(gitUrl string, args ...string) (string, *git.Repository, error) {
|
func CloneRepoUsingSSH(ctx context.Context, gitUrl string, args ...string) (string, *git.Repository, error) {
|
||||||
userInfo := url.User("git")
|
userInfo := url.User("git")
|
||||||
return CloneRepo(userInfo, gitUrl, args...)
|
return CloneRepo(ctx, userInfo, gitUrl, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GitCmdCheck() error {
|
// gitCmdCheck checks if git is installed.
|
||||||
|
func gitCmdCheck() error {
|
||||||
if errors.Is(exec.Command("git").Run(), exec.ErrNotFound) {
|
if errors.Is(exec.Command("git").Run(), exec.ErrNotFound) {
|
||||||
return fmt.Errorf("'git' command not found in $PATH. Make sure git is installed and included in $PATH")
|
return fmt.Errorf("'git' command not found in $PATH. Make sure git is installed and included in $PATH")
|
||||||
}
|
}
|
||||||
@@ -318,12 +319,9 @@ func GitCmdCheck() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string, scanOptions *ScanOptions, chunksChan chan *sources.Chunk) error {
|
func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string, scanOptions *ScanOptions, chunksChan chan *sources.Chunk) error {
|
||||||
if err := GitCmdCheck(); err != nil {
|
if err := gitCmdCheck(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if log.GetLevel() < log.DebugLevel {
|
|
||||||
zerolog.SetGlobalLevel(zerolog.Disabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
commitChan, err := gitparse.RepoPath(ctx, path, scanOptions.HeadHash)
|
commitChan, err := gitparse.RepoPath(ctx, path, scanOptions.HeadHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -338,11 +336,12 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string
|
|||||||
|
|
||||||
var depth int64
|
var depth int64
|
||||||
var reachedBase = false
|
var reachedBase = false
|
||||||
log.WithField("repo", urlMetadata).Debugf("Scanning repo")
|
|
||||||
|
ctx.Logger().V(1).Info("scanning repo", "repo", urlMetadata, "base", scanOptions.BaseHash, "head", scanOptions.HeadHash)
|
||||||
for commit := range commitChan {
|
for commit := range commitChan {
|
||||||
log.Tracef("Scanning commit %s", commit.Hash)
|
ctx.Logger().V(5).Info("scanning commit", "commit", commit.Hash, "message", commit.Message)
|
||||||
if scanOptions.MaxDepth > 0 && depth >= scanOptions.MaxDepth {
|
if scanOptions.MaxDepth > 0 && depth >= scanOptions.MaxDepth {
|
||||||
log.Debugf("reached max depth")
|
ctx.Logger().V(1).Info("reached max depth", "depth", depth)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
depth++
|
depth++
|
||||||
@@ -351,13 +350,11 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string
|
|||||||
}
|
}
|
||||||
if len(scanOptions.BaseHash) > 0 {
|
if len(scanOptions.BaseHash) > 0 {
|
||||||
if commit.Hash == scanOptions.BaseHash {
|
if commit.Hash == scanOptions.BaseHash {
|
||||||
log.Debugf("Reached base commit. Finishing scanning files.")
|
ctx.Logger().V(1).Info("reached base commit", "commit", commit.Hash)
|
||||||
reachedBase = true
|
reachedBase = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, diff := range commit.Diffs {
|
for _, diff := range commit.Diffs {
|
||||||
log.WithField("commit", commit.Hash).WithField("file", diff.PathB).Trace("Scanning file from git")
|
|
||||||
|
|
||||||
if !scanOptions.Filter.Pass(diff.PathB) {
|
if !scanOptions.Filter.Pass(diff.PathB) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -383,13 +380,13 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string
|
|||||||
Verify: s.verify,
|
Verify: s.verify,
|
||||||
}
|
}
|
||||||
if err := handleBinary(ctx, repo, chunksChan, chunkSkel, commitHash, fileName); err != nil {
|
if err := handleBinary(ctx, repo, chunksChan, chunkSkel, commitHash, fileName); err != nil {
|
||||||
log.WithError(err).WithField("file", fileName).Debug("Error handling binary file")
|
ctx.Logger().V(1).Info("error handling binary file", "error", err, "filename", fileName, "commit", commitHash, "file", diff.PathB)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff.Content.Len() > sources.ChunkSize+sources.PeekSize {
|
if diff.Content.Len() > sources.ChunkSize+sources.PeekSize {
|
||||||
s.gitChunk(diff, fileName, email, hash, when, urlMetadata, chunksChan)
|
s.gitChunk(ctx, diff, fileName, email, hash, when, urlMetadata, chunksChan)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
metadata := s.sourceMetadataFunc(fileName, email, hash, when, urlMetadata, int64(diff.LineStart))
|
metadata := s.sourceMetadataFunc(fileName, email, hash, when, urlMetadata, int64(diff.LineStart))
|
||||||
@@ -406,7 +403,7 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Git) gitChunk(diff gitparse.Diff, fileName, email, hash, when, urlMetadata string, chunksChan chan *sources.Chunk) {
|
func (s *Git) gitChunk(ctx context.Context, diff gitparse.Diff, fileName, email, hash, when, urlMetadata string, chunksChan chan *sources.Chunk) {
|
||||||
originalChunk := bufio.NewScanner(&diff.Content)
|
originalChunk := bufio.NewScanner(&diff.Content)
|
||||||
newChunkBuffer := bytes.Buffer{}
|
newChunkBuffer := bytes.Buffer{}
|
||||||
lastOffset := 0
|
lastOffset := 0
|
||||||
@@ -443,9 +440,8 @@ func (s *Git) gitChunk(diff gitparse.Diff, fileName, email, hash, when, urlMetad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := newChunkBuffer.Write(line)
|
if _, err := newChunkBuffer.Write(line); err != nil {
|
||||||
if err != nil {
|
ctx.Logger().Error(err, "error writing to chunk buffer", "filename", fileName, "commit", hash, "file", diff.PathB)
|
||||||
log.WithError(err).Error("Could not write line to git diff buffer.")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Send anything still in the new chunk buffer
|
// Send anything still in the new chunk buffer
|
||||||
@@ -477,12 +473,15 @@ func (s *Git) ScanUnstaged(ctx context.Context, repo *git.Repository, path strin
|
|||||||
|
|
||||||
var depth int64
|
var depth int64
|
||||||
var reachedBase = false
|
var reachedBase = false
|
||||||
log.Debugf("Scanning repo")
|
|
||||||
|
ctx.Logger().V(1).Info("scanning unstaged changes", "path", path)
|
||||||
for commit := range commitChan {
|
for commit := range commitChan {
|
||||||
for _, diff := range commit.Diffs {
|
for _, diff := range commit.Diffs {
|
||||||
log.WithField("commit", commit.Hash).WithField("file", diff.PathB).Trace("Scanning file from git")
|
logger := ctx.Logger().WithValues("filename", diff.PathB, "commit", commit.Hash, "file", diff.PathB)
|
||||||
|
logger.V(2).Info("scanning unstaged changes from git")
|
||||||
|
|
||||||
if scanOptions.MaxDepth > 0 && depth >= scanOptions.MaxDepth {
|
if scanOptions.MaxDepth > 0 && depth >= scanOptions.MaxDepth {
|
||||||
log.Debugf("reached max depth")
|
logger.V(1).Info("reached max depth")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
depth++
|
depth++
|
||||||
@@ -491,7 +490,7 @@ func (s *Git) ScanUnstaged(ctx context.Context, repo *git.Repository, path strin
|
|||||||
}
|
}
|
||||||
if len(scanOptions.BaseHash) > 0 {
|
if len(scanOptions.BaseHash) > 0 {
|
||||||
if commit.Hash == scanOptions.BaseHash {
|
if commit.Hash == scanOptions.BaseHash {
|
||||||
log.Debugf("Reached base commit. Finishing scanning files.")
|
logger.V(1).Info("reached base hash, finishing scanning files")
|
||||||
reachedBase = true
|
reachedBase = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,7 +520,7 @@ func (s *Git) ScanUnstaged(ctx context.Context, repo *git.Repository, path strin
|
|||||||
Verify: s.verify,
|
Verify: s.verify,
|
||||||
}
|
}
|
||||||
if err := handleBinary(ctx, repo, chunksChan, chunkSkel, commitHash, fileName); err != nil {
|
if err := handleBinary(ctx, repo, chunksChan, chunkSkel, commitHash, fileName); err != nil {
|
||||||
log.WithError(err).WithField("file", fileName).Debug("Error handling binary file")
|
logger.V(1).Info("error handling binary file", "error", err, "filename", fileName)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -549,10 +548,11 @@ func (s *Git) ScanRepo(ctx context.Context, repo *git.Repository, repoPath strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.ScanUnstaged(ctx, repo, repoPath, scanOptions, chunksChan); err != nil {
|
if err := s.ScanUnstaged(ctx, repo, repoPath, scanOptions, chunksChan); err != nil {
|
||||||
log.WithError(err).Error("Error scanning unstaged changes")
|
ctx.Logger().V(1).Info("error scanning unstaged changes", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
scanTime := time.Now().UnixNano() - start
|
scanTime := time.Now().UnixNano() - start
|
||||||
log.Debugf("Scanning complete. Scan time: %f", time.Duration(scanTime).Seconds())
|
ctx.Logger().V(1).Info("scanning git repo complete", "path", repoPath, "time", scanTime)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,9 +656,9 @@ func TryAdditionalBaseRefs(repo *git.Repository, base string) (*plumbing.Hash, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrepareRepoSinceCommit clones a repo starting at the given commitHash and returns the cloned repo path.
|
// PrepareRepoSinceCommit clones a repo starting at the given commitHash and returns the cloned repo path.
|
||||||
func PrepareRepoSinceCommit(uriString, commitHash string) (string, bool, error) {
|
func PrepareRepoSinceCommit(ctx context.Context, uriString, commitHash string) (string, bool, error) {
|
||||||
if commitHash == "" {
|
if commitHash == "" {
|
||||||
return PrepareRepo(uriString)
|
return PrepareRepo(ctx, uriString)
|
||||||
}
|
}
|
||||||
// TODO: refactor with PrepareRepo to remove duplicated logic
|
// TODO: refactor with PrepareRepo to remove duplicated logic
|
||||||
|
|
||||||
@@ -673,13 +673,13 @@ func PrepareRepoSinceCommit(uriString, commitHash string) (string, bool, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if uri.Scheme == "file" || uri.Host != "github.com" {
|
if uri.Scheme == "file" || uri.Host != "github.com" {
|
||||||
return PrepareRepo(uriString)
|
return PrepareRepo(ctx, uriString)
|
||||||
}
|
}
|
||||||
|
|
||||||
uriPath := strings.TrimPrefix(uri.Path, "/")
|
uriPath := strings.TrimPrefix(uri.Path, "/")
|
||||||
owner, repoName, found := strings.Cut(uriPath, "/")
|
owner, repoName, found := strings.Cut(uriPath, "/")
|
||||||
if !found {
|
if !found {
|
||||||
return PrepareRepo(uriString)
|
return PrepareRepo(ctx, uriString)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := github.NewClient(nil)
|
client := github.NewClient(nil)
|
||||||
@@ -693,13 +693,13 @@ func PrepareRepoSinceCommit(uriString, commitHash string) (string, bool, error)
|
|||||||
|
|
||||||
commit, _, err := client.Git.GetCommit(context.Background(), owner, repoName, commitHash)
|
commit, _, err := client.Git.GetCommit(context.Background(), owner, repoName, commitHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return PrepareRepo(uriString)
|
return PrepareRepo(ctx, uriString)
|
||||||
}
|
}
|
||||||
var timestamp string
|
var timestamp string
|
||||||
{
|
{
|
||||||
author := commit.GetAuthor()
|
author := commit.GetAuthor()
|
||||||
if author == nil {
|
if author == nil {
|
||||||
return PrepareRepo(uriString)
|
return PrepareRepo(ctx, uriString)
|
||||||
}
|
}
|
||||||
timestamp = author.GetDate().Format(time.RFC3339)
|
timestamp = author.GetDate().Format(time.RFC3339)
|
||||||
}
|
}
|
||||||
@@ -708,28 +708,29 @@ func PrepareRepoSinceCommit(uriString, commitHash string) (string, bool, error)
|
|||||||
var path string
|
var path string
|
||||||
switch {
|
switch {
|
||||||
case uri.User != nil:
|
case uri.User != nil:
|
||||||
log.Debugf("Cloning remote Git repo with authentication")
|
ctx.Logger().V(1).Info("cloning repo with authentication", "uri", uri)
|
||||||
password, ok := uri.User.Password()
|
password, ok := uri.User.Password()
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", true, fmt.Errorf("password must be included in Git repo URL when username is provided")
|
return "", true, fmt.Errorf("password must be included in Git repo URL when username is provided")
|
||||||
}
|
}
|
||||||
path, _, err = CloneRepoUsingToken(password, remotePath, uri.User.Username(), "--shallow-since", timestamp)
|
path, _, err = CloneRepoUsingToken(ctx, password, remotePath, uri.User.Username(), "--shallow-since", timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, true, fmt.Errorf("failed to clone authenticated Git repo (%s): %s", remotePath, err)
|
return path, true, fmt.Errorf("failed to clone authenticated Git repo (%s): %s", remotePath, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Debugf("Cloning remote Git repo without authentication")
|
ctx.Logger().V(1).Info("cloning repo without authentication", "uri", uri)
|
||||||
path, _, err = CloneRepoUsingUnauthenticated(remotePath, "--shallow-since", timestamp)
|
path, _, err = CloneRepoUsingUnauthenticated(ctx, remotePath, "--shallow-since", timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, true, fmt.Errorf("failed to clone unauthenticated Git repo (%s): %s", remotePath, err)
|
return path, true, fmt.Errorf("failed to clone unauthenticated Git repo (%s): %s", remotePath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debugf("Git repo local path: %s", path)
|
|
||||||
|
ctx.Logger().V(1).Info("cloned repo", "path", path)
|
||||||
return path, true, nil
|
return path, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareRepo clones a repo if possible and returns the cloned repo path.
|
// PrepareRepo clones a repo if possible and returns the cloned repo path.
|
||||||
func PrepareRepo(uriString string) (string, bool, error) {
|
func PrepareRepo(ctx context.Context, uriString string) (string, bool, error) {
|
||||||
var path string
|
var path string
|
||||||
uri, err := gitURLParse(uriString)
|
uri, err := gitURLParse(uriString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -745,18 +746,18 @@ func PrepareRepo(uriString string) (string, bool, error) {
|
|||||||
remote = true
|
remote = true
|
||||||
switch {
|
switch {
|
||||||
case uri.User != nil:
|
case uri.User != nil:
|
||||||
log.Debugf("Cloning remote Git repo with authentication")
|
ctx.Logger().V(1).Info("cloning repo with authentication", "uri", uri)
|
||||||
password, ok := uri.User.Password()
|
password, ok := uri.User.Password()
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", remote, fmt.Errorf("password must be included in Git repo URL when username is provided")
|
return "", remote, fmt.Errorf("password must be included in Git repo URL when username is provided")
|
||||||
}
|
}
|
||||||
path, _, err = CloneRepoUsingToken(password, remotePath, uri.User.Username())
|
path, _, err = CloneRepoUsingToken(ctx, password, remotePath, uri.User.Username())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, remote, fmt.Errorf("failed to clone authenticated Git repo (%s): %s", remotePath, err)
|
return path, remote, fmt.Errorf("failed to clone authenticated Git repo (%s): %s", remotePath, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Debugf("Cloning remote Git repo without authentication")
|
ctx.Logger().V(1).Info("cloning repo without authentication", "uri", uri)
|
||||||
path, _, err = CloneRepoUsingUnauthenticated(remotePath)
|
path, _, err = CloneRepoUsingUnauthenticated(ctx, remotePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, remote, fmt.Errorf("failed to clone unauthenticated Git repo (%s): %s", remotePath, err)
|
return path, remote, fmt.Errorf("failed to clone unauthenticated Git repo (%s): %s", remotePath, err)
|
||||||
}
|
}
|
||||||
@@ -764,14 +765,15 @@ func PrepareRepo(uriString string) (string, bool, error) {
|
|||||||
case "ssh":
|
case "ssh":
|
||||||
remotePath := uri.String()
|
remotePath := uri.String()
|
||||||
remote = true
|
remote = true
|
||||||
path, _, err = CloneRepoUsingSSH(remotePath)
|
path, _, err = CloneRepoUsingSSH(ctx, remotePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, remote, fmt.Errorf("failed to clone unauthenticated Git repo (%s): %s", remotePath, err)
|
return path, remote, fmt.Errorf("failed to clone unauthenticated Git repo (%s): %s", remotePath, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return "", remote, fmt.Errorf("unsupported Git URI: %s", uriString)
|
return "", remote, fmt.Errorf("unsupported Git URI: %s", uriString)
|
||||||
}
|
}
|
||||||
log.Debugf("Git repo local path: %s", path)
|
|
||||||
|
ctx.Logger().V(1).Info("cloned repo", "path", path)
|
||||||
return path, remote, nil
|
return path, remote, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,7 +801,7 @@ func getSafeRemoteURL(repo *git.Repository, preferred string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleBinary(ctx context.Context, repo *git.Repository, chunksChan chan *sources.Chunk, chunkSkel *sources.Chunk, commitHash plumbing.Hash, path string) error {
|
func handleBinary(ctx context.Context, repo *git.Repository, chunksChan chan *sources.Chunk, chunkSkel *sources.Chunk, commitHash plumbing.Hash, path string) error {
|
||||||
log.WithField("path", path).Trace("Binary file found in repository.")
|
ctx.Logger().V(5).Info("handling binary file", "path", path)
|
||||||
commit, err := repo.CommitObject(commitHash)
|
commit, err := repo.CommitObject(commitHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -825,7 +827,7 @@ func handleBinary(ctx context.Context, repo *git.Repository, chunksChan chan *so
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithField("path", path).Trace("Binary file is not recognized by file handlers. Chunking raw.")
|
ctx.Logger().V(1).Info("binary file not handled, chunking raw", "path", path)
|
||||||
if err := reader.Reset(); err != nil {
|
if err := reader.Reset(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ func TestSource_Chunks_Integration(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
init init
|
init init
|
||||||
//verified
|
// verified
|
||||||
repoURL string
|
repoURL string
|
||||||
expectedChunkData map[string]*byteCompare
|
expectedChunkData map[string]*byteCompare
|
||||||
scanOptions ScanOptions
|
scanOptions ScanOptions
|
||||||
@@ -285,7 +285,7 @@ func TestSource_Chunks_Integration(t *testing.T) {
|
|||||||
chunksCh := make(chan *sources.Chunk, 1)
|
chunksCh := make(chan *sources.Chunk, 1)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(chunksCh)
|
defer close(chunksCh)
|
||||||
repoPath, repo, err := CloneRepoUsingUnauthenticated(tt.repoURL)
|
repoPath, repo, err := CloneRepoUsingUnauthenticated(ctx, tt.repoURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -476,7 +476,8 @@ func TestPrepareRepo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
repo, b, err := PrepareRepo(tt.uri)
|
ctx := context.Background()
|
||||||
|
repo, b, err := PrepareRepo(ctx, tt.uri)
|
||||||
var repoLen bool
|
var repoLen bool
|
||||||
if len(repo) > 0 {
|
if len(repo) > 0 {
|
||||||
repoLen = true
|
repoLen = true
|
||||||
@@ -491,8 +492,9 @@ func TestPrepareRepo(t *testing.T) {
|
|||||||
|
|
||||||
func BenchmarkPrepareRepo(b *testing.B) {
|
func BenchmarkPrepareRepo(b *testing.B) {
|
||||||
uri := "https://github.com/dustin-decker/secretsandstuff.git"
|
uri := "https://github.com/dustin-decker/secretsandstuff.git"
|
||||||
|
ctx := context.Background()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, _, _ = PrepareRepo(uri)
|
_, _, _ = PrepareRepo(ctx, uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ func (s *Source) cloneRepo(ctx context.Context, repoURL string, installationClie
|
|||||||
|
|
||||||
switch s.conn.GetCredential().(type) {
|
switch s.conn.GetCredential().(type) {
|
||||||
case *sourcespb.GitHub_Unauthenticated:
|
case *sourcespb.GitHub_Unauthenticated:
|
||||||
path, repo, err = git.CloneRepoUsingUnauthenticated(repoURL)
|
path, repo, err = git.CloneRepoUsingUnauthenticated(ctx, repoURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, fmt.Errorf("error cloning repo %s: %w", repoURL, err)
|
return "", nil, fmt.Errorf("error cloning repo %s: %w", repoURL, err)
|
||||||
}
|
}
|
||||||
@@ -581,7 +581,7 @@ func (s *Source) cloneRepo(ctx context.Context, repoURL string, installationClie
|
|||||||
return "", nil, fmt.Errorf("error getting token for repo %s: %w", repoURL, err)
|
return "", nil, fmt.Errorf("error getting token for repo %s: %w", repoURL, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path, repo, err = git.CloneRepoUsingToken(s.githubToken, repoURL, s.githubUser)
|
path, repo, err = git.CloneRepoUsingToken(ctx, s.githubToken, repoURL, s.githubUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, fmt.Errorf("error cloning repo %s: %w", repoURL, err)
|
return "", nil, fmt.Errorf("error cloning repo %s: %w", repoURL, err)
|
||||||
}
|
}
|
||||||
@@ -594,7 +594,7 @@ func (s *Source) cloneRepo(ctx context.Context, repoURL string, installationClie
|
|||||||
return "", nil, fmt.Errorf("error getting token for repo %s: %w", repoURL, err)
|
return "", nil, fmt.Errorf("error getting token for repo %s: %w", repoURL, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path, repo, err = git.CloneRepoUsingToken(s.githubToken, repoURL, s.githubUser)
|
path, repo, err = git.CloneRepoUsingToken(ctx, s.githubToken, repoURL, s.githubUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, fmt.Errorf("error cloning repo %s: %w", repoURL, err)
|
return "", nil, fmt.Errorf("error cloning repo %s: %w", repoURL, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ func TestSource_Token(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// user provided
|
// user provided
|
||||||
_, _, err = git.CloneRepoUsingToken(token, "https://github.com/trufflesecurity/trufflehog-updater.git", user)
|
_, _, err = git.CloneRepoUsingToken(ctx, token, "https://github.com/trufflesecurity/trufflehog-updater.git", user)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// no user provided
|
// no user provided
|
||||||
_, _, err = git.CloneRepoUsingToken(token, "https://github.com/trufflesecurity/trufflehog-updater.git", "")
|
_, _, err = git.CloneRepoUsingToken(ctx, token, "https://github.com/trufflesecurity/trufflehog-updater.git", "")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
_, _, err = s.cloneRepo(ctx, "https://github.com/trufflesecurity/trufflehog-updater.git", installationClient)
|
_, _, err = s.cloneRepo(ctx, "https://github.com/trufflesecurity/trufflehog-updater.git", installationClient)
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ func (s *Source) scanRepos(ctx context.Context, chunksChan chan *sources.Chunk)
|
|||||||
var repo *gogit.Repository
|
var repo *gogit.Repository
|
||||||
var err error
|
var err error
|
||||||
if s.authMethod == "UNAUTHENTICATED" {
|
if s.authMethod == "UNAUTHENTICATED" {
|
||||||
path, repo, err = git.CloneRepoUsingUnauthenticated(repoURL)
|
path, repo, err = git.CloneRepoUsingUnauthenticated(ctx, repoURL)
|
||||||
} else {
|
} else {
|
||||||
// If a username is not provided we need to use a default one in order to clone a private repo.
|
// If a username is not provided we need to use a default one in order to clone a private repo.
|
||||||
// Not setting "placeholder" as s.user on purpose in case any downstream services rely on a "" value for s.user.
|
// Not setting "placeholder" as s.user on purpose in case any downstream services rely on a "" value for s.user.
|
||||||
@@ -315,7 +315,7 @@ func (s *Source) scanRepos(ctx context.Context, chunksChan chan *sources.Chunk)
|
|||||||
if user == "" {
|
if user == "" {
|
||||||
user = "placeholder"
|
user = "placeholder"
|
||||||
}
|
}
|
||||||
path, repo, err = git.CloneRepoUsingToken(s.token, repoURL, user)
|
path, repo, err = git.CloneRepoUsingToken(ctx, s.token, repoURL, user)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(path)
|
defer os.RemoveAll(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user