fix: volle Bildabdeckung — kein dauerhaft ungeprüftes Bild mehr
Sicherheitslücke: Die Bildanalyse baute keine Abdeckung auf. Nach dem ersten Budget-Fenster (max_images_per_scan) wurden nur noch Bilder auf GEÄNDERTEN Seiten oder bereits geflaggte nachgeholt. Bilder auf stabilen Seiten jenseits des ersten Fensters blieben dauerhaft ungeprüft (real: 10 von 201 analysiert). Ein Angreifer hätte so ein strafbares Logo (z. B. Hakenkreuz) auf einer stabilen Firmenseite platzieren können, ohne dass die KI es je inhaltlich prüft. Fix: Jeder Scan holt zusätzlich noch nicht analysierte Bilder (URL nicht im Ledger) bis zum Budget nach → volle Abdeckung baut sich über mehrere Scans auf (wie beim Text). Priorität: geänderte/geflaggte Bilder zuerst, dann Restbudget für die Abdeckung. Byte-Änderungen bekannter Bilder deckt check-assets ab. Bewusste Entscheidung GEGEN ai_analysis.image.exclude_paths: ein Pfad-Ausschluss (z. B. /content/companies/) wäre genau der blinde Fleck — strafbare Logos würden durchrutschen. Stattdessen: initiales "Gemecker" anhören, legitime Logos einmalig per ai-dismiss akzeptieren (Quittung am Byte-Hash → ausgetauschtes Bild flaggt neu). Tests: 255 grün (+1: Abdeckung baut sich über mehrere Scans bis 100% auf). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
3ab313e733
commit
6c7e69e635
3 changed files with 53 additions and 8 deletions
|
|
@ -208,6 +208,28 @@ class TestImages:
|
|||
assert res["findings"][0]["kind"] == "image"
|
||||
assert res["findings"][0]["asset_url"] == "https://x.de/bild.jpg"
|
||||
|
||||
def test_image_coverage_builds_over_scans(self, tmp_path, monkeypatch):
|
||||
"""Bilder jenseits des Budgets dürfen kein blinder Fleck sein:
|
||||
jeder Scan deckt weitere, noch nie analysierte Bilder ab."""
|
||||
monkeypatch.setenv("OPENROUTER_API_KEY", "test")
|
||||
bm = BaselineManager(tmp_path)
|
||||
cfg = self._cfg_img()
|
||||
cfg["ai_analysis"]["image"]["max_images_per_scan"] = 2
|
||||
# 5 Bilder auf einer Seite, Budget 2 → volle Abdeckung über 3 Scans
|
||||
imgs = [{"url": f"https://x.de/img{i}.jpg", "class": "internal"} for i in range(5)]
|
||||
snap = _snap("kurz", img=imgs)
|
||||
hashes = {f"https://x.de/img{i}.jpg": {"sha256": f"h{i}", "size": 1, "error": None}
|
||||
for i in range(5)}
|
||||
|
||||
analysed = set()
|
||||
for _ in range(3): # drei aufeinanderfolgende Scans
|
||||
with patch("scanner.ai_analyzer.fetch_asset_hashes", return_value=hashes), \
|
||||
patch("scanner.ai_analyzer._openrouter_chat", return_value=_verdict()):
|
||||
run_ai_analysis(cfg, bm, snap, {})
|
||||
analysed = {e["url"] for e in bm.load_ai_ledger()["entries"].values()
|
||||
if e.get("kind") == "image"}
|
||||
assert len(analysed) == 5 # nach 3 Scans sind alle 5 Bilder abgedeckt
|
||||
|
||||
def test_image_cache_hit_second_scan(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("OPENROUTER_API_KEY", "test")
|
||||
bm = BaselineManager(tmp_path)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue