"""Probe-Backend mit Anmeldung: die echte App mit Attrappe, Wegwerf-Register und Wegwerf-Zugang. Koordinator-Werkzeug zu Teil 10, nicht fuers Repo. Kein Broker-Aufruf, kein Ereignis im echten Register, keine echte Zugangsdatei. Der Wegwerf-Zugang traegt ein bekanntes Passwort und das Beispielgeheimnis der TOTP-Literatur; beides steht in zugang.json im Ausgabeordner, damit angriffe.py und der Browser-Lauf sich anmelden koennen. Aufruf aus dem Projektordner (oder einer Kopie davon): python start_probe_zugang.py [mit-paperstatus] [zwei-benutzer] Mit zwei-benutzer kommt ein zweiter Wegwerf-Benutzer "zweiter" dazu (eigenes TOTP-Geheimnis, in zugang2.json), damit sich pruefen laesst, dass das Entfernen des einen den anderen nicht trifft. """ import dataclasses import json import os import sys from datetime import UTC from datetime import datetime from pathlib import Path import uvicorn from trading.broker.attrappe import BrokerAttrappe from trading.dashboard.app import erzeuge_app from trading.dashboard.config import lade_dashboard_config from trading.dashboard.zugang import Benutzer from trading.dashboard.zugang import schreibe_benutzer from trading.dashboard.zugang import setze_passwort from trading.killswitch.killswitch import lade_killswitch_config from trading.registry.registry import Registry BENUTZER = "probe" PASSWORT = "nur-fuer-die-probe-2026" GEHEIMNIS = "JBSWY3DPEHPK3PXP" port = int(sys.argv[1]) ordner = Path(sys.argv[2]) # Befund der Sicherheitspruefung vom 2026-09-20: erzeuge_app startete (bis Paket S5) immer den echten # Stille-Waechter und las dafuer config/paper.toml und config/secrets.toml aus dem Arbeitsordner. Eine # Probe-Instanz im echten Projektordner haette nach 180 s auf das Telefon geklingelt. Deshalb nur aus # einer Kopie oder einem Arbeitsbaum ohne Geheimnisdatei. # Seit Paket E2 (2026-09-22) findet die Plattform die Geheimnisdatei auch ueber TRADING_GEHEIMNISSE # bzw. CREDENTIALS_DIRECTORY -- nach dem Umzug steht die erste in jeder Login-Shell, und die Wache # unten liefe ins Leere. Die Probe nimmt beide aus ihrer Umgebung, bevor die App gebaut wird # (Befund der Abschlusspruefung E2). for name in ("TRADING_GEHEIMNISSE", "CREDENTIALS_DIRECTORY"): os.environ.pop(name, None) if Path("config/secrets.toml").exists(): sys.exit( "Abbruch: Im Arbeitsordner liegt config/secrets.toml. Die Probe startet nur aus einer Kopie " "ohne Geheimnisdatei, sonst spraeche sie mit dem echten ntfy und dem echten Home Assistant." ) ordner.mkdir(parents=True, exist_ok=True) mit_status = "mit-paperstatus" in sys.argv[3:] zwei_benutzer = "zwei-benutzer" in sys.argv[3:] ZWEITER = "zweiter" GEHEIMNIS_ZWEITER = "KRUGS4ZANFZSAYJA" zugang_datei = ordner / "zugang.toml" benutzer = {BENUTZER: Benutzer(name=BENUTZER, passwort=setze_passwort(PASSWORT), totp_geheimnis=GEHEIMNIS)} if zwei_benutzer: benutzer[ZWEITER] = Benutzer(name=ZWEITER, passwort=setze_passwort(PASSWORT), totp_geheimnis=GEHEIMNIS_ZWEITER) (ordner / "zugang2.json").write_text( json.dumps({"benutzer": ZWEITER, "passwort": PASSWORT, "geheimnis": GEHEIMNIS_ZWEITER}), encoding="utf-8", ) schreibe_benutzer(zugang_datei, benutzer) (ordner / "zugang.json").write_text( json.dumps({"benutzer": BENUTZER, "passwort": PASSWORT, "geheimnis": GEHEIMNIS}), encoding="utf-8", ) paper_ordner = ordner / "paper" paper_ordner.mkdir(exist_ok=True) status_datei = ordner / "status.json" if mit_status: protokoll = paper_ordner / "2026-09-18T131502-paper.jsonl" zeilen = [ {"art": "kopf", "modus": "paper"}, {"art": "takt", "schritt": 1, "phase": "handelt", "position": 10, "zielposition": 10}, ] protokoll.write_text("\n".join(json.dumps(z) for z in zeilen) + "\n", encoding="utf-8") status_datei.write_text( json.dumps( { "zeit": datetime.now(UTC).isoformat(), "modus": "paper", "phase": "handelt", "agent": { "quelle": "register", "name": "aapl-minute-ppo", "version": "v20260907-074410", "status": "paper", }, "instrument": "AAPL.XNAS", "killswitch": "aktiv", "position": 10, "zielposition": 10, "letzte_aktion": {"zeit": datetime.now(UTC).isoformat(), "aktion": 3, "stufe": 1}, "letzte_kerze": datetime.now(UTC).replace(second=0, microsecond=0).isoformat(), "orders": 1, "kontowert": 100012.5, "startkapital": 100000.0, "hinweis": None, "protokoll": str(protokoll), "pid": 1, } ), encoding="utf-8", ) config = dataclasses.replace( lade_dashboard_config("config/dashboard.toml"), port=port, broker_wahl="attrappe", sendeintervall_s=2.0, erlaubte_hosts=(f"127.0.0.1:{port}", f"localhost:{port}"), anmeldung_pflicht=True, mfa_pflicht=True, zugang_datei=str(zugang_datei), zugang_protokoll=str(ordner / "anmeldungen.jsonl"), paper_status_datei=str(status_datei), paper_protokoll_ordner=str(paper_ordner), ) app = erzeuge_app( broker=BrokerAttrappe(), registry=Registry(db_pfad=ordner / "registry.db", artefakt_wurzel=ordner / "artifacts"), config=config, killswitch_config=lade_killswitch_config("config/killswitch.toml"), dist=Path("dashboard/dist"), ) print(f"Probe-Backend mit Anmeldung auf 127.0.0.1:{port}, Ablage {ordner}", flush=True) uvicorn.run(app, host="127.0.0.1", port=port, log_level="warning", server_header=False, proxy_headers=False)