Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a02151add | |||
| c78d10149b | |||
| cb454bfc05 | |||
| fb9ae75661 | |||
| c06dd8a928 |
@@ -7,7 +7,7 @@ on:
|
||||
- v*
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -28,4 +28,4 @@ jobs:
|
||||
with:
|
||||
path: ./
|
||||
base: ${{ github.event.repository.default_branch }}
|
||||
head: HEAD
|
||||
head: HEAD
|
||||
|
||||
@@ -62,4 +62,4 @@ snifftest:
|
||||
./hack/snifftest/snifftest.sh
|
||||
|
||||
test-release:
|
||||
goreleaser release --rm-dist --skip-publish --snapshot
|
||||
goreleaser release --rm-dist --skip-publish --snapshot
|
||||
|
||||
@@ -17,6 +17,9 @@ inputs:
|
||||
default: ''
|
||||
description: Extra args to be passed to the trufflehog cli.
|
||||
required: false
|
||||
outputs:
|
||||
results:
|
||||
description: 'Trufflehog scan results'
|
||||
branding:
|
||||
icon: "shield"
|
||||
color: "green"
|
||||
@@ -32,4 +35,5 @@ runs:
|
||||
- ${{ inputs.head }}
|
||||
- --fail
|
||||
- --no-update
|
||||
- --github-actions
|
||||
- ${{ inputs.extra_args }}
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
# Parse the last argument into an array of extra_args.
|
||||
mapfile -t extra_args < <(bash -c "for arg in ${*: -1}; do echo \$arg; done")
|
||||
|
||||
/usr/bin/trufflehog "${@: 1: $#-1}" "${extra_args[@]}"
|
||||
results=$(/usr/bin/trufflehog "${@: 1: $#-1}" "${extra_args[@]}" | tee /dev/tty)
|
||||
echo "results=$results" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -10,7 +10,7 @@ replace github.com/gitleaks/go-gitdiff => github.com/trufflesecurity/go-gitdiff
|
||||
|
||||
require (
|
||||
cloud.google.com/go/secretmanager v1.10.0
|
||||
cloud.google.com/go/storage v1.30.0
|
||||
cloud.google.com/go/storage v1.30.1
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
|
||||
github.com/TheZeroSlave/zapsentry v1.14.0
|
||||
github.com/aws/aws-sdk-go v1.44.83
|
||||
@@ -149,7 +149,7 @@ require (
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
||||
@@ -10,8 +10,8 @@ cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB
|
||||
cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
|
||||
cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60=
|
||||
cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=
|
||||
cloud.google.com/go/storage v1.30.0 h1:g1yrbxAWOrvg/594228pETWkOi00MLTrOWfh56veU5o=
|
||||
cloud.google.com/go/storage v1.30.0/go.mod h1:xAVretHSROm1BQX4IIsoVgJqw0LqOyX+I/O2GzRAzdE=
|
||||
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
|
||||
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||
@@ -510,8 +510,8 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA=
|
||||
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
|
||||
@@ -34,18 +34,19 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
cli = kingpin.New("TruffleHog", "TruffleHog is a tool for finding credentials.")
|
||||
cmd string
|
||||
debug = cli.Flag("debug", "Run in debug mode.").Bool()
|
||||
trace = cli.Flag("trace", "Run in trace mode.").Bool()
|
||||
profile = cli.Flag("profile", "Enables profiling and sets a pprof and fgprof server on :18066.").Bool()
|
||||
jsonOut = cli.Flag("json", "Output in JSON format.").Short('j').Bool()
|
||||
jsonLegacy = cli.Flag("json-legacy", "Use the pre-v3.0 JSON format. Only works with git, gitlab, and github sources.").Bool()
|
||||
concurrency = cli.Flag("concurrency", "Number of concurrent workers.").Default(strconv.Itoa(runtime.NumCPU())).Int()
|
||||
noVerification = cli.Flag("no-verification", "Don't verify the results.").Bool()
|
||||
onlyVerified = cli.Flag("only-verified", "Only output verified results.").Bool()
|
||||
filterUnverified = cli.Flag("filter-unverified", "Only output first unverified result per chunk per detector if there are more than one results.").Bool()
|
||||
configFilename = cli.Flag("config", "Path to configuration file.").ExistingFile()
|
||||
cli = kingpin.New("TruffleHog", "TruffleHog is a tool for finding credentials.")
|
||||
cmd string
|
||||
debug = cli.Flag("debug", "Run in debug mode.").Bool()
|
||||
trace = cli.Flag("trace", "Run in trace mode.").Bool()
|
||||
profile = cli.Flag("profile", "Enables profiling and sets a pprof and fgprof server on :18066.").Bool()
|
||||
jsonOut = cli.Flag("json", "Output in JSON format.").Short('j').Bool()
|
||||
jsonLegacy = cli.Flag("json-legacy", "Use the pre-v3.0 JSON format. Only works with git, gitlab, and github sources.").Bool()
|
||||
gitHubActionsFormat = cli.Flag("github-actions", "Output in GitHub Actions format.").Bool()
|
||||
concurrency = cli.Flag("concurrency", "Number of concurrent workers.").Default(strconv.Itoa(runtime.NumCPU())).Int()
|
||||
noVerification = cli.Flag("no-verification", "Don't verify the results.").Bool()
|
||||
onlyVerified = cli.Flag("only-verified", "Only output verified results.").Bool()
|
||||
filterUnverified = cli.Flag("filter-unverified", "Only output first unverified result per chunk per detector if there are more than one results.").Bool()
|
||||
configFilename = cli.Flag("config", "Path to configuration file.").ExistingFile()
|
||||
// rules = cli.Flag("rules", "Path to file with custom rules.").String()
|
||||
printAvgDetectorTime = cli.Flag("print-avg-detector-time", "Print the average time spent on each detector.").Bool()
|
||||
noUpdate = cli.Flag("no-update", "Don't check for updates.").Bool()
|
||||
@@ -60,6 +61,7 @@ var (
|
||||
gitScanURI = gitScan.Arg("uri", "Git repository URL. https://, file://, or ssh:// schema expected.").Required().String()
|
||||
gitScanIncludePaths = gitScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
||||
gitScanExcludePaths = gitScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
||||
gitScanExcludeGlobs = gitScan.Flag("exclude-globs", "Comma separated list of globs to exclude in scan. This option filters at the `git log` level, resulting in faster scans.").String()
|
||||
gitScanSinceCommit = gitScan.Flag("since-commit", "Commit to start scan from.").String()
|
||||
gitScanBranch = gitScan.Flag("branch", "Branch to scan.").String()
|
||||
gitScanMaxDepth = gitScan.Flag("max-depth", "Maximum depth of commits to scan.").Int()
|
||||
@@ -301,13 +303,18 @@ func run(state overseer.State) {
|
||||
if remote {
|
||||
defer os.RemoveAll(repoPath)
|
||||
}
|
||||
excludedGlobs := []string{}
|
||||
if *gitScanExcludeGlobs != "" {
|
||||
excludedGlobs = strings.Split(*gitScanExcludeGlobs, ",")
|
||||
}
|
||||
|
||||
cfg := sources.GitConfig{
|
||||
RepoPath: repoPath,
|
||||
HeadRef: *gitScanBranch,
|
||||
BaseRef: *gitScanSinceCommit,
|
||||
MaxDepth: *gitScanMaxDepth,
|
||||
Filter: filter,
|
||||
RepoPath: repoPath,
|
||||
HeadRef: *gitScanBranch,
|
||||
BaseRef: *gitScanSinceCommit,
|
||||
MaxDepth: *gitScanMaxDepth,
|
||||
Filter: filter,
|
||||
ExcludeGlobs: excludedGlobs,
|
||||
}
|
||||
if err = e.ScanGit(ctx, cfg); err != nil {
|
||||
logFatal(err, "Failed to scan Git.")
|
||||
@@ -435,6 +442,8 @@ func run(state overseer.State) {
|
||||
err = output.PrintLegacyJSON(ctx, &r)
|
||||
case *jsonOut:
|
||||
err = output.PrintJSON(&r)
|
||||
case *gitHubActionsFormat:
|
||||
err = output.PrintGitHubActionsOutput(&r)
|
||||
default:
|
||||
err = output.PrintPlainOutput(&r)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ func (e *Engine) ScanGit(ctx context.Context, c sources.GitConfig) error {
|
||||
if c.HeadRef != "" {
|
||||
opts = append(opts, git.ScanOptionHeadCommit(c.HeadRef))
|
||||
}
|
||||
if c.ExcludeGlobs != nil {
|
||||
opts = append(opts, git.ScanOptionExcludeGlobs(c.ExcludeGlobs))
|
||||
}
|
||||
scanOptions := git.NewScanOptions(opts...)
|
||||
|
||||
gitSource := git.NewGit(sourcespb.SourceType_SOURCE_TYPE_GIT, 0, 0, "trufflehog - git", true, runtime.NumCPU(),
|
||||
|
||||
@@ -116,7 +116,7 @@ func (c1 *Commit) Equal(c2 *Commit) bool {
|
||||
}
|
||||
|
||||
// RepoPath parses the output of the `git log` command for the `source` path.
|
||||
func (c *Parser) RepoPath(ctx context.Context, source string, head string, abbreviatedLog bool) (chan Commit, error) {
|
||||
func (c *Parser) RepoPath(ctx context.Context, source string, head string, abbreviatedLog bool, excludedGlobs []string) (chan Commit, error) {
|
||||
args := []string{"-C", source, "log", "-p", "-U5", "--full-history", "--date=format:%a %b %d %H:%M:%S %Y %z"}
|
||||
if abbreviatedLog {
|
||||
args = append(args, "--diff-filter=AM")
|
||||
@@ -126,9 +126,11 @@ func (c *Parser) RepoPath(ctx context.Context, source string, head string, abbre
|
||||
} else {
|
||||
args = append(args, "--all")
|
||||
}
|
||||
for _, glob := range excludedGlobs {
|
||||
args = append(args, "--", ".", fmt.Sprintf(":(exclude)%s", glob))
|
||||
}
|
||||
|
||||
cmd := exec.Command("git", args...)
|
||||
|
||||
absPath, err := filepath.Abs(source)
|
||||
if err == nil {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_DIR=%s", filepath.Join(absPath, ".git")))
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
)
|
||||
|
||||
var dedupeCache = make(map[string]struct{})
|
||||
|
||||
func PrintGitHubActionsOutput(r *detectors.ResultWithMetadata) error {
|
||||
out := gitHubActionsOutputFormat{
|
||||
DetectorType: r.Result.DetectorType.String(),
|
||||
DecoderType: r.Result.DecoderType.String(),
|
||||
Verified: r.Result.Verified,
|
||||
}
|
||||
|
||||
meta, err := structToMap(r.SourceMetadata.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not marshal result: %w", err)
|
||||
}
|
||||
|
||||
for _, data := range meta {
|
||||
for k, v := range data {
|
||||
if k == "line" {
|
||||
if line, ok := v.(float64); ok {
|
||||
out.StartLine = int64(line)
|
||||
}
|
||||
}
|
||||
if k == "file" {
|
||||
if filename, ok := v.(string); ok {
|
||||
out.Filename = filename
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
verifiedStatus := "unverified"
|
||||
if out.Verified {
|
||||
verifiedStatus = "verified"
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%s:%s:%s:%s:%d", out.DecoderType, out.DetectorType, verifiedStatus, out.Filename, out.StartLine)
|
||||
h := sha256.New()
|
||||
h.Write([]byte(key))
|
||||
key = hex.EncodeToString(h.Sum(nil))
|
||||
if _, ok := dedupeCache[key]; ok {
|
||||
return nil
|
||||
}
|
||||
dedupeCache[key] = struct{}{}
|
||||
|
||||
message := fmt.Sprintf("Found %s %s result 🐷🔑\n", verifiedStatus, out.DetectorType)
|
||||
if r.Result.DecoderType != detectorspb.DecoderType_PLAIN {
|
||||
message = fmt.Sprintf("Found %s %s result with %s encoding 🐷🔑\n", verifiedStatus, out.DetectorType, out.DecoderType)
|
||||
}
|
||||
|
||||
fmt.Printf("::warning file=%s,line=%d,endLine=%d::%s",
|
||||
out.Filename, out.StartLine, out.StartLine, message)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type gitHubActionsOutputFormat struct {
|
||||
DetectorType,
|
||||
DecoderType string
|
||||
Verified bool
|
||||
StartLine int64
|
||||
Filename string
|
||||
}
|
||||
@@ -338,7 +338,7 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string
|
||||
return err
|
||||
}
|
||||
|
||||
commitChan, err := gitparse.NewParser().RepoPath(ctx, path, scanOptions.HeadHash, scanOptions.BaseHash == "")
|
||||
commitChan, err := gitparse.NewParser().RepoPath(ctx, path, scanOptions.HeadHash, scanOptions.BaseHash == "", scanOptions.ExcludeGlobs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ import (
|
||||
)
|
||||
|
||||
type ScanOptions struct {
|
||||
Filter *common.Filter
|
||||
BaseHash string // When scanning a git.Log, this is the oldest/first commit.
|
||||
HeadHash string
|
||||
MaxDepth int64
|
||||
LogOptions *git.LogOptions
|
||||
Filter *common.Filter
|
||||
BaseHash string // When scanning a git.Log, this is the oldest/first commit.
|
||||
HeadHash string
|
||||
MaxDepth int64
|
||||
ExcludeGlobs []string
|
||||
LogOptions *git.LogOptions
|
||||
}
|
||||
|
||||
type ScanOption func(*ScanOptions)
|
||||
@@ -39,6 +40,12 @@ func ScanOptionMaxDepth(maxDepth int64) ScanOption {
|
||||
}
|
||||
}
|
||||
|
||||
func ScanOptionExcludeGlobs(globs []string) ScanOption {
|
||||
return func(scanOptions *ScanOptions) {
|
||||
scanOptions.ExcludeGlobs = globs
|
||||
}
|
||||
}
|
||||
|
||||
func ScanOptionLogOptions(logOptions *git.LogOptions) ScanOption {
|
||||
return func(scanOptions *ScanOptions) {
|
||||
scanOptions.LogOptions = logOptions
|
||||
|
||||
@@ -83,6 +83,9 @@ type GitConfig struct {
|
||||
MaxDepth int
|
||||
// Filter is the filter to use to scan the source.
|
||||
Filter *common.Filter
|
||||
// ExcludeGlobs is a list of globs to exclude from the scan.
|
||||
// This differs from the Filter exclusions as ExcludeGlobs is applied at the `git log -p` level
|
||||
ExcludeGlobs []string
|
||||
}
|
||||
|
||||
// GithubConfig defines the optional configuration for a github source.
|
||||
|
||||
Reference in New Issue
Block a user