fix(kvb-check-security): accept a finding without a line by the sha1 of its file

A MEDUSA finding without a line number (a Dockerfile-level rule, for example) had no fingerprint, so security.py accept could never waive it and the score stayed below 100 after review. Such a finding is now keyed by the sha1 of the whole file; any edit of the file brings it back.

🎯 Fix: 95 %
💥 Break: 2 %
💸 Cost: 100 %
⏱️ Time: 100 %
🛡️ Security: 100 %
🏆 Score: 93
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Veen-BirkenbachandClaude Opus 5.5 committed 2026-11-11 15:48:11 +00:00
1 parent 45063dc71f
commit 87426c0046
2 files changed
+24 -6

No files matched your search

+10 -6
View File
@@ -20,12 +20,13 @@ Scan:
Accepted:
One JSON row per reviewed false positive (id, rule, path, sha1 of the stripped
source line, reason, repo, date), appended by accept to
source line, or of the whole file for a finding without a line, reason, repo,
date), appended by accept to
<council root>/security-accepted.jsonl of the kvb-org-organize watch.py, whose
hook keeps the rows in ~/.local/state/agents-council/security-accepted.jsonl;
a scan reads both. A finding with that rule, path and line text is accepted and
leaves the score; an edit of the line brings it back. A row without rule, path
and sha1 is a usage error.
a scan reads both. A finding with that rule, path and text is accepted and
leaves the score; an edit of the line, or of the file, brings it back. A row
without rule, path and sha1 is a usage error.
Output:
`🛡️ security <n> % (medusa: <k> findings, <a> accepted in <m> files: <severity> <path>:<line>, ...)`,
@@ -116,10 +117,13 @@ def located(name: str, tree: Path) -> str:
def fingerprint(tree: Path, path: str, line: int | None) -> str | None:
try:
rows = (tree / path).read_text(encoding="utf-8", errors="replace").splitlines()
text = (tree / path).read_text(encoding="utf-8", errors="replace")
except OSError:
return None
if line is None or not 1 <= line <= len(rows):
if line is None:
return hashlib.sha1(text.encode()).hexdigest()
rows = text.splitlines()
if not 1 <= line <= len(rows):
return None
return hashlib.sha1(rows[line - 1].strip().encode()).hexdigest()
+14
View File
@@ -33,6 +33,8 @@ for path in sorted(p for p in target.rglob("*") if p.is_file()):
"severity": severity, "rule_id": "FAKE-" + severity, "file": str(path), "line": number,
"code": text,
}})
if "MARK-FILE" in text:
findings.append({{"severity": "MEDIUM", "rule_id": "FAKE-FILE", "file": str(path), "line": None}})
report = {{"issues": findings}} if os.environ.get("FAKE_MEDUSA_SHAPE") == "other" else {{"findings": findings}}
(out / "medusa-scan-20261104-120000.json").write_text(json.dumps(report))
"""
@@ -163,6 +165,18 @@ class TestSecurity(unittest.TestCase):
self.assertEqual(result.returncode, 2)
self.assertIn("--sha1 must be 40 lowercase hex digits", result.stderr)
def test_a_file_level_finding_is_accepted_by_the_sha1_of_its_file_until_the_file_changes(self):
text = "FROM debian # MARK-FILE\n"
self.write("Dockerfile", text)
sha1 = hashlib.sha1(text.encode()).hexdigest()
self.assertEqual(json.loads(self.scan("--json", env=self.env).stdout)["findings"][0]["sha1"], sha1)
result = self.accept("--rule", "FAKE-FILE", "--path", "Dockerfile", "--sha1", sha1, "--reason", "fixture")
self.assertEqual(result.returncode, 0, result.stderr)
result = self.scan(env=self.env)
self.assertEqual(result.stdout, "🛡️ security 100 % (medusa: 0 findings, 1 accepted in 1 file)\n")
self.write("Dockerfile", text + "USER app\n")
self.assertEqual(self.scan(env=self.env).returncode, 3)
def test_one_accept_takes_every_rule_of_a_line(self):
line = "z = both() # MARK-HIGH MARK-LOW"
self.write("app.py", f"{line}\n")