the-custodian/docs/changes/2026-11-01-scanner-json-digest/scanner-json-digest.patch
codex ed93d0b21f
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Reject generated-only commits / generated-commit-guard (push) Waiting to run
docs: record fleet synchronization results and scanner blockers
2026-11-01 23:49:05 +01:00

60 lines
3.2 KiB
Diff

--- /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)