Ziel: Bot (clawbot) und Worker (clawbot-worker) von der Legacy-Rolle tradingbot_gui (SUPERUSER) auf die Runtime-Rolle tradingbot_gui_app umstellen. Defense-Effekt: bei Bot/Worker-Compromise (Market-data-RCE, dependency-injection, etc.) kann der Angreifer maximal Daten manipulieren, nicht Schema zerstoeren oder Rollen escalieren — analog zu SEC-1c-3a aber für die zwei Bot-Container.
Vorbedingung: SEC-1c-3a closed (GUI bereits umgestellt, 3-Rollen-Modell live).
Config-Source-of-Truth: Beide Container lesen ihre DB-Credentials aus der compose-env-Section in /projekte/Steve-TradingBot/docker-compose.yml. Die Werte werden via ${GUI_DB_*:-default}-Substitution aus /projekte/Steve-TradingBot/.env gefüllt. Aktuell sind dort nur GUI_DB_DSN + GUI_DB_CONNECT_TIMEOUT gesetzt; GUI_DB_USER/PASSWORD/HOST/PORT/NAME fallen auf compose-Defaults zurück (= tradingbot_gui:tradingbot_gui).
Cutover: Root-.env updaten + docker compose up -d --force-recreate clawbot clawbot-worker. Bot/Worker stop+recreate ~30s pro Container; Mainnet-Block + TESTNET-Sicherung unberührt; managed_proposals = 0 (kein In-Flight-State der gefährdet wäre).
| Item | Wert | Status |
|---|---|---|
| master HEAD | d351a3a | ✅ |
| git status | clean (kein uncommitted-Repo-Touch) | ✅ |
| Bot in-container PID | 363 (python3 main.py --paper) | ✅ |
| Worker in-container PID | 1 (python3 -m trading.command_worker) | ✅ |
| Worker heartbeat (command_audit_log) | command-bus aktiv (FOR UPDATE SKIP LOCKED Pattern in code, kontinuierliche Polls) | ✅ |
| BINANCE_TESTNET | true (verifiziert via Bot in-container .env) | ✅ |
| cmd 13 status | cancelled | ✅ |
| managed_proposals rows | 0 | ✅ |
| managed_assets_history rows | 0 | ✅ |
| GUI current_user | tradingbot_gui_app (SEC-1c-3a closed) | ✅ |
| Bot/Worker DB-Connection (compose-env) | tradingbot_gui (SUPERUSER) — muss umgestellt werden | 🔴 SEC-1c-3b target |
| decision_logs Schreibrate (letzte 1h) | 474 INSERTs — Bot+Worker schreiben aktiv | ✅ (Heartbeat-Indikator) |
| bot_statuses max_id | 9751 | ✅ |
| Tracebacks in Bot-Log (letzte 50 Zeilen) | 0 | ✅ |
| SECRET-READ-ONCE-Files | /root/.secrets/sec-1c-3a-app.SECRET-READ-ONCE (mode 600, 33 bytes) + migrator-equiv. Operator-Aufgabe vor Cutover: lesen + shreddern (NICHT shreddern WAEHREND Cutover, Bot/Worker brauchen App-PW noch) | ⏳ pending |
| Service | relevante Zeilen |
|---|---|
clawbot (Line 32-33) | nur GUI_DB_DSN=${GUI_DB_DSN:-} + GUI_DB_CONNECT_TIMEOUT=${GUI_DB_CONNECT_TIMEOUT:-2}. Bot liest DSN-URL-Form. |
clawbot-worker (Line 123-129) | vollständig: GUI_DB_DSN + HOST + PORT + NAME + USER + PASSWORD + CONNECT_TIMEOUT. Worker kann sowohl DSN als auch einzeln lesen. |
.env| Variable | aktueller Stand in /projekte/Steve-TradingBot/.env | Soll nach 1c-3b |
|---|---|---|
GUI_DB_DSN | vorhanden, mit altem User tradingbot_gui | aktualisiert auf postgres://tradingbot_gui_app:<app-PW>@steve-tradingbot-gui-db:5432/tradingbot_gui |
GUI_DB_USER | nicht gesetzt (compose-Default tradingbot_gui) | tradingbot_gui_app |
GUI_DB_PASSWORD | nicht gesetzt (compose-Default tradingbot_gui) | <app-PW> aus SECRET-READ-ONCE (gelesen, NICHT geechoed; via heredoc + sed-with-temp-file-pattern) |
GUI_DB_HOST/PORT/NAME/CONNECT_TIMEOUT | nicht gesetzt — compose-Defaults gui-db / 5432 / tradingbot_gui / 2 | unverändert (compose-Defaults sind korrekt) |
trading/db_emitter.py Zeile 185 verwendet INSERT INTO {table} (cols) VALUES (placeholders) — psycopg2 mit Standard-DSN-URL aus GUI_DB_DSN. KEIN CREATE/ALTER/DROP/TRUNCATE im Source.trading/command_worker.py ist Command-Bus-Poller. Verwendet FOR UPDATE SKIP LOCKED auf commands-Table und UPDATE commands SET .... Zwei separate Connect-Bibliotheken (sqlalchemy via DSN ODER psycopg2 direkt mit User/PW — je nach Code-Pfad). Alles im DML-Bereich, kein DDL.→ Beide Workloads sind DML-only und kompatibel mit tradingbot_gui_app-Privs.
| # | Step | Risiko | Zeit |
|---|---|---|---|
| 3b.0 | Pre-flight Snapshot (PIDs, decision_logs-Count, command_audit-Latest, GUI current_user, managed_proposals=0, cmd 13 cancelled, BINANCE_TESTNET=true). Operator-Aufgabe: SECRET-READ-ONCE shred KOMMT NACH 1c-3b (Bot/Worker brauchen PW noch zum Restart) | 0 | 3 min |
| 3b.1 | Backup: /projekte/Steve-TradingBot/.env → /root/sec-1c-3b-backup-<ts>/env.pre mode 600 | 0 | 1 min |
| 3b.2 | Snapshot Bot/Worker container-config (env-keys, mounts, networks) — bestehende compose-config bleibt unverändert; nur env-Substitution aus .env greift | 0 | 1 min |
| 3b.3 | /projekte/Steve-TradingBot/.env updaten: GUI_DB_DSN mit neuem User-PW + GUI_DB_USER=tradingbot_gui_app + GUI_DB_PASSWORD=<app-PW>. PW-Wert via heredoc/sed-with-temp-Pattern, NICHT geechoed. | LOW | 2 min |
| 3b.4 | docker compose config --no-interpolate (oder Filter durch grep -v key|token|password|secret) — Sanity-Check, dass compose die neuen Werte sieht ohne sie zu leaken | 0 | 1 min |
| 3b.5 | Bot-Container recreate: docker compose up -d --force-recreate clawbot — ~10s stop + ~20s recreate. PID wird neu (≠ 363). | HIGH (Restart-Window-Start) | 2 min |
| 3b.6 | Bot Smoke: docker exec clawbot tr "\0" "\n" < /proc/<newPID>/environ | grep GUI_DB_USER → tradingbot_gui_app. Bot-Logs (tail -50 logs/bot_stdout.log) frei von Tracebacks, scan-cycle aktiv | HIGH | 5 min |
| 3b.7 | Worker-Container recreate: docker compose up -d --force-recreate clawbot-worker | HIGH (Restart-Window-2) | 2 min |
| 3b.8 | Worker Smoke: command_worker.pid + heartbeat-write in command_audit_log; SELECT usename FROM pg_stat_activity WHERE application_name LIKE '%worker%' → tradingbot_gui_app | HIGH | 5 min |
| 3b.9 | Permission-Tests Bot/Worker: Bot kann decision_logs INSERT (= aktive Schreibrate >0 in nächsten 5 min) — aber CREATE/DROP/ALTER/TRUNCATE/CREATE-ROLE muss permission-denied geben (Negative-Tests via docker exec clawbot psql ...) | MEDIUM | 5 min |
| 3b.10 | Boundary-Recheck: cmd 13 noch cancelled, managed_proposals=0, BINANCE_TESTNET=true | 0 | 2 min |
| 3b.11 | (BACKLOG-relevant) SELECT key FROM pg_stat_activity WHERE usename='tradingbot_gui' — sollte ab jetzt LEER sein (kein App nutzt SUPERUSER). DBA-Test-Connect via SSH+psql bleibt erlaubt | 0 | 1 min |
| 3b.12 | Closure-Pin + STOP-Report | 0 | 5 min |
Σ SEC-1c-3b: ~35 min, davon ~30s Bot-Container-Recreate + ~30s Worker-Container-Recreate (sequenziell, nicht parallel).
bot_watchdog.sh */5 spawnt Bot-Process nur wenn Container läuft. Während docker compose up -d --force-recreate ist Container kurz down (entrypoint läuft neu); Watchdog feuert nicht in den down-Phasen.FOR UPDATE SKIP LOCKED — multiple parallel Worker safe. Restart ist atomic; aktuelle pending Commands (falls vorhanden) werden vom nächsten Poll re-claimed.# Bot kann decision_logs INSERT:
docker exec clawbot sh -lc 'psql "$GUI_DB_DSN" -c "INSERT INTO decision_logs (decision_id, decided_at, symbol, action) VALUES (\\'sec-1c-3b-canary\\', NOW(), \\'TEST/USDT\\', \\'sec-test\\') RETURNING id;"'
# Dann cleanup:
docker exec clawbot sh -lc 'psql "$GUI_DB_DSN" -c "DELETE FROM decision_logs WHERE decision_id=\\'sec-1c-3b-canary\\';"'
# Worker kann commands UPDATE (DML, kein DDL):
docker exec clawbot-worker sh -lc 'psql "$GUI_DB_DSN" -c "SELECT id, status FROM commands ORDER BY id DESC LIMIT 3;"'
docker exec clawbot-worker sh -lc 'psql "$GUI_DB_DSN" -c "SELECT current_user;"' # → tradingbot_gui_app
docker exec clawbot sh -lc 'psql "$GUI_DB_DSN" -c "CREATE TABLE _bot_leak (id int);"' # → permission denied
docker exec clawbot sh -lc 'psql "$GUI_DB_DSN" -c "DROP TABLE decision_logs;"' # → must be owner
docker exec clawbot sh -lc 'psql "$GUI_DB_DSN" -c "TRUNCATE bot_statuses;"' # → permission denied
docker exec clawbot-worker sh -lc 'psql "$GUI_DB_DSN" -c "CREATE ROLE evil;"' # → permission denied to create role
docker exec clawbot-worker sh -lc 'psql "$GUI_DB_DSN" -c "ALTER SYSTEM SET fsync=off;"' # → permission denied
# Decision-Logs Schreibrate sollte sich fortsetzen:
docker exec steve-tradingbot-gui-db psql -U tradingbot_gui -d tradingbot_gui -tAc "
SELECT 'decision_logs_last_5min='||COUNT(*) FROM decision_logs WHERE decided_at > NOW() - INTERVAL '5 minutes';
SELECT 'pg_stat_app_users='||string_agg(DISTINCT usename, ',') FROM pg_stat_activity WHERE datname='tradingbot_gui';
"
# Erwartet: decision_logs_last_5min > 0 ; usernames enthält tradingbot_gui_app (NICHT mehr tradingbot_gui für App-Connections)
docker compose up nicht (Exit-Code != 0, kein Process auf main.py) → rollback aus BackupFATAL: password authentication failed → .env-Wert falsch, rollback + Re-Try mit verifiziertem PWcommand_worker.pid in /var/log/... → rollbackcommand_audit_log nach Restart → rollbackcancelled zu etwas anderem → Boundary-Verletzungtrue → sofortiger Halt| Failure-Zeitpunkt | Rollback |
|---|---|
| nach 3b.3 (.env-Edit, vor Container-Restart) | cp /root/sec-1c-3b-backup-<ts>/env.pre /projekte/Steve-TradingBot/.env — kein Container-Restart nötig, da compose-env noch alt im laufenden Container |
| nach 3b.5 (Bot recreated, Bot failt) | Restore .env + docker compose up -d --force-recreate clawbot — Bot connectet wieder mit SUPERUSER |
| nach 3b.7 (Worker recreated, Worker failt) | analog — Restore .env + --force-recreate clawbot-worker |
| komplettes Rollback | .env-Restore + 2× --force-recreate — < 5 min, kein Datenverlust (alle Bot/Worker-Writes idempotent) |
| master HEAD | d351a3a unverändert |
| git status | clean |
| Bot in-container PID | 363 unverändert |
| Worker in-container PID | 1 unverändert |
| BINANCE_TESTNET | true |
| managed_proposals / history | 0 / 0 |
| cmd 13 | cancelled |
| GUI current_user | tradingbot_gui_app ✅ |
| Bot/Worker DB-User | tradingbot_gui (SUPERUSER) — geplant zu ändern in 1c-3b |
| Mainnet | 0 |
| Push | 0 (Plan-Review) |
| DB-Migration | 0 (kein Schema-Touch) |
| docker cp | 0 |
| managed_state / runtime_config / baseline-Touch | 0 |
| Secret-Werte im Output | 0 ✅ |
tradingbot_gui_app + tradingbot_gui_migrator mit App-PW + Mig-PW in SECRET-READ-ONCE-Files/projekte/Steve-TradingBot/.env via compose-Substitutiontradingbot_gui_app-PW noch zum Restart. Shredden NACH erfolgreichem Cutoverhttps://gui.gewerbespeicher-rechner.de/admin/login aufrufen und einen Read-Endpoint bestätigenGO SEC-1c-3b atomic 13-Step-Block mit explizitem Restart-Window-Approval. Aufwand ~35 min. Bei jedem Stop-Trigger sofortiger Rollback (< 5 min).
Alternativ: weiter aufsplitten in 3b-1 (Bot only) + 3b-2 (Worker only), falls Operator nur einen Container zur Zeit recreaten will. Weniger Risiko, aber unschön weil .env-Wechsel atomar; bevorzugte Variante: beide zusammen in einem Block.
PLAN-REVIEW Plan fertig. Warte auf:
Kein Code geschrieben. Keine Container/DB-/.env-Änderung. Pure analysis only.