# ============================================================
# Integrity Scanner — Konfigurationsvorlage
# ============================================================
# Verwendung:
#   1. Dieses Verzeichnis kopieren:
#        cp -r meine-seite.de neue-domain.de
#   2. In neue-domain.de/config.yaml alle Stellen mit
#      "meine-seite.de" durch die echte Domain ersetzen.
#   3. Verzeichnis in .gitignore eintragen (data/reports/logs).
#   4. Erste Einrichtung:
#        python -m scanner --config neue-domain.de/config.yaml init
# ============================================================

# --- Ziel-Website ---
target: "https://meine-seite.de"

# User-Agent, mit dem der Scanner sich bei der Website meldet.
# Bitte nicht auf einen Browser-Agent ändern — der Scanner soll erkennbar sein.
user_agent: "integrity-scanner/1.0 (+security-monitoring)"

# Timeout in Sekunden pro HTTP-Anfrage
request_timeout: 20

# --- Verzeichnisse (müssen absolut angegeben werden) ---
# Pfad zum Projektverzeichnis anpassen!
data_dir:    "/home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/meine-seite.de/data"
reports_dir: "/home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/meine-seite.de/reports"
logs_dir:    "/home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/meine-seite.de/logs"
config_dir:  "/home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/meine-seite.de/config"

# --- Crawl-Einstellungen ---
crawl:
  # Maximale Anzahl Seiten pro Crawl (Schutz vor endlosen Websites)
  max_pages: 200

  # Wartezeit zwischen zwei Seitenanfragen in Sekunden (Server schonen)
  delay_seconds: 1.0

  respect_robots_txt: false

  # Sitemap lesen, um nicht verlinkte Seiten (Orphan Pages) zu entdecken.
  # Der Scanner liest sitemap.xml (bzw. robots.txt → Sitemap:) und fügt alle
  # dort aufgeführten URLs in die Crawl-Queue ein.
  sitemap: true

  # Pfade, die vom Scan ausgeschlossen werden sollen.
  # Nützlich für Bereiche mit gewollt häufig wechselnden Inhalten,
  # z. B. RSS-Feeds, News-Archive, Nutzerprofile.
  # Beispiel: ["/rss/", "/feed/", "/news/archiv/", "/user/"]
  exclude_paths: []

  # Dateiendungen, die nicht gecrawlt werden (Binärdateien)
  skip_extensions:
    - ".jpg"
    - ".jpeg"
    - ".png"
    - ".gif"
    - ".webp"
    - ".svg"
    - ".ico"
    - ".pdf"
    - ".zip"
    - ".woff"
    - ".woff2"
    - ".ttf"
    - ".otf"
    - ".eot"
    - ".mp4"
    - ".mp3"
    - ".webm"
    - ".avi"
    - ".mov"

# --- Bewertungsgewichte ---
# Jedes Ereignis erhöht den Score. Ab 20 = gelb, ab 60 = rot.
# Die Werte können hier für diese Website angepasst werden.
scoring:
  new_external_domain: 50        # Neuer Verweis auf fremde Domain
  new_internal_url: 30           # Neue interne Seite aufgetaucht
  missing_internal_url: 20       # Bekannte Seite verschwunden
  hidden_content: 40             # Unsichtbarer Text/Link (display:none)
  unexpected_canonical: 35       # Canonical-Tag geändert
  meta_refresh: 40               # Automatische Weiterleitung eingebaut
  unexpected_jsonld: 35          # Unbekannter JSON-LD-Typ
  large_text_addition: 20        # Großer neuer Textblock (>200 Zeichen)
  new_inline_script_suspicious: 30  # Verdächtiges inline JavaScript
  comment_links: 25              # Link in HTML-Kommentar versteckt
  new_broken_link: 20            # Neuer kaputt interner Link
  suspicious_filename: 60        # Webshell-typischer Dateiname verlinkt
  cloaking_extra_link: 60        # Nur für Google-Bot sichtbarer Link
  cloaking_extra_text: 40        # Nur für Google-Bot sichtbarer Text
  cloaking_vary_ua: 25           # Server sendet verschiedene Inhalte je UA
  changed_script: 40             # JavaScript-Datei verändert
  changed_stylesheet: 30         # CSS-Datei verändert
  changed_asset: 20              # Bild/PDF/sonstige Datei verändert

thresholds:
  yellow: 20    # Ab diesem Score: Warnung (gelb) — Bitte prüfen
  red: 60       # Ab diesem Score: Alarm (rot) — Sofort prüfen
  large_text_block_chars: 200

# --- Wöchentliche Zusatzprüfungen ---
# Laufen automatisch beim täglichen `scan` mit — kein separater Aufruf nötig.
periodic_checks:
  enabled: true
  interval_days: 7
  cloak_check: true    # Prüft ob Google andere Inhalte sieht als Besucher
  ext_links: true      # Prüft ob externe Links noch erreichbar sind
  assets: true         # Prüft ob CSS/JS/Bilder sich verändert haben

# --- E-Mail-Benachrichtigung ---
# Passwort NIEMALS hier eintragen — nur als Umgebungsvariable:
#   export SCANNER_SMTP_PASSWORD="geheimesPasswort"
alerting:
  min_level: "yellow"   # "yellow" = bei Gelb und Rot mailen; "red" = nur bei Rot
  email:
    enabled: false      # Auf true setzen wenn SMTP konfiguriert
    smtp_host: "mail.meine-seite.de"
    smtp_port: 587
    smtp_tls: true
    smtp_user: "scanner@meine-seite.de"
    smtp_password_env: "SCANNER_SMTP_PASSWORD"
    from: "scanner@meine-seite.de"
    to:
      - "admin@meine-seite.de"
  webhook:
    enabled: false
    url: ""   # z.B. Slack-Webhook oder Telegram-Bot-URL

