Commit graph

6 commits

Author SHA1 Message Date
6c7e69e635 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>
2026-06-13 04:02:35 +02:00
125d80e7f9 feat: adaptiver Modell-Router (Circuit-Breaker) + parallele KI-Analyse
Der reale Erst-Scan dauerte ~10 min, weil pro Kandidat sequenziell erst die
rate-limited Free-Modelle (429) probiert wurden. Zwei Hebel beheben das:

1. ModelRouter: programmatische Telemetrie statt LLM-Orchestrator. Pro Modell
   Erfolg/Latenz; ausgefallene/rate-limited Modelle bekommen per Circuit-Breaker
   einen Cooldown und werden übersprungen, das schnellste gesunde Modell zuerst.
   Failsafe-Pruning toter Slugs über OpenRouter /models (24h-Cache). State
   persistent in data/ai_router_state.json.

2. Parallelisierung: ThreadPoolExecutor mit konfigurierbarer max_concurrency
   (Default 8, I/O-gebunden → an API-Rate-Limits gebunden, nicht an CPU-Kerne).
   Klassifikationen laufen nebenläufig, Merge im Hauptthread (keine Locks),
   findings deterministisch sortiert. Fingerprint-Gruppierung: identischer
   Inhalt wird nur einmal klassifiziert, Funde aber für alle URLs emittiert.

Realtest bredelar.info: Frisch-Scan von ~10 min auf 1:01 min; Breaker öffnete
14× (Free-Modelle übersprungen), alle Verdikte von gemini-2.5-flash-lite.

