feat(Phase 11b): Bypass-DB-Logging + Auto-Rotation-Skript

- auth_bypass_uses-Tabelle additiv (used_at, client_ip, path, user_agent).
- _check_debug_token schreibt jeden Use als Best-Effort-Insert
  (Try/Except, kein Fehler an User).
- scripts/rotate-debug-token.sh: wöchentlicher Cron, generiert
  neues Secret + re-creates dev-Container.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dotty Dotter 2026-05-06 23:31:51 +02:00
parent c13292133c
commit d853101275
3 changed files with 72 additions and 1 deletions

View File

@ -116,10 +116,29 @@ def _check_debug_token(request: Request) -> Optional[dict]:
presented = (request.query_params.get("__debug_token") or "").strip()
if presented and presented == expected:
client = request.client.host if request.client else "?"
path = request.url.path
user_agent = request.headers.get("user-agent", "")[:200]
logger.warning(
"DEBUG_AUTH_TOKEN bypass active — request from %s to %s",
client, request.url.path,
client, path,
)
# Best-Effort-Logging in DB (synchron, fire-and-forget).
# Schlägt unter keinen Umständen den Request fehl.
try:
import sqlite3
from .config import settings
conn = sqlite3.connect(str(settings.db_path), timeout=2)
try:
conn.execute(
"INSERT INTO auth_bypass_uses (client_ip, path, user_agent) "
"VALUES (?, ?, ?)",
(client, path, user_agent),
)
conn.commit()
finally:
conn.close()
except Exception:
pass # Logging-Fehler nie an User propagieren
return {
"sub": "debug-user",
"email": "debug@local",

View File

@ -363,6 +363,22 @@ async def init_db():
"ON auto_rate_runs(started_at DESC)"
)
# auth_bypass_uses (Phase 11b) — Tracking jeder Verwendung des
# DEBUG_AUTH_TOKEN-Bypass (siehe app/auth.py:_check_debug_token).
await db.execute("""
CREATE TABLE IF NOT EXISTS auth_bypass_uses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
used_at TEXT NOT NULL DEFAULT (datetime('now')),
client_ip TEXT,
path TEXT NOT NULL,
user_agent TEXT
)
""")
await db.execute(
"CREATE INDEX IF NOT EXISTS idx_auth_bypass_used "
"ON auth_bypass_uses(used_at DESC)"
)
await db.commit()

36
scripts/rotate-debug-token.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
# Auto-Rotation des DEBUG_AUTH_TOKEN-Bypass-Secrets (Phase 11b).
#
# Generiert wöchentlich ein neues Secret, schreibt es in
# /opt/gwoe-antragspruefer-dev/.env und re-creates den Container, damit
# die ENV-Änderung greift.
#
# Cron (Sonntag 04:00):
# 0 4 * * 0 /opt/gwoe-antragspruefer-dev/scripts/rotate-debug-token.sh \
# >> /var/log/gwoe-rotate-debug.log 2>&1
set -euo pipefail
ENV_FILE="/opt/gwoe-antragspruefer-dev/.env"
COMPOSE_FILE="/opt/gwoe-antragspruefer-dev/docker-compose.dev.yml"
if [ ! -f "$ENV_FILE" ]; then
echo "$(date -Iseconds) FAIL — $ENV_FILE not found"
exit 1
fi
NEW_TOKEN=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
# Bestehenden Eintrag entfernen, neuen anhängen — atomar via temp-Datei
TMP=$(mktemp)
grep -v "^DEBUG_AUTH_TOKEN=" "$ENV_FILE" > "$TMP"
echo "DEBUG_AUTH_TOKEN=$NEW_TOKEN" >> "$TMP"
mv "$TMP" "$ENV_FILE"
echo "$(date -Iseconds) ROTATED — new token written to $ENV_FILE"
# Container re-creates (compose liest .env nur beim Container-Create).
cd /opt/gwoe-antragspruefer-dev
docker compose -f "$COMPOSE_FILE" up -d --force-recreate
echo "$(date -Iseconds) END"