Merge fix/kvb-check-security/file-level-fingerprint into master
🎯 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:
commit
928d50f600
2 files changed
+24
-6
No files matched your search
@@ -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()
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in new issue
Block a user