Bladeren bron

refactor(config): use non-capture groups for allowlists (#1735)

Non-capture groups appear to be measurably faster.
Richard Gomez 1 jaar geleden
bovenliggende
commit
7fc11bb264

+ 26 - 26
cmd/generate/config/base/config.go

@@ -33,9 +33,9 @@ func CreateGlobalConfig() config.Config {
 				}(),
 
 				// ----------- Environment Variables -----------
-				regexp.MustCompile(`^\$(\d+|{\d+})$`),
-				regexp.MustCompile(`^\$([A-Z_]+|[a-z_]+)$`),
-				regexp.MustCompile(`^\${([A-Z_]+|[a-z_]+)}$`),
+				regexp.MustCompile(`^\$(?:\d+|{\d+})$`),
+				regexp.MustCompile(`^\$(?:[A-Z_]+|[a-z_]+)$`),
+				regexp.MustCompile(`^\${(?:[A-Z_]+|[a-z_]+)}$`),
 
 				// ----------- Interpolated Variables -----------
 				// Ansible (https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html)
@@ -43,14 +43,14 @@ func CreateGlobalConfig() config.Config {
 				// GitHub Actions
 				// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables
 				// https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions
-				regexp.MustCompile(`^\$\{\{[ \t]*((env|github|secrets|vars)(\.[A-Za-z]\w+)+[\w "'&./=|]*)[ \t]*}}$`),
+				regexp.MustCompile(`^\$\{\{[ \t]*(?:(?:env|github|secrets|vars)(?:\.[A-Za-z]\w+)+[\w "'&./=|]*)[ \t]*}}$`),
 				// NuGet (https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#using-environment-variables)
-				regexp.MustCompile(`^%([A-Z_]+|[a-z_]+)%$`),
+				regexp.MustCompile(`^%(?:[A-Z_]+|[a-z_]+)%$`),
 				// String formatting.
 				regexp.MustCompile(`^%[+\-# 0]?[bcdeEfFgGoOpqstTUvxX]$`), // Golang (https://pkg.go.dev/fmt)
 				regexp.MustCompile(`^\{\d{0,2}}$`),                       // Python (https://docs.python.org/3/tutorial/inputoutput.html)
 				// Urban Code Deploy (https://www.ibm.com/support/pages/replace-token-step-replaces-replacement-values-windows-variables)
-				regexp.MustCompile(`^@([A-Z_]+|[a-z_]+)@$`),
+				regexp.MustCompile(`^@(?:[A-Z_]+|[a-z_]+)@$`),
 
 				// ----------- Miscellaneous -----------
 			},
@@ -58,42 +58,42 @@ func CreateGlobalConfig() config.Config {
 				regexp.MustCompile(`gitleaks\.toml`),
 
 				// ----------- Documents and media -----------
-				regexp.MustCompile(`(?i)\.(bmp|gif|jpe?g|svg|tiff?)$`), // Images
-				regexp.MustCompile(`\.(eot|[ot]tf|woff2?)$`),           // Fonts
-				regexp.MustCompile(`(.*?)(doc|docx|zip|xls|pdf|bin|socket|vsidx|v2|suo|wsuo|.dll|pdb|exe|gltf)$`),
+				regexp.MustCompile(`(?i)\.(?:bmp|gif|jpe?g|png|svg|tiff?)$`), // Images
+				regexp.MustCompile(`(?i)\.(?:eot|[ot]tf|woff2?)$`),           // Fonts
+				regexp.MustCompile(`(?i)\.(?:docx?|xlsx?|pdf|bin|socket|vsidx|v2|suo|wsuo|.dll|pdb|exe|gltf|zip)$`),
 
 				// ----------- Golang files -----------
-				regexp.MustCompile(`go\.(mod|sum|work(\.sum)?)$`),
-				regexp.MustCompile(`(^|/)vendor/modules\.txt$`),
-				regexp.MustCompile(`(^|/)vendor/(github\.com|golang\.org/x|google\.golang\.org|gopkg\.in|istio\.io|k8s\.io|sigs\.k8s\.io)(/.*)?$`),
+				regexp.MustCompile(`go\.(?:mod|sum|work(?:\.sum)?)$`),
+				regexp.MustCompile(`(?:^|/)vendor/modules\.txt$`),
+				regexp.MustCompile(`(?:^|/)vendor/(?:github\.com|golang\.org/x|google\.golang\.org|gopkg\.in|istio\.io|k8s\.io|sigs\.k8s\.io)(?:/.*)?$`),
 
 				// ----------- Java files -----------
 				// Gradle
-				regexp.MustCompile(`(^|/)gradlew(\.bat)?$`),
-				regexp.MustCompile(`(^|/)gradle\.lockfile$`),
-				regexp.MustCompile(`(^|/)mvnw(\.cmd)?$`),
-				regexp.MustCompile(`(^|/)\.mvn/wrapper/MavenWrapperDownloader\.java$`),
+				regexp.MustCompile(`(?:^|/)gradlew(?:\.bat)?$`),
+				regexp.MustCompile(`(?:^|/)gradle\.lockfile$`),
+				regexp.MustCompile(`(?:^|/)mvnw(?:\.cmd)?$`),
+				regexp.MustCompile(`(?:^|/)\.mvn/wrapper/MavenWrapperDownloader\.java$`),
 
 				// ----------- JavaScript files -----------
 				// Dependencies and lock files.
-				regexp.MustCompile(`(^|/)node_modules(/.*)?$`),
-				regexp.MustCompile(`(^|/)(npm-shrinkwrap\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$`),
-				regexp.MustCompile(`(^|/)bower_components(/.*)?$`),
+				regexp.MustCompile(`(?:^|/)node_modules(?:/.*)?$`),
+				regexp.MustCompile(`(?:^|/)(?:npm-shrinkwrap\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$`),
+				regexp.MustCompile(`(?:^|/)bower_components(?:/.*)?$`),
 				// TODO: Add more common static assets, such as swagger-ui.
-				regexp.MustCompile(`(^|/)(angular|bootstrap|jquery(-?ui)?|plotly|swagger-?ui)[a-zA-Z0-9.-]*(\.min)?\.js(\.map)?$`),
-				regexp.MustCompile(`(^|/)javascript\.json$`),
+				regexp.MustCompile(`(?:^|/)(?:angular|bootstrap|jquery(?:-?ui)?|plotly|swagger-?ui)[a-zA-Z0-9.-]*(?:\.min)?\.js(?:\.map)?$`),
+				regexp.MustCompile(`(?:^|/)javascript\.json$`),
 
 				// ----------- Python files -----------
 				// Dependencies and lock files.
-				regexp.MustCompile(`(^|/)(Pipfile|poetry)\.lock$`),
+				regexp.MustCompile(`(?:^|/)(?:Pipfile|poetry)\.lock$`),
 				// Virtual environments
-				regexp.MustCompile(`(?i)/?(v?env|virtualenv)/lib(64)?(/.*)?$`),
-				regexp.MustCompile(`(?i)(^|/)(lib(64)?/python[23](\.\d{1,2})+|python/[23](\.\d{1,2})+/lib(64)?)(/.*)?$`),
+				regexp.MustCompile(`(?i)(?:^|/)(?:v?env|virtualenv)/lib(?:64)?(?:/.*)?$`),
+				regexp.MustCompile(`(?i)(?:^|/)(?:lib(?:64)?/python[23](?:\.\d{1,2})+|python/[23](?:\.\d{1,2})+/lib(?:64)?)(?:/.*)?$`),
 				// dist-info directory (https://py-pkgs.org/04-package-structure.html#building-sdists-and-wheels)
-				regexp.MustCompile(`(?i)(^|/)[a-z0-9_.]+-[0-9.]+\.dist-info(/.+)?$`),
+				regexp.MustCompile(`(?i)(?:^|/)[a-z0-9_.]+-[0-9.]+\.dist-info(?:/.+)?$`),
 
 				// ----------- Ruby files -----------
-				regexp.MustCompile(`(^|/)vendor/(bundle|ruby)(/.*?)?$`),
+				regexp.MustCompile(`(?:^|/)vendor/(?:bundle|ruby)(?:/.*?)?$`),
 				regexp.MustCompile(`\.gem$`), // tar archive
 
 				// Misc

+ 126 - 94
cmd/generate/config/base/config_test.go

@@ -4,70 +4,70 @@ import (
 	"testing"
 )
 
-func TestConfigAllowlistRegexes(t *testing.T) {
-	tests := map[string]struct {
-		invalid []string
-		valid   []string
-	}{
-		"general placeholders": {
-			invalid: []string{
-				`true`, `True`, `false`, `False`, `null`, `NULL`,
-			},
-		},
-		"general placeholders - repeated characters": {
-			invalid: []string{
-				`aaaaaaaaaaaaaaaaa`, `BBBBBBBBBBbBBBBBBBbBB`, `********************`,
-			},
-			valid: []string{`aaaaaaaaaaaaaaaaaaabaa`, `pas*************d`},
+var allowlistRegexTests = map[string]struct {
+	invalid []string
+	valid   []string
+}{
+	"general placeholders": {
+		invalid: []string{
+			`true`, `True`, `false`, `False`, `null`, `NULL`,
 		},
-		"environment variables": {
-			invalid: []string{`$2`, `$GIT_PASSWORD`, `${GIT_PASSWORD}`, `$password`},
-			valid:   []string{`$yP@R.@=ibxI`, `$2a6WCust9aE`, `${not_complete1`},
+	},
+	"general placeholders - repeated characters": {
+		invalid: []string{
+			`aaaaaaaaaaaaaaaaa`, `BBBBBBBBBBbBBBBBBBbBB`, `********************`,
 		},
-		"interpolated variables - ansible": {
-			invalid: []string{
-				`{{ x }}`, `{{ password }}`, `{{password}}`, `{{ data.proxy_password }}`,
-				`{{ dict1 | ansible.builtin.combine(dict2) }}`,
-			},
+		valid: []string{`aaaaaaaaaaaaaaaaaaabaa`, `pas*************d`},
+	},
+	"environment variables": {
+		invalid: []string{`$2`, `$GIT_PASSWORD`, `${GIT_PASSWORD}`, `$password`},
+		valid:   []string{`$yP@R.@=ibxI`, `$2a6WCust9aE`, `${not_complete1`},
+	},
+	"interpolated variables - ansible": {
+		invalid: []string{
+			`{{ x }}`, `{{ password }}`, `{{password}}`, `{{ data.proxy_password }}`,
+			`{{ dict1 | ansible.builtin.combine(dict2) }}`,
 		},
-		"interpolated variables - github actions": {
-			invalid: []string{
-				`${{ env.First_Name }}`,
-				`${{ env.DAY_OF_WEEK == 'Monday' }}`,
-				`${{env.JAVA_VERSION}}`,
-				`${{ github.event.issue.title }}`,
-				`${{ github.repository == "Gattocrucco/lsqfitgp" }}`,
-				`${{ github.event.pull_request.number || github.ref }}`,
-				`${{ github.event_name == 'pull_request' && github.event.action == 'unassigned' }}`,
-				`${{ secrets.SuperSecret }}`,
-				`${{ vars.JOB_NAME }}`,
-				`${{ vars.USE_VARIABLES == 'true' }}`,
-			},
+	},
+	"interpolated variables - github actions": {
+		invalid: []string{
+			`${{ env.First_Name }}`,
+			`${{ env.DAY_OF_WEEK == 'Monday' }}`,
+			`${{env.JAVA_VERSION}}`,
+			`${{ github.event.issue.title }}`,
+			`${{ github.repository == "Gattocrucco/lsqfitgp" }}`,
+			`${{ github.event.pull_request.number || github.ref }}`,
+			`${{ github.event_name == 'pull_request' && github.event.action == 'unassigned' }}`,
+			`${{ secrets.SuperSecret }}`,
+			`${{ vars.JOB_NAME }}`,
+			`${{ vars.USE_VARIABLES == 'true' }}`,
 		},
-		"interpolated variables - nuget": {
-			invalid: []string{
-				`%MY_PASSWORD%`, `%password%`,
-			},
+	},
+	"interpolated variables - nuget": {
+		invalid: []string{
+			`%MY_PASSWORD%`, `%password%`,
 		},
-		"interpolated variables - string fmt - golang": {
-			invalid: []string{
-				`%b`, `%c`, `%d`, `% d`, `%e`, `%E`, `%f`, `%F`, `%g`, `%G`, `%o`, `%O`, `%p`, `%q`, `%-s`, `%s`, `%t`, `%T`, `%U`, `%#U`, `%+v`, `%#v`, `%v`, `%x`, `%X`,
-			},
+	},
+	"interpolated variables - string fmt - golang": {
+		invalid: []string{
+			`%b`, `%c`, `%d`, `% d`, `%e`, `%E`, `%f`, `%F`, `%g`, `%G`, `%o`, `%O`, `%p`, `%q`, `%-s`, `%s`, `%t`, `%T`, `%U`, `%#U`, `%+v`, `%#v`, `%v`, `%x`, `%X`,
 		},
-		"interpolated variables - string fmt - python": {
-			invalid: []string{
-				`{}`, `{0}`, `{10}`,
-			},
+	},
+	"interpolated variables - string fmt - python": {
+		invalid: []string{
+			`{}`, `{0}`, `{10}`,
 		},
-		"interpolated variables - ucd": {
-			invalid: []string{`@password@`, `@LDAP_PASS@`},
-			valid:   []string{`@username@mastodon.example`},
-		},
-	}
+	},
+	"interpolated variables - ucd": {
+		invalid: []string{`@password@`, `@LDAP_PASS@`},
+		valid:   []string{`@username@mastodon.example`},
+	},
+}
 
+func TestConfigAllowlistRegexes(t *testing.T) {
 	cfg := CreateGlobalConfig()
 	allowlist := cfg.Allowlist
-	for name, cases := range tests {
+	for name, cases := range allowlistRegexTests {
 		t.Run(name, func(t *testing.T) {
 			for _, c := range cases.invalid {
 				if !allowlist.RegexAllowed(c) {
@@ -84,51 +84,67 @@ func TestConfigAllowlistRegexes(t *testing.T) {
 	}
 }
 
-func TestConfigAllowlistPaths(t *testing.T) {
-	tests := map[string]struct {
-		invalid []string
-		valid   []string
-	}{
-		"javascript - common static assets": {
-			invalid: []string{
-				`tests/e2e/nuget/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js`,
-				`src/main/static/lib/angular.1.2.16.min.js`,
-				`src/main/resources/static/jquery-ui-1.12.1/jquery-ui-min.js`,
-				`src/main/resources/static/js/jquery-ui-1.10.4.min.js`,
-				`src-static/js/plotly.min.js`,
-				`swagger/swaggerui/swagger-ui-bundle.js.map`,
-				`swagger/swaggerui/swagger-ui-es-bundle.js.map`,
-				`src/main/static/swagger-ui.min.js`,
-				`swagger/swaggerui/swagger-ui.js`,
-			},
+func BenchmarkConfigAllowlistRegexes(b *testing.B) {
+	cfg := CreateGlobalConfig()
+	allowlist := cfg.Allowlist
+	for n := 0; n < b.N; n++ {
+		for _, cases := range allowlistRegexTests {
+			for _, c := range cases.invalid {
+				allowlist.RegexAllowed(c)
+			}
+
+			for _, c := range cases.valid {
+				allowlist.RegexAllowed(c)
+			}
+		}
+	}
+}
+
+var allowlistPathsTests = map[string]struct {
+	invalid []string
+	valid   []string
+}{
+	"javascript - common static assets": {
+		invalid: []string{
+			`tests/e2e/nuget/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js`,
+			`src/main/static/lib/angular.1.2.16.min.js`,
+			`src/main/resources/static/jquery-ui-1.12.1/jquery-ui-min.js`,
+			`src/main/resources/static/js/jquery-ui-1.10.4.min.js`,
+			`src-static/js/plotly.min.js`,
+			`swagger/swaggerui/swagger-ui-bundle.js.map`,
+			`swagger/swaggerui/swagger-ui-es-bundle.js.map`,
+			`src/main/static/swagger-ui.min.js`,
+			`swagger/swaggerui/swagger-ui.js`,
 		},
-		"python": {
-			invalid: []string{
-				// lock files
-				`Pipfile.lock`, `poetry.lock`,
-				// virtual environments
-				"env/lib/python3.7/site-packages/urllib3/util/url.py",
-				"venv/Lib/site-packages/regex-2018.08.29.dist-info/DESCRIPTION.rst",
-				"venv/lib64/python3.5/site-packages/pynvml.py",
-				"python/python3/virtualenv/Lib/site-packages/pyphonetics/utils.py",
-				"virtualenv/lib64/python3.7/base64.py",
-				// packages
-				"cde-root/usr/lib64/python2.4/site-packages/Numeric.pth",
-				"lib/python3.9/site-packages/setuptools/_distutils/msvccompiler.py",
-				"lib/python3.8/site-packages/botocore/data/alexaforbusiness/2017-11-09/service-2.json",
-				"code/python/3.7.4/Lib/site-packages/dask/bytes/tests/test_bytes_utils.py",
-				"python/3.7.4/Lib/site-packages/fsspec/utils.py",
-				"python/2.7.16.32/Lib/bsddb/test/test_dbenv.py",
-				"python/lib/python3.8/site-packages/boto3/data/ec2/2016-04-01/resources-1.json",
-				// distinfo
-				"libs/PyX-0.15.dist-info/AUTHORS",
-			},
+	},
+	"python": {
+		invalid: []string{
+			// lock files
+			`Pipfile.lock`, `poetry.lock`,
+			// virtual environments
+			"env/lib/python3.7/site-packages/urllib3/util/url.py",
+			"venv/Lib/site-packages/regex-2018.08.29.dist-info/DESCRIPTION.rst",
+			"venv/lib64/python3.5/site-packages/pynvml.py",
+			"python/python3/virtualenv/Lib/site-packages/pyphonetics/utils.py",
+			"virtualenv/lib64/python3.7/base64.py",
+			// packages
+			"cde-root/usr/lib64/python2.4/site-packages/Numeric.pth",
+			"lib/python3.9/site-packages/setuptools/_distutils/msvccompiler.py",
+			"lib/python3.8/site-packages/botocore/data/alexaforbusiness/2017-11-09/service-2.json",
+			"code/python/3.7.4/Lib/site-packages/dask/bytes/tests/test_bytes_utils.py",
+			"python/3.7.4/Lib/site-packages/fsspec/utils.py",
+			"python/2.7.16.32/Lib/bsddb/test/test_dbenv.py",
+			"python/lib/python3.8/site-packages/boto3/data/ec2/2016-04-01/resources-1.json",
+			// distinfo
+			"libs/PyX-0.15.dist-info/AUTHORS",
 		},
-	}
+	},
+}
 
+func TestConfigAllowlistPaths(t *testing.T) {
 	cfg := CreateGlobalConfig()
 	allowlist := cfg.Allowlist
-	for name, cases := range tests {
+	for name, cases := range allowlistPathsTests {
 		t.Run(name, func(t *testing.T) {
 			for _, c := range cases.invalid {
 				if !allowlist.PathAllowed(c) {
@@ -144,3 +160,19 @@ func TestConfigAllowlistPaths(t *testing.T) {
 		})
 	}
 }
+
+func BenchmarkConfigAllowlistPaths(b *testing.B) {
+	cfg := CreateGlobalConfig()
+	allowlist := cfg.Allowlist
+	for n := 0; n < b.N; n++ {
+		for _, cases := range allowlistPathsTests {
+			for _, c := range cases.invalid {
+				allowlist.PathAllowed(c)
+			}
+
+			for _, c := range cases.valid {
+				allowlist.PathAllowed(c)
+			}
+		}
+	}
+}

+ 6 - 6
cmd/generate/config/rules/curl.go

@@ -19,12 +19,12 @@ func CurlBasicAuth() *config.Rule {
 		Allowlists: []config.Allowlist{
 			{
 				Regexes: []*regexp.Regexp{
-					regexp.MustCompile(`[^:]+:(change(it|me)|pass(word)?|pwd|test|token|\*+|x+)`), // common placeholder passwords
-					regexp.MustCompile(`['"]?<[^>]+>['"]?:['"]?<[^>]+>|<[^:]+:[^>]+>['"]?`),       // <placeholder>
-					regexp.MustCompile(`[^:]+:\[[^]]+]`),                                          // [placeholder]
-					regexp.MustCompile(`['"]?[^:]+['"]?:['"]?\$(\d|\w+|\{(\d|\w+)})['"]?`),        // $1 or $VARIABLE
-					regexp.MustCompile(`\$\([^)]+\):\$\([^)]+\)`),                                 // $(cat login.txt)
-					regexp.MustCompile(`['"]?\$?{{[^}]+}}['"]?:['"]?\$?{{[^}]+}}['"]?`),           // ${{ secrets.FOO }} or {{ .Values.foo }}
+					regexp.MustCompile(`[^:]+:(?:change(?:it|me)|pass(?:word)?|pwd|test|token|\*+|x+)`), // common placeholder passwords
+					regexp.MustCompile(`['"]?<[^>]+>['"]?:['"]?<[^>]+>|<[^:]+:[^>]+>['"]?`),             // <placeholder>
+					regexp.MustCompile(`[^:]+:\[[^]]+]`),                                                // [placeholder]
+					regexp.MustCompile(`['"]?[^:]+['"]?:['"]?\$(?:\d|\w+|\{(?:\d|\w+)})['"]?`),          // $1 or $VARIABLE
+					regexp.MustCompile(`\$\([^)]+\):\$\([^)]+\)`),                                       // $(cat login.txt)
+					regexp.MustCompile(`['"]?\$?{{[^}]+}}['"]?:['"]?\$?{{[^}]+}}['"]?`),                 // ${{ secrets.FOO }} or {{ .Values.foo }}
 				},
 			},
 		},

+ 14 - 14
cmd/generate/config/rules/generic.go

@@ -49,13 +49,13 @@ func GenericCredential() *config.Rule {
 				MatchCondition: config.AllowlistMatchOr,
 				RegexTarget:    "match",
 				Regexes: []*regexp.Regexp{
-					regexp.MustCompile(`(?i)(` +
+					regexp.MustCompile(`(?i)(?:` +
 						// Access
-						`access(ibility|or)` +
+						`access(?:ibility|or)` +
 						`|access[_.-]?id` +
 						`|random[_.-]?access` +
 						// API
-						`|api[_.-]?(id|name|version)` + // id/name/version -> not a secret
+						`|api[_.-]?(?:id|name|version)` + // id/name/version -> not a secret
 						`|rapid|capital` + // common words containing "api"
 						`|[a-z0-9-]*?api[a-z0-9-]*?:jar:` + // Maven META-INF dependencies that contain "api" in the name.
 						// Auth
@@ -63,29 +63,29 @@ func GenericCredential() *config.Rule {
 						`|X-MS-Exchange-Organization-Auth` + // email header
 						`|Authentication-Results` + // email header
 						// Credentials
-						`|(credentials?[_.-]?id|withCredentials)` + // Jenkins plugins
+						`|(?:credentials?[_.-]?id|withCredentials)` + // Jenkins plugins
 						// Key
-						`|(bucket|foreign|hot|idx|natural|primary|pub(lic)?|schema|sequence)[_.-]?key` +
-						`|key[_.-]?(alias|board|code|frame|id|length|mesh|name|pair|ring|selector|signature|size|stone|storetype|word|up|down|left|right)` +
+						`|(?:bucket|foreign|hot|idx|natural|primary|pub(?:lic)?|schema|sequence)[_.-]?key` +
+						`|key[_.-]?(?:alias|board|code|frame|id|length|mesh|name|pair|ring|selector|signature|size|stone|storetype|word|up|down|left|right)` +
 						// Azure KeyVault
-						`|key[_.-]?vault[_.-]?(id|name)|keyVaultToStoreSecrets` +
-						`|key(store|tab)[_.-]?(file|path)` +
+						`|key[_.-]?vault[_.-]?(?:id|name)|keyVaultToStoreSecrets` +
+						`|key(?:store|tab)[_.-]?(?:file|path)` +
 						`|issuerkeyhash` + // part of ssl cert
 						`|(?-i:[DdMm]onkey|[DM]ONKEY)|keying` + // common words containing "key"
 						// Secret
-						`|(secret)[_.-]?(length|name|size)` + // name of e.g. env variable
+						`|(?:secret)[_.-]?(?:length|name|size)` + // name of e.g. env variable
 						`|UserSecretsId` + // https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-8.0&tabs=linux
 
 						// Token
-						`|(io\.jsonwebtoken[ \t]?:[ \t]?[\w-]+)` + // Maven library coordinats. (e.g., https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt)
+						`|(?:io\.jsonwebtoken[ \t]?:[ \t]?[\w-]+)` + // Maven library coordinats. (e.g., https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt)
 
 						// General
-						`|(api|credentials|token)[_.-]?(endpoint|ur[il])` +
+						`|(?:api|credentials|token)[_.-]?(?:endpoint|ur[il])` +
 						`|public[_.-]?token` +
-						`|(key|token)[_.-]?file` +
+						`|(?:key|token)[_.-]?file` +
 						// Empty variables capturing the next line (e.g., .env files)
-						`|(?-i:([A-Z_]+=\n[A-Z_]+=|[a-z_]+=\n[a-z_]+=)(\n|\z))` +
-						`|(?-i:([A-Z.]+=\n[A-Z.]+=|[a-z.]+=\n[a-z.]+=)(\n|\z))` +
+						`|(?-i:(?:[A-Z_]+=\n[A-Z_]+=|[a-z_]+=\n[a-z_]+=)(?:\n|\z))` +
+						`|(?-i:(?:[A-Z.]+=\n[A-Z.]+=|[a-z.]+=\n[a-z.]+=)(?:\n|\z))` +
 						`)`),
 				},
 				StopWords: append(DefaultStopWords,

+ 1 - 1
cmd/generate/config/rules/github.go

@@ -11,7 +11,7 @@ var githubAllowlist = []config.Allowlist{
 	{
 		Paths: []*regexp.Regexp{
 			// https://github.com/octokit/auth-token.js/?tab=readme-ov-file#createtokenauthtoken-options
-			regexp.MustCompile(`(^|/)@octokit/auth-token/README\.md$`),
+			regexp.MustCompile(`(?:^|/)@octokit/auth-token/README\.md$`),
 		},
 	},
 }

+ 1 - 1
cmd/generate/config/rules/kubernetes.go

@@ -45,7 +45,7 @@ func KubernetesSecret() *config.Rule {
 				// Avoid overreach between directives.
 				RegexTarget: "match",
 				Regexes: []*regexp.Regexp{
-					regexp.MustCompile(`(kind:(.|\s)+\n---\n(.|\s)+\bdata:|data:(.|\s)+\n---\n(.|\s)+\bkind:)`),
+					regexp.MustCompile(`(kind:(?:.|\s)+\n---\n(?:.|\s)+\bdata:|data:(?:.|\s)+\n---\n(?:.|\s)+\bkind:)`),
 				},
 			},
 		},

+ 32 - 32
config/gitleaks.toml

@@ -15,38 +15,38 @@ description = "global allow lists"
 regexes = [
     '''(?i)^true|false|null$''',
     '''^(?i:a+|b+|c+|d+|e+|f+|g+|h+|i+|j+|k+|l+|m+|n+|o+|p+|q+|r+|s+|t+|u+|v+|w+|x+|y+|z+|\*+|\.+)$''',
-    '''^\$(\d+|{\d+})$''',
-    '''^\$([A-Z_]+|[a-z_]+)$''',
-    '''^\${([A-Z_]+|[a-z_]+)}$''',
+    '''^\$(?:\d+|{\d+})$''',
+    '''^\$(?:[A-Z_]+|[a-z_]+)$''',
+    '''^\${(?:[A-Z_]+|[a-z_]+)}$''',
     '''^\{\{[ \t]*[\w ().|]+[ \t]*}}$''',
-    '''^\$\{\{[ \t]*((env|github|secrets|vars)(\.[A-Za-z]\w+)+[\w "'&./=|]*)[ \t]*}}$''',
-    '''^%([A-Z_]+|[a-z_]+)%$''',
+    '''^\$\{\{[ \t]*(?:(?:env|github|secrets|vars)(?:\.[A-Za-z]\w+)+[\w "'&./=|]*)[ \t]*}}$''',
+    '''^%(?:[A-Z_]+|[a-z_]+)%$''',
     '''^%[+\-# 0]?[bcdeEfFgGoOpqstTUvxX]$''',
     '''^\{\d{0,2}}$''',
-    '''^@([A-Z_]+|[a-z_]+)@$''',
+    '''^@(?:[A-Z_]+|[a-z_]+)@$''',
 ]
 paths = [
     '''gitleaks\.toml''',
-    '''(?i)\.(bmp|gif|jpe?g|svg|tiff?)$''',
-    '''\.(eot|[ot]tf|woff2?)$''',
-    '''(.*?)(doc|docx|zip|xls|pdf|bin|socket|vsidx|v2|suo|wsuo|.dll|pdb|exe|gltf)$''',
-    '''go\.(mod|sum|work(\.sum)?)$''',
-    '''(^|/)vendor/modules\.txt$''',
-    '''(^|/)vendor/(github\.com|golang\.org/x|google\.golang\.org|gopkg\.in|istio\.io|k8s\.io|sigs\.k8s\.io)(/.*)?$''',
-    '''(^|/)gradlew(\.bat)?$''',
-    '''(^|/)gradle\.lockfile$''',
-    '''(^|/)mvnw(\.cmd)?$''',
-    '''(^|/)\.mvn/wrapper/MavenWrapperDownloader\.java$''',
-    '''(^|/)node_modules(/.*)?$''',
-    '''(^|/)(npm-shrinkwrap\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$''',
-    '''(^|/)bower_components(/.*)?$''',
-    '''(^|/)(angular|bootstrap|jquery(-?ui)?|plotly|swagger-?ui)[a-zA-Z0-9.-]*(\.min)?\.js(\.map)?$''',
-    '''(^|/)javascript\.json$''',
-    '''(^|/)(Pipfile|poetry)\.lock$''',
-    '''(?i)/?(v?env|virtualenv)/lib(64)?(/.*)?$''',
-    '''(?i)(^|/)(lib(64)?/python[23](\.\d{1,2})+|python/[23](\.\d{1,2})+/lib(64)?)(/.*)?$''',
-    '''(?i)(^|/)[a-z0-9_.]+-[0-9.]+\.dist-info(/.+)?$''',
-    '''(^|/)vendor/(bundle|ruby)(/.*?)?$''',
+    '''(?i)\.(?:bmp|gif|jpe?g|png|svg|tiff?)$''',
+    '''(?i)\.(?:eot|[ot]tf|woff2?)$''',
+    '''(?i)\.(?:docx?|xlsx?|pdf|bin|socket|vsidx|v2|suo|wsuo|.dll|pdb|exe|gltf|zip)$''',
+    '''go\.(?:mod|sum|work(?:\.sum)?)$''',
+    '''(?:^|/)vendor/modules\.txt$''',
+    '''(?:^|/)vendor/(?:github\.com|golang\.org/x|google\.golang\.org|gopkg\.in|istio\.io|k8s\.io|sigs\.k8s\.io)(?:/.*)?$''',
+    '''(?:^|/)gradlew(?:\.bat)?$''',
+    '''(?:^|/)gradle\.lockfile$''',
+    '''(?:^|/)mvnw(?:\.cmd)?$''',
+    '''(?:^|/)\.mvn/wrapper/MavenWrapperDownloader\.java$''',
+    '''(?:^|/)node_modules(?:/.*)?$''',
+    '''(?:^|/)(?:npm-shrinkwrap\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$''',
+    '''(?:^|/)bower_components(?:/.*)?$''',
+    '''(?:^|/)(?:angular|bootstrap|jquery(?:-?ui)?|plotly|swagger-?ui)[a-zA-Z0-9.-]*(?:\.min)?\.js(?:\.map)?$''',
+    '''(?:^|/)javascript\.json$''',
+    '''(?:^|/)(?:Pipfile|poetry)\.lock$''',
+    '''(?i)(?:^|/)(?:v?env|virtualenv)/lib(?:64)?(?:/.*)?$''',
+    '''(?i)(?:^|/)(?:lib(?:64)?/python[23](?:\.\d{1,2})+|python/[23](?:\.\d{1,2})+/lib(?:64)?)(?:/.*)?$''',
+    '''(?i)(?:^|/)[a-z0-9_.]+-[0-9.]+\.dist-info(?:/.+)?$''',
+    '''(?:^|/)vendor/(?:bundle|ruby)(?:/.*?)?$''',
     '''\.gem$''',
     '''verification-metadata\.xml''',
     '''Database.refactorlog''',
@@ -298,10 +298,10 @@ entropy = 2
 keywords = ["curl"]
 [[rules.allowlists]]
 regexes = [
-    '''[^:]+:(change(it|me)|pass(word)?|pwd|test|token|\*+|x+)''',
+    '''[^:]+:(?:change(?:it|me)|pass(?:word)?|pwd|test|token|\*+|x+)''',
     '''['"]?<[^>]+>['"]?:['"]?<[^>]+>|<[^:]+:[^>]+>['"]?''',
     '''[^:]+:\[[^]]+]''',
-    '''['"]?[^:]+['"]?:['"]?\$(\d|\w+|\{(\d|\w+)})['"]?''',
+    '''['"]?[^:]+['"]?:['"]?\$(?:\d|\w+|\{(?:\d|\w+)})['"]?''',
     '''\$\([^)]+\):\$\([^)]+\)''',
     '''['"]?\$?{{[^}]+}}['"]?:['"]?\$?{{[^}]+}}['"]?''',
 ]
@@ -586,7 +586,7 @@ regexes = [
 [[rules.allowlists]]
 regexTarget = "match"
 regexes = [
-    '''(?i)(access(ibility|or)|access[_.-]?id|random[_.-]?access|api[_.-]?(id|name|version)|rapid|capital|[a-z0-9-]*?api[a-z0-9-]*?:jar:|author|X-MS-Exchange-Organization-Auth|Authentication-Results|(credentials?[_.-]?id|withCredentials)|(bucket|foreign|hot|idx|natural|primary|pub(lic)?|schema|sequence)[_.-]?key|key[_.-]?(alias|board|code|frame|id|length|mesh|name|pair|ring|selector|signature|size|stone|storetype|word|up|down|left|right)|key[_.-]?vault[_.-]?(id|name)|keyVaultToStoreSecrets|key(store|tab)[_.-]?(file|path)|issuerkeyhash|(?-i:[DdMm]onkey|[DM]ONKEY)|keying|(secret)[_.-]?(length|name|size)|UserSecretsId|(io\.jsonwebtoken[ \t]?:[ \t]?[\w-]+)|(api|credentials|token)[_.-]?(endpoint|ur[il])|public[_.-]?token|(key|token)[_.-]?file|(?-i:([A-Z_]+=\n[A-Z_]+=|[a-z_]+=\n[a-z_]+=)(\n|\z))|(?-i:([A-Z.]+=\n[A-Z.]+=|[a-z.]+=\n[a-z.]+=)(\n|\z)))''',
+    '''(?i)(?:access(?:ibility|or)|access[_.-]?id|random[_.-]?access|api[_.-]?(?:id|name|version)|rapid|capital|[a-z0-9-]*?api[a-z0-9-]*?:jar:|author|X-MS-Exchange-Organization-Auth|Authentication-Results|(?:credentials?[_.-]?id|withCredentials)|(?:bucket|foreign|hot|idx|natural|primary|pub(?:lic)?|schema|sequence)[_.-]?key|key[_.-]?(?:alias|board|code|frame|id|length|mesh|name|pair|ring|selector|signature|size|stone|storetype|word|up|down|left|right)|key[_.-]?vault[_.-]?(?:id|name)|keyVaultToStoreSecrets|key(?:store|tab)[_.-]?(?:file|path)|issuerkeyhash|(?-i:[DdMm]onkey|[DM]ONKEY)|keying|(?:secret)[_.-]?(?:length|name|size)|UserSecretsId|(?:io\.jsonwebtoken[ \t]?:[ \t]?[\w-]+)|(?:api|credentials|token)[_.-]?(?:endpoint|ur[il])|public[_.-]?token|(?:key|token)[_.-]?file|(?-i:(?:[A-Z_]+=\n[A-Z_]+=|[a-z_]+=\n[a-z_]+=)(?:\n|\z))|(?-i:(?:[A-Z.]+=\n[A-Z.]+=|[a-z.]+=\n[a-z.]+=)(?:\n|\z)))''',
 ]
 stopwords = [
     "000000",
@@ -2084,7 +2084,7 @@ keywords = [
 ]
 [[rules.allowlists]]
 paths = [
-    '''(^|/)@octokit/auth-token/README\.md$''',
+    '''(?:^|/)@octokit/auth-token/README\.md$''',
 ]
 
 [[rules]]
@@ -2109,7 +2109,7 @@ entropy = 3
 keywords = ["ghp_"]
 [[rules.allowlists]]
 paths = [
-    '''(^|/)@octokit/auth-token/README\.md$''',
+    '''(?:^|/)@octokit/auth-token/README\.md$''',
 ]
 
 [[rules]]
@@ -2385,7 +2385,7 @@ regexes = [
 [[rules.allowlists]]
 regexTarget = "match"
 regexes = [
-    '''(kind:(.|\s)+\n---\n(.|\s)+\bdata:|data:(.|\s)+\n---\n(.|\s)+\bkind:)''',
+    '''(kind:(?:.|\s)+\n---\n(?:.|\s)+\bdata:|data:(?:.|\s)+\n---\n(?:.|\s)+\bkind:)''',
 ]
 
 [[rules]]