integrity_scanner_fuer_stat.../scanner/config.py

202 lines
8 KiB
Python
Raw Normal View History

"""Config loading with deep-merge against defaults."""
from pathlib import Path
import yaml
DEFAULT_CONFIG: dict = {
"target": "https://bredelar.info",
"user_agent": "integrity-scanner/1.0 (+security-monitoring)",
"request_timeout": 20,
"data_dir": "data",
"reports_dir": "reports",
"logs_dir": "logs",
"config_dir": "config",
"crawl": {
"max_pages": 200,
"delay_seconds": 1.0,
"respect_robots_txt": False,
"skip_extensions": [
".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico",
".pdf", ".zip", ".woff", ".woff2", ".ttf", ".otf", ".eot",
".mp4", ".mp3", ".webm", ".avi", ".mov",
],
"exclude_paths": [],
"include_paths": [],
"sitemap": True,
},
"scoring": {
"new_external_domain": 50,
"new_internal_url": 30,
"missing_internal_url": 20,
"hidden_content": 40,
"unexpected_canonical": 35,
"meta_refresh": 40,
"unexpected_jsonld": 35,
"large_text_addition": 20,
"new_inline_script_suspicious": 30,
"comment_links": 25,
"new_broken_link": 20,
"suspicious_filename": 60,
"cloaking_extra_link": 60,
"cloaking_extra_text": 40,
"cloaking_vary_ua": 25,
"changed_script": 40,
"changed_stylesheet": 30,
"changed_asset": 20,
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
# KI-Inhaltsanalyse (additiv; Gesamt-Level aus KI ist auf gelb gedeckelt)
"ai_pornography": 50,
"ai_defamation_illegal": 50,
"ai_propaganda": 40,
"ai_hidden_spam": 40,
"ai_off_topic_commercial": 30,
"ai_contradiction": 20,
"ai_suspicious_image": 40,
},
"thresholds": {
"yellow": 20,
"red": 60,
"large_text_block_chars": 200,
},
"periodic_checks": {
"enabled": True,
"interval_days": 7,
"cloak_check": True,
"ext_links": True,
"assets": True,
},
"alerting": {
"min_level": "yellow",
"email": {
"enabled": False,
"smtp_host": "linix.de",
"smtp_port": 587,
"smtp_tls": True,
"smtp_user": "eliza",
"smtp_password_env": "SCANNER_SMTP_PASSWORD",
"from": "eliza@linix.de",
"to": ["dieter.schlueter@linix.de"],
},
"webhook": {
"enabled": False,
"url": "",
},
},
# KI-gestützte semantische Inhaltsanalyse (OpenRouter, primär).
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
# Hash-gegated: nur neue/geänderte Inhalte lösen einen API-Call aus — siehe
# ai_ledger.json. Der API-Key kommt NUR aus der Umgebungsvariable (nie in config.yaml).
# Lokale Server (localhost:8001, :8002) dienen nur als Dev-Fallback.
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
"ai_analysis": {
"enabled": False,
"api_key_env": "OPENROUTER_API_KEY",
"site_context": "", # Themenbeschreibung der Website (Pflicht wenn enabled)
"ai_confidence_min": 0.7, # Mindest-Konfidenz, damit ein Fund gewertet wird
# 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,
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
"request_timeout": 60, # Ceiling (auch für Asset-Fetch der Bilder)
"attempt_timeout": 20, # HARTES Wanduhr-Limit je Modell-Versuch → 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 wie 24-Kern-Maschine gleich steuerbar).
"max_concurrency": 8,
# Adaptiver Router: ausgefallene/rate-limited Modelle werden nach so vielen Fehlern
# für die Cooldown-Dauer übersprungen; das schnellste gesunde Modell zuerst.
"breaker_failure_threshold": 2,
"breaker_cooldown_seconds": 120,
"refresh_models": True, # tote Slugs failsafe über OpenRouter /models aussortieren
# Verhalten, wenn Inhalte trotz Retry NICHT geprüft werden konnten (KI nicht erreichbar):
# "warn" = sichtbarer Hinweis in Report/Terminal/E-Mail (Level bleibt unberührt)
# "yellow" = zusätzlich Gesamt-Level auf mindestens Gelb anheben
# Für ein Sicherheitswerkzeug gilt: "konnte nicht prüfen" ≠ "sauber".
"unchecked_level": "warn",
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
# 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, # nur Seitentexte ab dieser Größe prüfen
# Drossel NUR für den historischen Bestand; 0 = unbegrenzt (volle Abdeckung im
# ersten Scan). Geänderte/neue Seiten werden IMMER geprüft, ungeachtet dieses Werts.
"max_pages_per_scan": 0,
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
},
"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 (volle Abdeckung im ersten
# Scan). Geänderte/neue/geflaggte Bilder werden IMMER geprüft, ungeachtet des Werts.
"max_images_per_scan": 0,
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
},
# Vorbereitet, default aus — Medien sind auf statischen Heimat-Seiten selten.
"audio": {
"enabled": False,
"models": ["google/gemini-2.5-flash"],
"max_files_per_scan": 0, # 0 = unbegrenzt
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
},
"video": {
"enabled": False,
"models": ["google/gemini-2.5-flash"],
"max_files_per_scan": 3,
},
},
"normalization": {
"strip_html_comments": True,
"collapse_whitespace": True,
"ignore_selectors": [],
"ignore_patterns": [],
},
"allowed_jsonld_types": [
"Organization", "WebSite", "WebPage", "Article", "BreadcrumbList",
"ItemList", "LocalBusiness", "Place", "Person", "Event",
"FAQPage", "Question", "Answer", "ImageObject", "SiteLinksSearchBox",
"ContactPage", "AboutPage",
],
"security_headers": [
"Content-Security-Policy",
"Strict-Transport-Security",
"X-Content-Type-Options",
"Referrer-Policy",
],
}
def load_config(config_file: str = "config.yaml") -> dict:
"""Load config from YAML, deep-merged on top of defaults."""
cfg = _deep_copy(DEFAULT_CONFIG)
p = Path(config_file)
if p.exists():
with p.open(encoding="utf-8") as f:
user_cfg = yaml.safe_load(f) or {}
_deep_update(cfg, user_cfg)
return cfg
def resolve_paths(cfg: dict, base_dir: Path) -> dict:
"""Resolve relative paths in config against base_dir."""
for key in ("data_dir", "reports_dir", "logs_dir", "config_dir"):
cfg[key] = str(base_dir / cfg[key])
return cfg
def _deep_copy(d: dict) -> dict:
import copy
return copy.deepcopy(d)
def _deep_update(base: dict, override: dict) -> None:
for k, v in override.items():
if isinstance(v, dict) and isinstance(base.get(k), dict):
_deep_update(base[k], v)
elif v is None and isinstance(base.get(k), list):
pass # YAML null on a list field = "not set" → keep default
else:
base[k] = v