diff --git a/.github/workflows/secrets.yml b/.github/workflows/secrets.yml index 383d995a6..59c51c4d8 100644 --- a/.github/workflows/secrets.yml +++ b/.github/workflows/secrets.yml @@ -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 \ No newline at end of file + head: HEAD diff --git a/Makefile b/Makefile index 3fa648e55..d4cb6e5b6 100644 --- a/Makefile +++ b/Makefile @@ -62,4 +62,4 @@ snifftest: ./hack/snifftest/snifftest.sh test-release: - goreleaser release --rm-dist --skip-publish --snapshot \ No newline at end of file + goreleaser release --rm-dist --skip-publish --snapshot diff --git a/action.yml b/action.yml index 6aed83129..770c9b302 100644 --- a/action.yml +++ b/action.yml @@ -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" diff --git a/entrypoint.sh b/entrypoint.sh index 7db98e4b4..6b03b2c09 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -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[@]}" \ No newline at end of file +results=$(/usr/bin/trufflehog "${@: 1: $#-1}" "${extra_args[@]}") +echo "results=$results" >> $GITHUB_OUTPUT diff --git a/main.go b/main.go index a21e28a26..2fc0fbef7 100644 --- a/main.go +++ b/main.go @@ -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() @@ -441,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) } diff --git a/pkg/output/github_actions.go b/pkg/output/github_actions.go new file mode 100644 index 000000000..11d0e19b8 --- /dev/null +++ b/pkg/output/github_actions.go @@ -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 +}