Просмотр исходного кода

Add support for reportGroup (#456)

Why:

* There are times where it would be nice to have a group from the regex
  reported rather than the complete match.

This change addresses the need by:

* Add the reportGroup configuration option for a rule.
* Update scan.CheckRules to return the reportGroup if set.

Co-authored-by: Daniel Paul Searles <dsearles@gitlab.com>
Daniel Paul Searles 5 лет назад
Родитель
Сommit
2acc34dfdf

+ 3 - 0
config/config.go

@@ -40,6 +40,7 @@ type Rule struct {
 	Regex       *regexp.Regexp
 	File        *regexp.Regexp
 	Path        *regexp.Regexp
+	ReportGroup int
 	Tags        []string
 	AllowList   AllowList
 	Entropies   []Entropy
@@ -73,6 +74,7 @@ type TomlLoader struct {
 		Regex       string
 		File        string
 		Path        string
+		ReportGroup int
 		Tags        []string
 		Entropies   []struct {
 			Min   string
@@ -198,6 +200,7 @@ func (tomlLoader TomlLoader) Parse() (Config, error) {
 			Regex:       re,
 			File:        fileNameRe,
 			Path:        filePathRe,
+			ReportGroup: rule.ReportGroup,
 			Tags:        rule.Tags,
 			AllowList:   allowList,
 			Entropies:   entropies,

+ 82 - 0
config/config_test.go

@@ -2,6 +2,8 @@ package config
 
 import (
 	"fmt"
+	"io/ioutil"
+	"os"
 	"regexp"
 	"testing"
 
@@ -129,3 +131,83 @@ func TestParse(t *testing.T) {
 		}
 	}
 }
+
+// TestParseFields will test that fields are properly parsed from a config. As fields are added, then please
+// add tests here.
+func TestParseFields(t *testing.T) {
+	tomlConfig := `
+[[rules]]
+	description = "Some Groups without a reportGroup"
+	regex = '(.)(.)'
+
+[[rules]]
+	description = "Some Groups"
+	regex = '(.)(.)'
+  reportGroup = 1
+`
+	configPath, err := writeTestConfig(tomlConfig)
+	defer os.Remove(configPath)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config, err := NewConfig(options.Options{Config: configPath})
+	if err != nil {
+		t.Fatalf("Couldn't parse config: %v", err)
+	}
+
+	expectedRuleFields := []struct {
+		Description string
+		ReportGroup int
+	}{
+		{
+			Description: "Some Groups without a reportGroup",
+			ReportGroup: 0,
+		},
+		{
+			Description: "Some Groups",
+			ReportGroup: 1,
+		},
+	}
+
+	if len(config.Rules) != len(expectedRuleFields) {
+		t.Fatalf("expected %v rules", len(expectedRuleFields))
+	}
+
+	for _, expected := range expectedRuleFields {
+		rule, err := findRuleByDescription(config.Rules, expected.Description)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if rule.ReportGroup != expected.ReportGroup {
+			t.Errorf("expected the rule with description '%v' to have a ReportGroup of %v", expected.Description, expected.ReportGroup)
+		}
+	}
+}
+
+func findRuleByDescription(rules []Rule, description string) (*Rule, error) {
+	for _, rule := range rules {
+		if rule.Description == description {
+			return &rule, nil
+		}
+	}
+
+	return nil, fmt.Errorf("Couldn't find rule with the description: %s", description)
+}
+
+func writeTestConfig(toml string) (string, error) {
+	tmpfile, err := ioutil.TempFile("", "testConfig")
+	if err != nil {
+		return "", fmt.Errorf("Couldn't create test config got: %w", err)
+	}
+
+	if _, err := tmpfile.Write([]byte(toml)); err != nil {
+		return "", fmt.Errorf("Couldn't create test config got: %w", err)
+	}
+
+	if err := tmpfile.Close(); err != nil {
+		return "", fmt.Errorf("Couldn't create test config got: %w", err)
+	}
+
+	return tmpfile.Name(), nil
+}

+ 5 - 0
scan/rule.go

@@ -121,6 +121,11 @@ func (repo *Repo) CheckRules(bundle *Bundle) {
 						continue
 					}
 
+					// 0 is a match for the full regex pattern
+					if 0 < rule.ReportGroup && rule.ReportGroup < len(groups) {
+						offender = groups[rule.ReportGroup]
+					}
+
 					leak := manager.Leak{
 						LineNumber: defaultLineNumber,
 						Line:       line,

+ 11 - 0
scan/scan_test.go

@@ -144,6 +144,17 @@ func TestScan(t *testing.T) {
 			},
 			wantEmpty: true,
 		},
+		{
+			description: "test local repo three leaks dev branch with reportGroup set",
+			opts: options.Options{
+				RepoPath:     "../test_data/test_repos/test_repo_3",
+				Report:       "../test_data/test_local_repo_three_leaks_with_report_groups.json.got",
+				Config:       "../test_data/test_configs/aws_key_with_report_groups.toml",
+				Branch:       "dev",
+				ReportFormat: "json",
+			},
+			wantPath: "../test_data/test_local_repo_three_leaks_with_report_groups.json",
+		},
 		{
 			description: "test local repo three leaks dev branch",
 			opts: options.Options{

+ 10 - 0
test_data/test_configs/aws_key_with_report_groups.toml

@@ -0,0 +1,10 @@
+[[rules]]
+	description = "AWS Secret Key"
+	regex = '''(?i)aws(.{0,20})?(?-i)['\"][0-9a-zA-Z\/+]{40}['\"]'''
+	tags = ["key", "AWS"]
+
+[[rules]]
+    description = "AWS Manager ID"
+    regex = '''AWS secret: ("?)((A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16})("?)'''
+    tags = ["key", "AWS"]
+    reportGroup = 2

+ 47 - 0
test_data/test_local_repo_three_leaks_with_report_groups.json

@@ -0,0 +1,47 @@
+[
+ {
+  "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
+  "lineNumber": 6,
+  "offender": "AKIALALEMEL33243OLIA",
+  "commit": "deea550dd6c7acaf0e59432600593533984a2125",
+  "repo": "test_repo_3",
+  "rule": "AWS Manager ID",
+  "commitMessage": "dev branch\n",
+  "author": "zach rice",
+  "email": "zricer@protonmail.com",
+  "file": "secrets.md",
+  "date": "2019-10-25T13:35:03-04:00",
+  "tags": "key, AWS",
+  "operation": "addition"
+ },
+ {
+  "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
+  "lineNumber": 5,
+  "offender": "AKIALALEMEL33243OLIA",
+  "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
+  "repo": "test_repo_3",
+  "rule": "AWS Manager ID",
+  "commitMessage": "wait this is actually adding an aws secret\n",
+  "author": "zach rice",
+  "email": "zricer@protonmail.com",
+  "file": "secrets.md",
+  "date": "2019-10-25T13:01:27-04:00",
+  "tags": "key, AWS",
+  "operation": "addition"
+ },
+ {
+  "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
+  "lineNumber": 3,
+  "offender": "AKIALALEMEL33243OLIA",
+  "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
+  "repo": "test_repo_3",
+  "rule": "AWS Manager ID",
+  "commitMessage": "adding aws key\n",
+  "author": "zach rice",
+  "email": "zricer@protonmail.com",
+  "file": "secrets.md",
+  "date": "2019-10-25T12:58:39-04:00",
+  "tags": "key, AWS",
+  "operation": "addition"
+ }
+]