Parcourir la source

Fix rule extension (#1556)

* Reimplement the ability to override built-in rules

PR #1524 broke the ability to specify a `[[rules]]` with the same ID as
a built-in rule in order to extend the default configuration.

This PR restores this ability, but merges the provided configuration
with the default rule instead of overwriting the default rule wholesale.

* Add tests

* Append keywords and tags
Rebecca Turner il y a 1 an
Parent
commit
be9d0f8930

+ 17 - 0
config/config.go

@@ -252,6 +252,23 @@ func (c *Config) extend(extensionConfig Config) {
 			c.OrderedRules = append(c.OrderedRules, ruleID)
 			c.OrderedRules = append(c.OrderedRules, ruleID)
 		} else {
 		} else {
 			// Rule exists, merge our changes into the base.
 			// Rule exists, merge our changes into the base.
+			if currentRule.Description != "" {
+				baseRule.Description = currentRule.Description
+			}
+			if currentRule.Entropy != 0 {
+				baseRule.Entropy = currentRule.Entropy
+			}
+			if currentRule.SecretGroup != 0 {
+				baseRule.SecretGroup = currentRule.SecretGroup
+			}
+			if currentRule.Regex != nil {
+				baseRule.Regex = currentRule.Regex
+			}
+			if currentRule.Path != nil {
+				baseRule.Path = currentRule.Path
+			}
+			baseRule.Tags = append(baseRule.Tags, currentRule.Tags...)
+			baseRule.Keywords = append(baseRule.Keywords, currentRule.Keywords...)
 			baseRule.Allowlist.Commits = append(baseRule.Allowlist.Commits, currentRule.Allowlist.Commits...)
 			baseRule.Allowlist.Commits = append(baseRule.Allowlist.Commits, currentRule.Allowlist.Commits...)
 			baseRule.Allowlist.Paths = append(baseRule.Allowlist.Paths, currentRule.Allowlist.Paths...)
 			baseRule.Allowlist.Paths = append(baseRule.Allowlist.Paths, currentRule.Allowlist.Paths...)
 			baseRule.Allowlist.Regexes = append(baseRule.Allowlist.Regexes, currentRule.Allowlist.Regexes...)
 			baseRule.Allowlist.Regexes = append(baseRule.Allowlist.Regexes, currentRule.Allowlist.Regexes...)

+ 116 - 2
config/config_test.go

@@ -15,8 +15,13 @@ const configPath = "../testdata/config/"
 
 
 func TestTranslate(t *testing.T) {
 func TestTranslate(t *testing.T) {
 	tests := []struct {
 	tests := []struct {
-		cfgName   string
-		cfg       Config
+		// Configuration file basename to load, from `../testdata/config/`.
+		cfgName string
+		// Expected result.
+		cfg Config
+		// Rules to compare.
+		rules []string
+		// Error to expect.
 		wantError error
 		wantError error
 	}{
 	}{
 		{
 		{
@@ -174,6 +179,107 @@ func TestTranslate(t *testing.T) {
 				},
 				},
 			},
 			},
 		},
 		},
+		{
+			cfgName: "override_description",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "Puppy Doggy",
+					Regex:       regexp.MustCompile("(?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}"),
+					Keywords:    []string{},
+					Tags:        []string{"key", "AWS"},
+				},
+				},
+			},
+		},
+		{
+			cfgName: "override_entropy",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "AWS Access Key",
+					Entropy:     999.0,
+					Regex:       regexp.MustCompile("(?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}"),
+					Keywords:    []string{},
+					Tags:        []string{"key", "AWS"},
+				},
+				},
+			},
+		},
+		{
+			cfgName: "override_secret_group",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "AWS Access Key",
+					Regex:       regexp.MustCompile("(?:a)(?:a)"),
+					SecretGroup: 2,
+					Keywords:    []string{},
+					Tags:        []string{"key", "AWS"},
+				},
+				},
+			},
+		},
+		{
+			cfgName: "override_regex",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "AWS Access Key",
+					Regex:       regexp.MustCompile("(?:a)"),
+					Keywords:    []string{},
+					Tags:        []string{"key", "AWS"},
+				},
+				},
+			},
+		},
+		{
+			cfgName: "override_path",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "AWS Access Key",
+					Regex:       regexp.MustCompile("(?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}"),
+					Path:        regexp.MustCompile("(?:puppy)"),
+					Keywords:    []string{},
+					Tags:        []string{"key", "AWS"},
+				},
+				},
+			},
+		},
+		{
+			cfgName: "override_tags",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "AWS Access Key",
+					Regex:       regexp.MustCompile("(?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}"),
+					Keywords:    []string{},
+					Tags:        []string{"key", "AWS", "puppy"},
+				},
+				},
+			},
+		},
+		{
+			cfgName: "override_keywords",
+			rules:   []string{"aws-access-key"},
+			cfg: Config{
+				Rules: map[string]Rule{"aws-access-key": {
+					RuleID:      "aws-access-key",
+					Description: "AWS Access Key",
+					Regex:       regexp.MustCompile("(?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}"),
+					Keywords:    []string{"puppy"},
+					Tags:        []string{"key", "AWS"},
+				},
+				},
+			},
+		},
 	}
 	}
 
 
 	for _, tt := range tests {
 	for _, tt := range tests {
@@ -197,6 +303,14 @@ func TestTranslate(t *testing.T) {
 				return
 				return
 			}
 			}
 
 
+			if len(tt.rules) > 0 {
+				rules := make(map[string]Rule)
+				for _, name := range tt.rules {
+					rules[name] = cfg.Rules[name]
+				}
+				cfg.Rules = rules
+			}
+
 			var regexComparer = func(x, y *regexp.Regexp) bool {
 			var regexComparer = func(x, y *regexp.Regexp) bool {
 				// Compare the string representation of the regex patterns.
 				// Compare the string representation of the regex patterns.
 				if x == nil || y == nil {
 				if x == nil || y == nil {

+ 8 - 0
testdata/config/override_description.toml

@@ -0,0 +1,8 @@
+title = "override a built-in rule's description"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+description = "Puppy Doggy"

+ 8 - 0
testdata/config/override_entropy.toml

@@ -0,0 +1,8 @@
+title = "override a built-in rule's entropy"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+entropy = 999

+ 8 - 0
testdata/config/override_keywords.toml

@@ -0,0 +1,8 @@
+title = "override a built-in rule's keywords"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+keywords = ["puppy"]

+ 8 - 0
testdata/config/override_path.toml

@@ -0,0 +1,8 @@
+title = "override a built-in rule's path"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+path = '''(?:puppy)'''

+ 8 - 0
testdata/config/override_regex.toml

@@ -0,0 +1,8 @@
+title = "override a built-in rule's regex"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+regex = '''(?:a)'''

+ 9 - 0
testdata/config/override_secret_group.toml

@@ -0,0 +1,9 @@
+title = "override a built-in rule's secretGroup"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+regex = '''(?:a)(?:a)'''
+secretGroup = 2

+ 8 - 0
testdata/config/override_tags.toml

@@ -0,0 +1,8 @@
+title = "override a built-in rule's tags"
+
+[extend]
+path = "../testdata/config/simple.toml"
+
+[[rules]]
+id = "aws-access-key"
+tags = ["puppy"]