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
|
|
@ -363,7 +363,6 @@ def _analyze_images(cfg, ai_cfg, api_key, snap, diff, entries, result, router, e
|
|||
if not current_img_urls:
|
||||
return False
|
||||
|
||||
has_image_entries = any(e.get("kind") == "image" for e in entries.values())
|
||||
changed = {pd["url"] for pd in diff.get("page_diffs", [])} | set(diff.get("new_internal_urls", []))
|
||||
changed_img_urls = _all_image_urls(snap, only_pages=changed)
|
||||
# Markierte Bilder erneut holen: ersetztes Bild → neue Bytes → Neubewertung
|
||||
|
|
@ -373,13 +372,18 @@ def _analyze_images(cfg, ai_cfg, api_key, snap, diff, entries, result, router, e
|
|||
if e.get("kind") == "image" and e.get("category", "clean") != "clean"
|
||||
and not e.get("dismissed") and e.get("url") in current_img_urls
|
||||
}
|
||||
# Noch nie analysierte Bilder (URL nicht im Ledger): bauen über mehrere Scans die
|
||||
# VOLLE Abdeckung auf — sonst bliebe jedes Bild jenseits des ersten Budget-Fensters
|
||||
# ein dauerhafter blinder Fleck (z. B. ein eingeschleustes strafbares Logo auf einer
|
||||
# ansonsten stabilen Seite). Bytes-Änderungen bekannter Bilder deckt check-assets ab.
|
||||
known_img_urls = {e["url"] for e in entries.values() if e.get("kind") == "image"}
|
||||
coverage_urls = current_img_urls - known_img_urls
|
||||
|
||||
if has_image_entries:
|
||||
fetch_urls = sorted((changed_img_urls | flagged_img_urls) & current_img_urls)
|
||||
else:
|
||||
fetch_urls = sorted(current_img_urls) # Erstlauf: vollständiger Sweep
|
||||
|
||||
fetch_urls = fetch_urls[: img_cfg.get("max_images_per_scan", 15)]
|
||||
# Priorität: geänderte/geflaggte Bilder zuerst, dann mit dem Restbudget Abdeckung aufbauen.
|
||||
priority = sorted((changed_img_urls | flagged_img_urls) & current_img_urls)
|
||||
coverage = sorted(coverage_urls - set(priority))
|
||||
budget = img_cfg.get("max_images_per_scan", 15)
|
||||
fetch_urls = (priority + coverage)[:budget]
|
||||
if not fetch_urls:
|
||||
return False
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue