"""Vor dem Push: kommt ein Wert aus der Geheimnis- oder Zugangsdatei in den neuen Commits vor? Koordinator-Werkzeug, nicht fuers Repo (Pascal 2026-09-24: Push jederzeit, vorher dieser Scan). Regressionsnachweis vor jedem Scan: SCAN_PROBE= muss einen Treffer melden. Liest die Werte, gibt sie nie aus, nur Schluesselname und Trefferzahl. Laeuft in WSL als claude. Aufruf: python geheimnis_scan.py [ ...] """ import subprocess import sys import tomllib from pathlib import Path GEHEIM = Path("/home/claude/.config/trading-plattform/secrets.toml") repo = Path(sys.argv[1]) von = sys.argv[2] ziele = sys.argv[3:] def blaetter(tabelle, pfad=""): for schluessel, wert in tabelle.items(): name = f"{pfad}.{schluessel}" if pfad else schluessel if isinstance(wert, dict): yield from blaetter(wert, name) elif isinstance(wert, str): yield name, wert werte = [] for datei in (GEHEIM, repo / "config" / "zugang.toml"): if not datei.exists(): print(f"BEFUND: {datei.name} fehlt, Scan ohne diese Werte") continue with datei.open("rb") as f: daten = tomllib.load(f) for name, wert in blaetter(daten): # Kurze Werte (true/false, Hostnamen wie localhost, Modellnamen) treffen Prosa. if len(wert) >= 12: werte.append((f"{datei.name}:{name}", wert)) schluessel_json = repo / "config" / "zugang-schluessel.json" if schluessel_json.exists(): import json for i, eintrag in enumerate(json.loads(schluessel_json.read_text(encoding="utf-8")) or []): if isinstance(eintrag, dict): for k, v in eintrag.items(): if isinstance(v, str) and len(v) >= 12: werte.append((f"zugang-schluessel.json:{i}.{k}", v)) # Seit 2026-09-24 (Paket IB): die IBKR-Zugangsdateien. Die Kontonummer hat 9 Zeichen, deshalb # hier ab 6 statt ab 12; diese drei Werte stehen in keiner Prosa. IBKR = Path("/home/claude/.config/trading-plattform/ibkr") for name in ("paper_benutzer", "paper_passwort", "paper_konto"): datei = IBKR / name if datei.exists(): wert = datei.read_text(encoding="utf-8").strip() if len(wert) >= 6: werte.append((f"ibkr:{name}", wert)) else: print(f"BEFUND: ibkr/{name} fehlt, Scan ohne diesen Wert") import os if os.environ.get("SCAN_PROBE"): # Regressionsnachweis: ein bekannter Text aus dem Verlauf muss als Treffer erscheinen. werte.append(("probe", os.environ["SCAN_PROBE"])) print(f"geprueft: {len(werte)} Werte ab 12 Zeichen") befunde = 0 for ziel in ziele: text = subprocess.run( ["git", "-c", "safe.directory=*", "-C", str(repo), "log", "-p", "--all-match", f"{von}..{ziel}"], capture_output=True, text=True, encoding="utf-8", errors="replace", ).stdout print(f"{von}..{ziel}: {len(text)} Zeichen Verlauf") for name, wert in werte: n = text.count(wert) if n: befunde += 1 print(f" TREFFER {name}: {n}") verfolgt = subprocess.run( ["git", "-c", "safe.directory=*", "-C", str(repo), "ls-tree", "-r", "--name-only", ziel], capture_output=True, text=True, ).stdout.splitlines() for gesperrt in ("config/secrets.toml", "config/zugang.toml", "config/zugang-schluessel.json"): if gesperrt in verfolgt: befunde += 1 print(f" TREFFER verfolgt: {gesperrt}") print(f"ERGEBNIS: {befunde} Treffer") sys.exit(1 if befunde else 0)