# --- KI-gestützte Inhaltsanalyse (optional, OpenRouter) ---
# Prüft Text und Bilder semantisch auf problematische Inhalte (Pornografie,
# Propaganda, Spam, themenfremde Werbung, strafbare/widersprüchliche Aussagen).
# Kostengate: nur NEUE/GEÄNDERTE Inhalte lösen einen API-Call aus (Hash-Cache).
# KI-Funde sind auf GELB gedeckelt. API-Key NUR als Umgebungsvariable setzen:
#   export OPENROUTER_API_KEY="sk-or-..."
ai_analysis:
  enabled: false
  api_key_env: "OPENROUTER_API_KEY"
  # Themenbeschreibung der Website — die KI bewertet die Passung dazu, nicht
  # einzelne Schlüsselwörter. Bitte ausfüllen, wenn enabled: true.
  site_context: ""
  ai_confidence_min: 0.7
  # KI-Funde sind auf Gelb gedeckelt — AUSSER diese schwerwiegenden Kategorien lösen
  # bei hoher Schwere + hoher Konfidenz ROT aus. Leere Liste [] = immer max. Gelb.
  red_categories: ["pornography", "defamation_illegal"]
  red_min_severity: "high"
  red_min_confidence: 0.9
  attempt_timeout: 20        # HARTES Wanduhr-Limit je Modell-Versuch (Sek.) → Eskalation
  max_retries: 1             # Wiederholungen der ganzen Modell-Kette bei Komplettausfall
  retry_backoff_seconds: 2.0
  # Parallelität: gleichzeitige API-Requests. I/O-gebunden → an die Rate-Limits der API
  # gebunden, NICHT an CPU-Kerne (vhost mit 4 Kernen wie 24-Kern-Rechner gleich steuerbar).
  max_concurrency: 8
  # Adaptiver Router: ausgefallene/rate-limited Modelle nach so vielen Fehlern für die
  # Cooldown-Dauer überspringen; das schnellste gesunde Modell zuerst.
  breaker_failure_threshold: 2
  breaker_cooldown_seconds: 120
  refresh_models: true       # tote Modell-Slugs failsafe über OpenRouter /models aussortieren
  # Verhalten, wenn Inhalte trotz Retry NICHT geprüft werden konnten (KI nicht erreichbar):
  #   "warn"   = sichtbarer Hinweis (Level bleibt unberührt)
  #   "yellow" = zusätzlich Gesamt-Level auf mindestens Gelb anheben (für hohe Sicherheit)
  unchecked_level: "warn"
  # Modell-Kette mit zweifacher Eskalation: Stufe 1+2 free, Stufe 3 günstig bezahlt.
  # Schlägt ein Modell fehl oder antwortet zu langsam, wird zur nächsten Stufe eskaliert.
  text:
    enabled: true
    models:
      - "qwen/qwen3-next-80b-a3b-instruct:free"   # Stufe 1: free
      - "meta-llama/llama-3.3-70b-instruct:free"  # Stufe 2: free
      - "google/gemini-2.5-flash-lite"            # Stufe 3: günstig bezahlt, zuverlässig
    min_chars: 200
    # Drossel NUR für den Altbestand; 0 = unbegrenzt (volle Abdeckung im ersten Scan).
    # Geänderte/neue Seiten werden IMMER geprüft. Positiver Wert nur für sehr große Sites.
    max_pages_per_scan: 0
  image:
    enabled: true
    models:
      - "google/gemma-4-31b-it:free"              # Stufe 1: free, multimodal + OCR
      - "nvidia/nemotron-nano-12b-v2-vl:free"     # Stufe 2: free, Vision
      - "google/gemini-2.5-flash-lite"            # Stufe 3: günstig bezahlt, Vision
    # Drossel NUR für den Bild-Altbestand; 0 = unbegrenzt. Geänderte/neue/geflaggte
    # Bilder werden IMMER geprüft. Positiver Wert nur für sehr große Bildbestände.
    max_images_per_scan: 0
  # Audio/Video: vorbereitet, default aus (Medien auf statischen Seiten selten).
  audio:
    enabled: false
    models: ["google/gemini-2.5-flash"]
  video:
    enabled: false
    models: ["google/gemini-2.5-flash"]

# --- Normalisierung ---
# Elemente, die vor dem Vergleich aus dem HTML entfernt werden
# (z. B. dynamische Datums-/Zeitanzeigen die sich täglich ändern).
normalization:
  strip_html_comments: true
  collapse_whitespace: true
  ignore_selectors:
    # - "#last-modified"    # Element mit dieser ID ignorieren
    # - ".timestamp"        # Alle Elemente mit dieser CSS-Klasse ignorieren
  ignore_patterns:
    # - '\d{1,2}\.\d{1,2}\.\d{4}'   # Datumsangaben im Text ignorieren
    # - 'Stand:\s+\S+'

# --- Erlaubte JSON-LD-Typen ---
# Alles, was hier nicht steht und auf der Website auftaucht, löst Alarm aus.
allowed_jsonld_types:
  - "Organization"
  - "WebSite"
  - "WebPage"
  - "Article"
  - "BreadcrumbList"
  - "ItemList"
  - "LocalBusiness"
  - "Place"
  - "Person"
  - "Event"
  - "FAQPage"
  - "Question"
  - "Answer"
  - "ImageObject"
  - "SiteLinksSearchBox"
  - "ContactPage"
  - "AboutPage"

# --- Erwartete Security-Header ---
# Fehlen diese Header, erscheint ein Hinweis im Report (kein Score-Einfluss).
security_headers:
  - "Content-Security-Policy"
  - "Strict-Transport-Security"
  - "X-Content-Type-Options"
  - "Referrer-Policy"
