"""Angriffsfaelle fuer rueckweg_aapl.py auf einem Wegwerf-Git-Repo. Koordinator-Werkzeug, nicht fuers Repo. Jeder Fall einzeln, zuerst die Grundlinie; ohne WSL (--ohne-wsl, Runnerzustand vorgegeben), ohne Meldung. Aufruf unter Windows: python rueckweg_aapl_angriffe.py Exit 0, wenn jeder Fall wie erwartet ausgeht. """ import subprocess import sys import tempfile from pathlib import Path HIER = Path(__file__).resolve().parent sys.path.insert(0, str(HIER)) import rueckweg_aapl as rw # noqa: E402 # Abdichtung (Pruefung DH-Nachtrag, 2026-09-26): Die Faelle laufen mit --ohne-wsl. Bricht ein Mutant # diesen Schalter, riefe melde() sonst den echten WSL-Teil mit --meldung, also ntfy. rueckweg_aapl # holt WSL und WSL_SKRIPT als Wert aus abendkontrolle; deshalb werden sie hier im Modul ersetzt. rw.WSL = str(Path(tempfile.gettempdir()) / "rueckweg-angriffe-kein-wsl" / "wsl.exe") rw.WSL_SKRIPT = "/nicht-vorhanden/abendkontrolle_wsl.py" ZEHN = '[agent]\nquelle = "folge"\ninstrumente = ["AAPL.XNAS", "MSFT.XNAS"]\n' AAPL = '[agent]\nquelle = "register"\ninstrument = "AAPL.XNAS"\n' abweichungen: list[str] = [] def repo(tmp: Path, paper: str | None = ZEHN, aapl: str | None = AAPL) -> Path: projekt = tmp / "projekt" (projekt / "config").mkdir(parents=True) if paper is not None: (projekt / "config" / "paper.toml").write_bytes(paper.encode("utf-8")) if aapl is not None: (projekt / "config" / "paper-aapl-register.toml").write_bytes(aapl.encode("utf-8")) (projekt / ".gitignore").write_text("data/\n", encoding="utf-8") for befehl in (["init", "-q", "-b", "master"], ["config", "user.email", "t@example.invalid"], ["config", "user.name", "Test"], ["config", "core.autocrlf", "false"], ["add", "-A"], ["commit", "-q", "-m", "start"]): subprocess.run([rw.GIT, "-C", str(projekt), *befehl], check=True, capture_output=True) (tmp / "Inbox").mkdir() return projekt def fall(name, *, jetzt="2026-09-30T22:50:00", vorbereiten=None, runner="inactive", paper=ZEHN, aapl=AAPL, erwartet_code, getauscht, notiz, marke, commits, grund=None): with tempfile.TemporaryDirectory() as tmp: tmp = Path(tmp) projekt = repo(tmp, paper, aapl) if vorbereiten: vorbereiten(projekt) vorher = subprocess.run([rw.GIT, "-C", str(projekt), "rev-list", "--count", "HEAD"], capture_output=True, text=True).stdout.strip() code = rw.main(["--jetzt", jetzt, "--projekt", str(projekt), "--vault", str(tmp), "--ohne-wsl", "--runner-zustand", runner]) paper_jetzt = (projekt / "config" / "paper.toml").read_text(encoding="utf-8") if (projekt / "config" / "paper.toml").exists() else None notizen = list((tmp / "Inbox").glob("*.md")) text = notizen[0].read_text(encoding="utf-8") if notizen else "" hat_marke = (projekt / "data" / "paper" / "abendkontrollen" / "rueckweg.json").exists() nachher = subprocess.run([rw.GIT, "-C", str(projekt), "rev-list", "--count", "HEAD"], capture_output=True, text=True).stdout.strip() ist = { "code": code, "getauscht": paper_jetzt == AAPL, "notiz": ("nicht ausgeführt" if "nicht ausgeführt" in text else ("ja" if "Rückweg auf AAPL" in text else "nein")), "marke": hat_marke, "commits": int(nachher) - int(vorher), } soll = {"code": erwartet_code, "getauscht": getauscht, "notiz": notiz, "marke": marke, "commits": commits} ok = ist == soll and (grund is None or grund in text) zeile = f"{'OK ' if ok else 'FEHL'} {name}: {ist}" + ("" if ok else f" SOLL {soll}") print(zeile) if not ok: abweichungen.append(zeile) fall("Grundlinie", erwartet_code=0, getauscht=True, notiz="ja", marke=True, commits=1) fall("zu frueh", jetzt="2026-09-30T21:59:00", erwartet_code=0, getauscht=False, notiz="nein", marke=False, commits=0) fall("Ergebnisdatei schon da", vorbereiten=lambda p: ((p / "data" / "paper" / "abendkontrollen").mkdir(parents=True), (p / "data" / "paper" / "abendkontrollen" / "rueckweg.json").write_text("{}")), erwartet_code=0, getauscht=False, notiz="nein", marke=True, commits=0) fall("Runner aktiv", runner="active", erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Runner deactivating", runner="deactivating", erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Runnerzustand unlesbar", runner="", erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Runner failed (steht)", runner="failed", erwartet_code=0, getauscht=True, notiz="ja", marke=True, commits=1) fall("schon AAPL", paper=AAPL, erwartet_code=0, getauscht=True, notiz="ja", marke=True, commits=0) fall("Ordner nicht sauber (fremde Aenderung)", vorbereiten=lambda p: (p / "config" / "risk.toml").write_text("x\n"), erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("paper.toml geaendert, nicht committet", vorbereiten=lambda p: (p / "config" / "paper.toml").write_text(ZEHN + "# neu\n"), erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("paper.toml ohne folge", paper='[agent]\nquelle = "halte"\n', erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Rueckweg-Datei fehlt", aapl=None, erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("zweiter Termin Donnerstag", jetzt="2026-10-01T22:10:00", erwartet_code=0, getauscht=True, notiz="ja", marke=True, commits=1) # Befunde des Pruefers: halb erledigter Tausch, verlorener Abschnitt, falscher Zweig fall("halb getauscht (Datei getauscht, nicht committet)", vorbereiten=lambda p: (p / "config" / "paper.toml").write_bytes(AAPL.encode("utf-8")), erwartet_code=0, getauscht=True, notiz="ja", marke=True, commits=1) AUTO = "\n[auto_fortsetzen]\naktiv = true\n" fall("halb getauscht und fremde Aenderung", vorbereiten=lambda p: ((p / "config" / "paper.toml").write_bytes(AAPL.encode("utf-8")), (p / "config" / "risk.toml").write_text("x\n")), erwartet_code=1, getauscht=True, notiz="nicht ausgeführt", marke=False, commits=0) fall("Abschnitt nur in paper.toml", paper=ZEHN + AUTO, erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Abschnitt in beiden", paper=ZEHN + AUTO, aapl=AAPL + AUTO, erwartet_code=0, getauscht=False, notiz="ja", marke=True, commits=1) AUS = "\n[auto_fortsetzen]\naktiv = false\n" fall("Automatik nur in paper.toml abgeschaltet", paper=ZEHN + AUS, aapl=AAPL + AUTO, erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Abschnitt in paper.toml geloescht, in der Rueckweg-Datei noch da", paper=ZEHN, aapl=AAPL + AUTO, erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0, grund="auto_fortsetzen.aktiv steht nur in der Rueckweg-Datei") fall("anderer Wert in [grenzen]", paper=ZEHN + "\n[grenzen]\nmax_orders = 5\n", aapl=AAPL + "\n[grenzen]\nmax_orders = 10\n", erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) fall("Tagesverlust darf sich unterscheiden", paper=ZEHN + "\n[grenzen]\nmax_tagesverlust_anteil = 0.01\n", aapl=AAPL + "\n[grenzen]\nmax_tagesverlust_anteil = 0.002\n", erwartet_code=0, getauscht=False, notiz="ja", marke=True, commits=1) fall("anderer Zweig ausgecheckt", vorbereiten=lambda p: subprocess.run([rw.GIT, "-C", str(p), "checkout", "-q", "-b", "z2"], check=True), erwartet_code=1, getauscht=False, notiz="nicht ausgeführt", marke=False, commits=0) print(f"ERGEBNIS: {len(abweichungen)} Abweichung(en)") sys.exit(1 if abweichungen else 0)