Config: max_concurrency, breaker_failure_threshold, breaker_cooldown_seconds,
refresh_models. Tests: 251 grün (+12: Router-Reihung/Breaker/Pruning-failsafe,
parallel==sequenziell, Dedup, deterministische Reihenfolge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 02:51:30 +02:00
31730403b3 fix: KI-Robustheit — harter Wanduhr-Deadline + persistenter Ledger
Ein echter Durchlauf auf bredelar.info deckte zwei Bugs auf, die mit
gemockten Tests unsichtbar waren:

1. Hang: attempt_timeout wurde nur als requests-Inaktivitäts-Timeout
   übergeben. Ein Free-Modell, das die Verbindung offen hält oder Tokens
   langsam tröpfeln lässt, umging ihn → der ganze Scan hing unbegrenzt
   (real auf einem Bild >5 min). Fix: _post_with_deadline führt den Call
   in einem Worker-Thread mit future.result(timeout=...) aus — hartes
   Wanduhr-Limit, bei Überschreitung Eskalation statt Hang.

2. Verlust bei Abbruch: Das Ledger wurde nur ganz am Ende gespeichert,
   ein Hang/Crash verwarf alle berechneten Verdikte. Fix: Zwischensicherung
   nach der Textphase + im finally — Verdikte überleben einen Abbruch.

Zusätzlich attempt_timeout 30 → 20 s (flottere Eskalation).

Im erneuten Lauf griff der Deadline 4× sauber, der Scan lief vollständig
durch (Gelb: ein off_topic_commercial-Fund auf einer Gewerbe-Seite).

Tests: 239 grün (+2: Deadline kappt Hang <2s, Textverdikte überleben
Bildphasen-Crash).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 02:11:14 +02:00
a8dcaabf7c feat: schwerwiegende KI-Funde dürfen ROT auslösen (konfigurierbar)
Bisher war das KI-Level hart auf Gelb gedeckelt — auch injizierte
Pornografie oder strafbare/diffamierende Inhalte lösten nie Rot aus.
Das unterschätzt echte Notfälle (Sicherheits- + Rechts-/Reputationsrisiko).

Neu: kategoriebasierter Grave-Override in score_ai_findings. Nur Kategorien
aus red_categories (default ["pornography","defamation_illegal"]) lösen Rot
aus, und nur bei Schwere ≥ red_min_severity (high) UND Konfidenz ≥
red_min_confidence (0.9). Alle anderen Kategorien (Spam, Off-Topic,
Propaganda, Widerspruch) bleiben höchstens Gelb. Die Punktsumme allein
ergibt weiterhin nie Rot. red_categories: [] stellt das alte Verhalten her.

Begründung für die konservative Schwelle: LLM-Konfidenzen sind nicht
perfekt kalibriert — nur die gravierendsten Fälle dürfen die volle
ROT-Dringlichkeit ("Dienstleister informieren, nichts freigeben") tragen.

Rot fließt über die bestehende _worst_level-Verdrahtung automatisch ins
Gesamt-Level + Exit-Code 2; gilt auch für Bildfunde (OCR).

Tests: 237 grün (+7 Rot-Gate, bestehender Cap-Test auf Punktsumme-Logik
umgestellt). Config + Template + README + Bedienungsanleitung aktualisiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 01:16:23 +02:00
d06e3d3dfd feat: KI-Absicherung gegen Falsch-Negative bei Dienstausfall
Bisher: Konnte die KI kein Verdikt liefern (alle Modellstufen scheitern),
ging der Inhalt still als grün durch — für ein Sicherheitswerkzeug ein
Falsch-Negativ-Risiko ("konnte nicht prüfen" ≠ "sauber").

Zwei Maßnahmen:
1. Retry: _classify wiederholt die ganze Modell-Kette bei Komplettausfall
   bis max_retries (Default 1) mit Backoff — fängt transiente Aussetzer ab.
2. Tracking: nicht prüfbare Inhalte landen in ai_result["unchecked"] (statt
   stillem skip) und werden sichtbar in Terminal, Report (Markdown), diff-only
   und E-Mail — jeweils mit URL. score_ai_findings nimmt sie als Grund auf;
   mit unchecked_level="yellow" heben sie das Level auf mindestens Gelb an
   (Default "warn" = nur Hinweis, Ampel unberührt).

Config: max_retries, retry_backoff_seconds, unchecked_level (ai_analysis).
Tests: 230 grün (+ Retry-Recovery, unchecked-Tracking, unchecked_level).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:50:36 +02:00
cae3dbb985 feat: KI-gestützte Inhaltsanalyse via OpenRouter (hash-gegated)
Optionale semantische Prüfung von Text und Bildern (inkl. OCR) auf
problematische Inhalte ohne Link-Signal: Pornografie, Propaganda,
diffamierende/strafbare Texte, versteckter Spam, themenfremde Werbung,
widersprüchliche Aussagen. Bewertet die thematische Passung zum
deklarierten site_context — eingestreute Heimat-Begriffe täuschen die
Erkennung nicht.

Kern:
- scanner/ai_analyzer.py: run_ai_analysis + score_ai_findings.
  Hash-Gate über data/ai_ledger.json → unveränderte Inhalte = Cache-
  Treffer = kein API-Call. Nur neue/geänderte Inhalte kosten etwas.
- Modell-Kette mit zweifacher Eskalation (Stufe 1+2 free, Stufe 3
  günstig bezahlt); eskaliert bei Fehler ODER Timeout (attempt_timeout).
  Erfolgreiches Modell wird im Ledger vermerkt.
- KI-Funde sind auf GELB gedeckelt — ROT bleibt harten Integritäts-
  Signalen vorbehalten. Graceful degradation: ohne Key/bei Fehler wird
  übersprungen, Scan läuft unverändert weiter.

Integration:
- baseline.py: load/save_ai_ledger, dismiss_ai_entries.
- config.py: ai_analysis-Block + ai_* Scoring-Schlüssel.
- __main__.py: Einhängung in cmd_scan/cmd_check, ai-dismiss-Subcommand,
  approve quittiert zugehörige Funde, status-Anzeige, diff-only + report.
- alerter.py + __main__.py: beanstandete Dateien erscheinen mit URL,
  Begründung und Quittier-Fingerprint in E-Mail UND Markdown-Report.
- plain.py: laienverständliche KI-Sätze.

API-Key nur aus Umgebungsvariable (OPENROUTER_API_KEY). Audio/Video als
abschaltbare Hooks vorbereitet (default aus).

Modelle live gegen OpenRouter verifiziert; Demo auf bredelar.info zeigte
korrekte Erkennung (echter Inhalt clean, eingeschleuster Casino-Spam mit
Heimat-Begriffen als hidden_spam erkannt).

Tests: 227 grün (+26 für ai_analyzer, +1 für E-Mail-KI-Abschnitt).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:04:33 +02:00