Prechádzať zdrojové kódy

Add scanning from a pipe with --pipe (#1012)

Zachary Rice 3 rokov pred
rodič
commit
6ef704f28f
6 zmenil súbory, kde vykonal 75 pridanie a 24 odobranie
  1. 5 0
      .gitleaksignore
  2. 20 20
      README.md
  3. 13 2
      cmd/detect.go
  4. 32 1
      detect/detect.go
  5. 1 1
      detect/detect_test.go
  6. 4 0
      detect/utils.go

+ 5 - 0
.gitleaksignore

@@ -745,3 +745,8 @@ testdata/repos/nogit/main.go:aws-access-token:20
 bfbc39eb185a217ead81a7174026f1c55f963660:cmd/generate/config/rules/jwt.go:jwt:17
 bfbc39eb185a217ead81a7174026f1c55f963660:cmd/generate/config/rules/jwt.go:jwt:19
 acce01f2338434a78f6a4a06a097b0fd23280484:README.md:aws-access-token:220
+99d620c719020fa24baa831299f0c964da79875e:detect/detect_test.go:aws-access-token:514
+111c8b47b65627db117bd20be85ff0aee8961eb9:detect/detect_test.go:private-key:567
+99d620c719020fa24baa831299f0c964da79875e:detect/detect_test.go:aws-access-token:512
+99d620c719020fa24baa831299f0c964da79875e:detect/detect_test.go:aws-access-token:513
+

+ 20 - 20
README.md

@@ -138,29 +138,29 @@ Usage:
 
 Available Commands:
   completion  generate the autocompletion script for the specified shell
-  detect      Detect secrets in code
+  detect      detect secrets in code
   help        Help about any command
-  protect     Protect secrets in code
-  version     Display gitleaks version
+  protect     protect secrets in code
+  version     display gitleaks version
 
 Flags:
-  -c, --config string          config file path
-                               order of precedence:
-                               1. --config/-c
-                               2. env var GITLEAKS_CONFIG
-                               3. (--source/-s)/.gitleaks.toml
-                               If none of the three options are used, then gitleaks will use the default config
-      --exit-code string       exit code when leaks have been encountered (default: 1)
-  -h, --help                   help for gitleaks
-  -l, --log-level string       log level (debug, info, warn, error, fatal) (default "info")
-      --no-banner              suppress banner
-      --redact                 redact secrets from logs and stdout
-  -f, --report-format string   output format (json, csv, sarif)
-  -r, --report-path string     report file
-  -b, --baseline-path          path to a previously generated report with known issues that gitleaks should ignore
-  -s, --source string          path to source (git repo, directory, file)
-  -v, --verbose                show verbose output from scan
-  --max-target-megabytes int   files larger than this will be skipped
+  -b, --baseline-path string       path to baseline with issues that can be ignored
+  -c, --config string              config file path
+                                   order of precedence:
+                                   1. --config/-c
+                                   2. env var GITLEAKS_CONFIG
+                                   3. (--source/-s)/.gitleaks.toml
+                                   If none of the three options are used, then gitleaks will use the default config
+      --exit-code int              exit code when leaks have been encountered (default 1)
+  -h, --help                       help for gitleaks
+  -l, --log-level string           log level (trace, debug, info, warn, error, fatal) (default "info")
+      --max-target-megabytes int   files larger than this will be skipped
+      --no-banner                  suppress banner
+      --redact                     redact secrets from logs and stdout
+  -f, --report-format string       output format (json, csv, sarif) (default "json")
+  -r, --report-path string         report file
+  -s, --source string              path to source (default: $PWD) (default ".")
+  -v, --verbose                    show verbose output from scan
 
 Use "gitleaks [command] --help" for more information about a command.
 ```

+ 13 - 2
cmd/detect.go

@@ -18,7 +18,8 @@ func init() {
 	rootCmd.AddCommand(detectCmd)
 	detectCmd.Flags().String("log-opts", "", "git log options")
 	detectCmd.Flags().Bool("no-git", false, "treat git repo as a regular directory and scan those files, --log-opts has no effect on the scan when --no-git is set")
-	detectCmd.Flags().Bool("follow-symlinks", false, "Scan files that are symlinks to other files")
+	detectCmd.Flags().Bool("pipe", false, "scan input from stdin, ex: `cat some_file | gitleaks detect --pipe`")
+	detectCmd.Flags().Bool("follow-symlinks", false, "scan files that are symlinks to other files")
 
 }
 
@@ -109,6 +110,10 @@ func runDetect(cmd *cobra.Command, args []string) {
 	if err != nil {
 		log.Fatal().Err(err).Msg("could not call GetBool() for no-git")
 	}
+	fromPipe, err := cmd.Flags().GetBool("pipe")
+	if err != nil {
+		log.Fatal().Err(err)
+	}
 
 	// start the detector scan
 	if noGit {
@@ -117,7 +122,13 @@ func runDetect(cmd *cobra.Command, args []string) {
 			// don't exit on error, just log it
 			log.Error().Err(err).Msg("")
 		}
-
+	} else if fromPipe {
+		findings, err = detector.DetectReader(os.Stdin, 10)
+		if err != nil {
+			// log fatal to exit, no need to continue since a report
+			// will not be generated when scanning from a pipe...for now
+			log.Fatal().Err(err).Msg("")
+		}
 	} else {
 		var logOpts string
 		logOpts, err = cmd.Flags().GetString("log-opts")

+ 32 - 1
detect/detect.go

@@ -4,6 +4,7 @@ import (
 	"bufio"
 	"context"
 	"fmt"
+	"io"
 	"io/fs"
 	"os"
 	"path/filepath"
@@ -11,13 +12,13 @@ import (
 	"strings"
 	"sync"
 
+	"github.com/h2non/filetype"
 	"github.com/zricethezav/gitleaks/v8/config"
 	"github.com/zricethezav/gitleaks/v8/detect/git"
 	"github.com/zricethezav/gitleaks/v8/report"
 
 	"github.com/fatih/semgroup"
 	"github.com/gitleaks/go-gitdiff/gitdiff"
-	"github.com/h2non/filetype"
 	ahocorasick "github.com/petar-dambovaliev/aho-corasick"
 	"github.com/rs/zerolog/log"
 	"github.com/spf13/viper"
@@ -479,6 +480,36 @@ func (d *Detector) DetectFiles(source string) ([]report.Finding, error) {
 	return d.findings, nil
 }
 
+// DetectReader accepts an io.Reader and a buffer size for the reader in KB
+func (d *Detector) DetectReader(r io.Reader, bufSize int) ([]report.Finding, error) {
+	reader := bufio.NewReader(r)
+	buf := make([]byte, 0, 1000*bufSize)
+	findings := []report.Finding{}
+
+	for {
+		n, err := reader.Read(buf[:cap(buf)])
+		buf = buf[:n]
+		if err != nil {
+			if err != io.EOF {
+				return findings, err
+			}
+			break
+		}
+
+		fragment := Fragment{
+			Raw: string(buf),
+		}
+		for _, finding := range d.Detect(fragment) {
+			findings = append(findings, finding)
+			if d.Verbose {
+				printFinding(finding)
+			}
+		}
+	}
+
+	return findings, nil
+}
+
 // Detect scans the given fragment and returns a list of findings
 func (d *Detector) Detect(fragment Fragment) []report.Finding {
 	var findings []report.Finding

+ 1 - 1
detect/detect_test.go

@@ -470,7 +470,7 @@ func TestFromGit(t *testing.T) {
 	}
 }
 
-// TestFromGit tests the FromGit function
+// TestFromFiles tests the FromFiles function
 func TestFromFiles(t *testing.T) {
 	tests := []struct {
 		cfgName          string

+ 4 - 0
detect/utils.go

@@ -131,6 +131,10 @@ func printFinding(f report.Finding) {
 	fmt.Printf("%-12s %s\n", "Secret:", secret)
 	fmt.Printf("%-12s %s\n", "RuleID:", f.RuleID)
 	fmt.Printf("%-12s %f\n", "Entropy:", f.Entropy)
+	if f.File == "" {
+		fmt.Println("")
+		return
+	}
 	fmt.Printf("%-12s %s\n", "File:", f.File)
 	fmt.Printf("%-12s %d\n", "Line:", f.StartLine)
 	if f.Commit == "" {