--- /home/worsch/repo-manager/src/repo_manager/secret_scan.py +++ /home/worsch/repo-manager/src/repo_manager/secret_scan.py @@ -55,7 +55,7 @@ description = "Filename key whose value is a lowercase 64-hex content digest" targetRules = ["generic-api-key"] regexTarget = "match" -regexes = ['^[\w.-]+\.(?:md|markdown|txt|yaml|yml|json|py|toml):[ \t]+[a-f0-9]{64}$'] +regexes = ['^[\w.-]+\.(?:md|markdown|txt|yaml|yml|json|py|toml)(?::[ \t]+[a-f0-9]{64}|":[ \t]+"[a-f0-9]{64}")$'] """ --- /home/worsch/repo-manager/tests/test_secret_scan.py +++ /home/worsch/repo-manager/tests/test_secret_scan.py @@ -479,3 +479,21 @@ if process.poll() is None: process.kill(); process.wait(timeout=5) process.stdout.close() + + +@pytest.mark.parametrize("key", ["values/secrets-engine.yaml", "docs/runtime-externalsecret.r1.yaml"]) +def test_json_filename_digest_is_allowed(binary, repo, key): + digest = os.urandom(32).hex() + stage(repo, json.dumps({key: digest}).encode(), "source-pin.json") + assert secret_scan.scan_staged(repo, binary)["status"] == "clean" + + +@pytest.mark.parametrize("content", [ + lambda digest: json.dumps({"secret": digest}), + lambda digest: json.dumps({"values/secrets-engine.yaml": "glpat-" + digest}), + lambda digest: json.dumps({"values/secrets-engine.yaml": digest + "a"}), + lambda digest: json.dumps({"values/secrets-engine.yaml": digest.upper()}), +]) +def test_json_digest_exception_does_not_allow_secret_shapes(binary, repo, content): + stage(repo, content(os.urandom(32).hex()).encode(), "manifest.json") + assert secret_scan.scan_staged(repo, binary)["status"] == "blocked" --- /home/worsch/railiance-forge/tools/receive-secret-scan/main.go +++ /home/worsch/railiance-forge/tools/receive-secret-scan/main.go @@ -36,7 +36,7 @@ description = "Filename key whose value is a lowercase 64-hex content digest" targetRules = ["generic-api-key"] regexTarget = "match" -regexes = ['^[\w.-]+\.(?:md|markdown|txt|yaml|yml|json|py|toml):[ \t]+[a-f0-9]{64}$'] +regexes = ['^[\w.-]+\.(?:md|markdown|txt|yaml|yml|json|py|toml)(?::[ \t]+[a-f0-9]{64}|":[ \t]+"[a-f0-9]{64}")$'] ` const maxInput = 512 * 1024 const maxObject = 8 * 1024 * 1024 --- /home/worsch/railiance-forge/tools/receive-secret-scan/batch_test.go +++ /home/worsch/railiance-forge/tools/receive-secret-scan/batch_test.go @@ -188,6 +188,11 @@ {"inline-suppression", append([]byte("# gitleaks:allow\n"), privateKey...), true}, {"filename-digest", []byte(" cards/access.md: " + digest + "\n"), false}, {"bare-keyword-digest", []byte("access: " + digest + "\n"), true}, + {"json-filename-digest", []byte("{\"values/secrets-engine.yaml\": \"" + digest + "\"}\n"), false}, + {"json-bare-secret-digest", []byte("{\"secret\": \"" + digest + "\"}\n"), true}, + {"json-filename-token", []byte("{\"values/secrets-engine.yaml\": \"" + string(canary) + "\"}\n"), true}, + {"json-filename-long-digest", []byte("{\"values/secrets-engine.yaml\": \"" + digest + "a\"}\n"), true}, + {"json-filename-uppercase-digest", []byte("{\"values/secrets-engine.yaml\": \"" + strings.ToUpper(digest) + "\"}\n"), true}, } { t.Run(tc.name, func(t *testing.T) { stdin, e := scan(context.Background(), f, config, tc.input)