# AUTH.3B — SECRET / ENV / RUNTIME INJECTION DESIGN + DEPLOYMENT PRE-FLIGHT **Status:** DESIGN + VERIFIED DEPLOYMENT PLAN (STRICT READ-ONLY, KEIN produktives Deployment) **Datum:** 2026-08-27 **Mission Type:** STRICT DESIGN + READ-ONLY DISCOVERY + ISOLATED TESTS **Baseline:** AUTH.1 (40bbc40) + AUTH.2 (edcb4902) + AUTH.3A (a11c1bb) = COMPLETE > ⚠️ Dies ist ein **Design-/Plan-Dokument**. Es wird NICHTS produktiv deployt, > kein Token erzeugt, keine ENV/Compose/Coolify geändert, kein Container > restart/recreate, keine produktive Tolaria-Auth aktiviert. --- ## 1. RUNTIME DISCOVERY (Phase 1) — IST-Zustand ### A) Tolaria Server | Attribut | Wert | |---|---| | Container | `tolaria` | | Runtime | Node.js 20 / Vite (dev server, `vite.config.ts` middleware) | | Host Source | `/opt/tolaria/app/tolaria` | | Container Source | `/app/tolaria` | | Vault | `/opt/data/tolaria-vault` → `/app/vault` (Bind-Mount) | | Compose | `/opt/tolaria/docker-compose.yml` | | Port | 5173 (produktiv); Repo-`vite.config.ts` deklariert 5202 (dev) | | Produktiver Source-Basisstand | `b5a5e4bd` (VOR AUTH.2) | | AUTH.2 deployed? | **NEIN** — Produktion läuft noch OHNE neue Auth (verifiziert: save ohne Token → 200) | | ENV erwartet (Code) | `TOLARIA_SAVE_TOKEN`, `TOLARIA_DELETE_TOKEN`, `TOLARIA_VAULT_ROOT` (Default `/app/vault`) | | Fail-closed | JA — `authorizeVaultWrite` Z.120-123: leeres `expected` → 401 "Write scope not configured" | ### B) C5C Writer (SAVE) | Attribut | Wert | |---|---| | Klasse | `C5CPropagator` (`rq_c5c.py` Z.497) | | Write-Methode | `TolariaClient.write()` (Z.315) → POST `/api/vault/save`, Bearer mit `save_token` | | Credential-Quelle | NUR explizit injizierter Client (`client=...`); Default `TolariaClient()` credential-frei → fail-closed | | ENV | `TOLARIA_SAVE_TOKEN` (Konstante Z.100); `rq_c5c.py` liest ENV NICHT selbst | | CLI-Entrypoint | **KEINER** — kein CLI-Command ruft C5CPropagator mit save_token auf | | Produktiver Aufrufer | `rq_c5f_resume.py` (untracked) — konstruiert `TolariaClient()` OHNE save_token → mit AUTH.3A fail-closed | | Runtime | RQ-Container (`06a4a73573d0`), C5-DB `/opt/data/c5c_live/c5a.db` | ### C) C5 DeleteExecutor (DELETE) | Attribut | Wert | |---|---| | Klasse | `DeleteExecutor` (`rq_c5_delete.py`) | | Write-Methode | `TolariaClient.delete()` → POST `/api/vault/delete`, Bearer mit `delete_token` | | Credential-Quelle | `_delete_executor` (`rq_c5_cli.py` Z.344): `delete_token=os.environ.get(ENV_TOLARIA_DELETE_TOKEN)` | | ENV | `TOLARIA_DELETE_TOKEN` (Konstante Z.101) | | CLI-Entrypoint | `c5-delete-execute`, `c5-delete-replay` (Human-Gated) | | Runtime | RQ-Container (`06a4a73573d0`), C5-DB `/opt/data/c5c_live/c5a.db` | ### D) Red Queen / Hermes | Attribut | Wert | |---|---| | Container | `06a4a73573d0` (RQ/Hermes) | | C5-Caller | laufen IM RQ-Container (C5-DB `/opt/data/c5c_live/c5a.db`) | | Docker-Daemon | NICHT verfügbar aus RQ-Container (kein `/var/run/docker.sock`) | | VPS-Host-SSH | NICHT verfügbar (Key `red_queen_forgejo` nur für Forgejo-Git-Push) | | Tolaria-API | read-only erreichbar (`187.124.31.123:5173`) | ### E) Rain / OpenClaw | Attribut | Wert | |---|---| | Ports | 55163 (Alice), 54524 (Matt Addison) | | Zugriff auf C5-DB | NICHT verifiziert (separate Container) | | Tolaria-Write-Credential | KEIN (Architektur-Invariante) | --- ## 2. KRITISCHER BEFUND (Phase 7-Vorab) **SAVE-Caller (C5CPropagator) und DELETE-Caller (DeleteExecutor) laufen im SELBEN Prozess/Container (RQ-Container `06a4a73573d0`).** Es existiert KEINE getrennte Runtime-Boundary zwischen SAVE und DELETE. Beide Credentials würden, wenn beide injiziert würden, im selben Container landen. **Konsequenz:** Die Credential-Separation (SAVE≠DELETE) ist heute NUR logisch (verschiedene ENV-Namen, verschiedene Klassen), NICHT technisch als getrennte Security Boundaries. Das muss in Phase 7 explizit dokumentiert und in Phase 3/4 bewertet werden. --- ## 2b. SECURITY BOUNDARY ANALYSIS (Phase 2) — IST-Zustand ### Runtime-Fakten (verifiziert) - **RQ/Hermes-Container** = `06a4a73573d0`, User `hermes` (uid 10010, gid 10000). - **Kein Docker-Socket** im RQ-Container (`/var/run/docker.sock` fehlt) → RQ kann keine anderen Container inspizieren. - **Kein VPS-Host-SSH** (Key `red_queen_forgejo` nur für Forgejo-Git-Push) → RQ kann Host-Dateien (`/opt/tolaria`, Compose) NICHT lesen. - **Kein `/opt/tolaria`** im RQ-Container-Dateisystem. - **/proc** im RQ-Container zeigt nur eigene Prozesse (24 PIDs) → kein Cross-Container /proc-Zugriff. - **Netzwerk:** RQ erreicht Tolaria intern (`10.0.4.1:5173` → `{"ok":true}`) und Forgejo (`10.0.4.1:3000`). Tolaria läuft in SEPARATEM Container auf VPS-Host. - **C5-Caller:** KEIN Daemon, KEIN separater Container. `C5CPropagator` (SAVE) und `DeleteExecutor` (DELETE) sind Library/CLI, die manuell im RQ-Container aufgerufen werden (Hermes-Gateway-Prozess). C5-DB `/opt/data/c5c_live/c5a.db` liegt im RQ-Container. - **ENV im RQ-Container:** `TOLARIA_SAVE_TOKEN` ABSENT, `TOLARIA_DELETE_TOKEN` ABSENT (korrekt — RQ credential-free). Vorhandene Secrets: `FORGEJO_WRITE_TOKEN`, `NOTION_API_KEY`, `TELEGRAM_BOT_TOKEN`, `HERMES_SESSION_KEY` (Namen, keine Werte). ### CAN_*_READ_SECRET — SAVE und DELETE (identisch, da gleiche Boundary) | Akteur | SAVE | DELETE | Weg | |---|---|---|---| | **RQ/Hermes** (Container `06a4a73573d0`) | **NEIN** (tatsächlich) | **NEIN** (tatsächlich) | Kein Docker-Socket, kein Host-SSH, kein /proc-Cross, kein /opt/tolaria. ENV ABSENT. | | **RQ/Hermes** (theoretisch via root) | JA (wenn Host-root) | JA (wenn Host-root) | Host-root kann Container-ENV via `docker inspect`/`docker exec` lesen. | | **Rain/OpenClaw** (Alice 55163, Matt 54524) | **NEIN** (tatsächlich) | **NEIN** (tatsächlich) | Separate Container, kein Zugriff auf RQ-ENV oder Tolaria-Container. | | **Anderer Container** (Tolaria selbst) | JA (eigener ENV) | JA (eigener ENV) | Tolaria-Container hält seine eigenen erwarteten Tokens. | | **Docker-Admin** (VPS-Host) | JA | JA | `docker inspect`/`docker exec` auf Tolaria-Container. | | **Host-Root** (VPS) | JA | JA | Liest Compose, .env, Container-ENV, Mounts. | | **C5C Writer** (SAVE-Prozess) | JA (SAVE) | NEIN (kein DELETE) | Erhält nur SAVE-Token via injiziertem Client. | | **DeleteExecutor** (DELETE-Prozess) | NEIN (kein SAVE) | JA (DELETE) | Erhält nur DELETE-Token via ENV. | ### Security-Boundary-Befund - **Tolaria-Server** = eigene Boundary (separater Container, VPS-Host). - **RQ/Hermes** = eigene Boundary (Container `06a4a73573d0`), aber **C5-Caller (SAVE+DELETE) laufen INNERHALB dieser Boundary**. - **CRITICAL:** SAVE- und DELETE-Credential würden, wenn beide injiziert würden, im **selben Container** (`06a4a73573d0`) landen. Es gibt KEINE getrennte Runtime-Boundary zwischen SAVE-Caller und DELETE-Caller. - **Konsequenz für Phase 3:** Die Zielarchitektur "SAVE≠DELETE als getrennte Boundaries" ist mit dem realen Deployment **NICHT vollständig erreichbar**, solange beide Caller im selben RQ-Container laufen. Die Separation ist NUR logisch (verschiedene ENV-Namen, verschiedene Klassen, verschiedene CLI-Commands), NICHT technisch als getrennte Container/Prozesse. --- ## 3b. CREDENTIAL OWNERSHIP MODEL (Phase 3) — Zielarchitektur vs. Realität ### Zielarchitektur (verbindlich aus Freigabe) - SAVE credential → Tolaria Server + C5C Writer - DELETE credential → Tolaria Server + C5 DeleteExecutor - RQ: KEIN SAVE, KEIN DELETE - Hermes generisch: KEIN SAVE, KEIN DELETE - Rain: KEIN SAVE, KEIN DELETE - Kein Master-Token - SAVE darf DELETE nicht autorisieren; DELETE darf SAVE nicht autorisieren ### Erreichbarkeit mit realem Deployment **1) Server-seitige Auth (AUTH.2) — ERREICHBAR ✓** - Tolaria-Server hält SAVE+DELETE-Tokens in seiner eigenen ENV (separater Container). - RQ/Hermes/Rain haben KEINEN Zugriff auf den Tolaria-Container (kein Docker-Socket, kein Host-SSH, kein /proc-Cross). - Server-seitige Scope-Trennung (SAVE≠DELETE) ist im Code verifiziert (AUTH.2). **2) Caller-seitige Credential-Separation — NICHT ERREICHBAR (HARD STOP-Kandidat) ✗** - **Ursache:** C5C Writer (SAVE) und DeleteExecutor (DELETE) laufen im **selben Container** wie RQ/Hermes (`06a4a73573d0`). Es gibt KEINE getrennte Runtime-Boundary. - Wenn SAVE- und DELETE-Tokens in die ENV dieses Containers injiziert würden, hätte RQ/Hermes (das im selben Container läuft, gleicher User `hermes`) **technischen Zugriff auf BEIDE Tokens**. - Das verletzt die Zielarchitektur "RQ: KEIN SAVE KEIN DELETE" und "Hermes: KEIN SAVE KEIN DELETE" — unabhängig davon, ob RQ den Zugriff tatsächlich nutzt. ### HARD STOP — exakte Ursache **Die Zielarchitektur "RQ/Hermes credential-free" ist mit dem realen Deployment NICHT erreichbar, solange die C5-Caller (SAVE+DELETE) im selben Container wie RQ/Hermes laufen und ihre Tokens in dessen ENV liegen.** Notwendige Voraussetzung für AUTH.4 (Architektur-Änderung, NICHT in AUTH.3B): - **Option A (empfohlen):** C5C Writer und DeleteExecutor in einen **separaten Container/Prozess** mit eigener Boundary verschieben, der NICHT der RQ-Container ist. RQ/Hermes ruft diesen Container nur über eine schmale Schnittstelle auf. - **Option B:** Tokens über einen **separaten Secret-Store** injizieren, auf den nur der C5-Caller-Prozess (nicht RQ/Hermes) Zugriff hat. Im selben Container mit gleichem User ist das praktisch nicht durchsetzbar (RQ kann dieselbe Datei lesen). **Ohne diese Änderung bleibt die Separation NUR logisch** (verschiedene ENV-Namen, verschiedene Klassen, verschiedene CLI-Commands), NICHT technisch als getrennte Security Boundaries. Das wird NICHT stillschweigend abgeschwächt — es wird als HARD STOP für die volle Zielarchitektur dokumentiert. ### Was TROTZDEM sicher erreichbar ist (ohne Architektur-Änderung) - **Server-seitige Auth (AUTH.2) aktivieren:** Tolaria-Server fail-closed, SAVE≠DELETE Scope-Trennung. RQ bleibt credential-free (kein Zugriff auf Tolaria-Container). - **SAVE-Aktivierung:** C5C Writer erhält SAVE-Token. ABER: da im RQ-Container, hätte RQ technisch Zugriff → verletzt "RQ credential-free" für SAVE. - **DELETE-Aktivierung:** DeleteExecutor erhält DELETE-Token. ABER: da im RQ-Container, hätte RQ technisch Zugriff → verletzt "RQ credential-free" für DELETE. ### Fazit Phase 3 - **SERVER_AUTH_DEPLOYMENT:** ERREICHBAR (RQ bleibt credential-free ggü. Tolaria). - **SAVE_ACTIVATION / DELETE_CREDENTIAL_ACTIVATION:** BLOCKED bis C5-Caller in getrennte Boundary verschoben ODER Secret-Injection RQ-undurchdringbar ist. - **Kein Master-Token:** ERREICHBAR (AUTH.2/AUTH.3A verifiziert, kein Master-Key). - **SAVE≠DELETE Scope-Trennung:** Server-seitig ERREICHBAR; Caller-seitig nur logisch. --- ## 4b. SECRET STORAGE OPTIONS (Phase 4) — Bewertung ### Kontext: Was existiert im realen Stack? - **Coolify-Suite** ist auf dem VPS installiert (infrastructure-handbook Z.52). - **Exakte Tolaria-Provisionierung (Compose vs Coolify) ist aus RQ-Sicht UNKNOWN** (kein Docker-Socket, kein Host-SSH). CURRENT_STATE Z.27: "UNKNOWN: Container-Name/ Image-Konfiguration, Env-Variablen, Mounts, Volumes — nur über Host-/Docker-Zugriff ermittelbar, der nicht verfügbar ist." - **Kein separater Secret-Store** (kein Vault/Consul/SOPS/age) im Stack nachweisbar. - **Kein Docker-Secrets-Mechanismus** im Stack nachweisbar (kein Swarm). - Tolaria-Server liest ENV via `process.env.TOLARIA_SAVE_TOKEN` (vite.config.ts). ### Optionen-Bewertung (SAVE und DELETE, identisch) | Kriterium | A) Plain Compose ENV | B) .env-Datei | C) Docker Secrets | D) read-only Secret-Datei | E) Coolify Secret Mgmt | F) separater Secret-Store | |---|---|---|---|---|---|---| | SECURITY | Schwach (ENV in inspect) | Mittel (Datei, chmod) | Stark (nur im Container) | Mittel (Datei, chmod) | Stark (Coolify-UI) | Stark | | VISIBILITY | `docker inspect` sichtbar | Datei, nicht inspect | Nicht in inspect | Datei, nicht inspect | Nicht in inspect | Nicht in inspect | | DOCKER_INSPECT_EXPOSURE | **JA** | NEIN | NEIN | NEIN | NEIN | NEIN | | HOST_EXPOSURE | JA (root liest) | JA (root liest) | JA (root liest) | JA (root liest) | JA (root liest) | JA (root liest) | | RQ_EXPOSURE | JA (wenn im RQ-Container) | JA (wenn im RQ-Container) | NEIN (nur Ziel-Container) | JA (wenn im RQ-Container) | NEIN | NEIN | | ROTATION | Restart nötig | Restart nötig | Restart nötig | Restart nötig | Restart nötig | Restart nötig | | REVOCATION | ENV entfernen + Restart | Datei löschen + Restart | Secret entfernen + Restart | Datei löschen + Restart | ENV entfernen + Restart | Store-Update + Restart | | RESTART_BEHAVIOR | ENV bleibt | Datei bleibt | Secret bleibt | Datei bleibt | ENV bleibt | Store bleibt | | BACKUP_BEHAVIOR | ENV nicht in Backup | Datei evtl. in Backup | Secret nicht in Backup | Datei evtl. in Backup | ENV nicht in Backup | Store in Backup | | OPERATIONAL_COMPLEXITY | Niedrig | Niedrig | Mittel (Swarm nötig) | Niedrig | Mittel | Hoch | | COMPATIBILITY | Hoch (Vite liest ENV) | Hoch | Niedrig (kein Swarm) | Hoch (Datei lesen) | Mittel (Coolify vorhanden) | Niedrig (nicht vorhanden) | | BLAST_RADIUS | Hoch (inspect) | Mittel | Niedrig | Mittel | Niedrig | Niedrig | ### Empfehlung für UNSEREN Stack **Minimal sichere Variante: B) .env-Datei (oder D) read-only Secret-Datei) mit strikten Permissions, injiziert in die Tolaria-Container-ENV.** Begründung: - **A (Plain Compose ENV) ist abzulehnen:** `docker inspect` würde die Tokenwerte offenlegen (DOCKER_INSPECT_EXPOSURE=JA). Das verletzt die Anforderung "kein Secret in docker inspect". - **C (Docker Secrets) ist nicht kompatibel:** erfordert Docker Swarm, das im Stack nicht nachweisbar ist. - **F (separater Secret-Store) ist nicht vorhanden:** keine neue Infrastruktur erfinden (Freigabe-Anforderung). - **E (Coolify Secret Mgmt):** Coolify ist vorhanden, aber die exakte Tolaria- Provisionierung ist UNKNOWN. Falls Tolaria über Coolify deployed wird, ist Coolify Secret Management die natürliche Wahl (nicht in inspect, Rotation via UI). - **B/D sind die robuste Default-Empfehlung:** `.env`-Datei mit `chmod 600`, vom Compose/Coolify in die Container-ENV injiziert. Tokenwerte erscheinen NICHT in `docker inspect` (nur der ENV-Name, nicht der Wert, wenn via `env_file` injiziert). **WICHTIG (Phase 3-Kopplung):** Unabhängig von der Storage-Option bleibt der HARD STOP bestehen: Solange die C5-Caller im RQ-Container laufen, würde jede Injektion in dessen ENV RQ technischen Zugriff geben. Die Storage-Empfehlung gilt daher primär für den **Tolaria-Server-Container** (eigene Boundary, RQ-fern). --- ## 5b. TOKEN GENERATION CONTRACT (Phase 5) — NUR DESIGN, KEINE echten Tokens > ⚠️ Dies ist ein **Design-Vertrag**. Es wird KEIN echtes Token erzeugt, kein Wert > angezeigt, nichts in ENV/Compose/Logs/Telegram/Repo geschrieben. ### Kryptographische Zufallsquelle - **`/dev/urandom`** (Linux) oder `secrets.token_urlsafe()` (Python) — kryptographisch sicher, nicht-deterministisch. - NICHT: `random`-Modul, `time`-basiert, UUID (nicht krypto-sicher genug für Auth). ### Mindestentropie - **≥ 256 Bit** (32 Bytes) pro Token. Empfehlung: 32 Bytes aus `/dev/urandom`, base64url-kodiert → 43 Zeichen. ### Format / Länge - **Format:** base64url (URL-sicher, kein `+`/`/`/`=`), 43 Zeichen bei 32 Bytes. - **Länge:** 43 Zeichen (256 Bit Entropie). - **Keine semantischen Token-Präfixe** (kein `save-`, `delete-`, `tolaria-` im Wert) — Präfixe wären unnötige Information und könnten Scope-Leaks erzeugen. Der Scope wird durch die ENV-Variable bestimmt, nicht durch den Tokenwert. ### Unabhängigkeit - **SAVE und DELETE unabhängig generiert** (zwei separate `/dev/urandom`-Ziehungen). - **Niemals gleicher Wert** (bei 256 Bit Entropie kollisionsfrei). - **Keine Ableitung SAVE→DELETE** (kein Hash/Substring/Transformation). - **Kein Master-Key** (kein gemeinsamer Seed, kein hierarchisches Schema). ### Nicht-Speicherung / Nicht-Ausgabe - **Keine Shell-History** (kein `echo $TOKEN`, kein Token in interaktiven Befehlen). - **Keine Ausgabe in Telegram / Chat / Logs / FINAL REPORT.** - Token wird NUR in die Ziel-ENV/Secret-Datei geschrieben (Tolaria-Server-Container), nie in Git, nie in Reports, nie in Test-Fixtures. ### Wer die Tokens bei AUTH.4 erzeugen darf - **Nur Christian (Mensch)** — manuell auf dem VPS-Host, via `/dev/urandom` oder `openssl rand -base64 32`, direkt in die Secret-Datei/Coolify-ENV geschrieben. - **NICHT RQ/Hermes/Rain** — kein Agent erzeugt oder sieht die echten Tokens. - Erzeugung erfolgt im Rahmen der AUTH.4-Deployment-Sequenz (Phase 9), nicht in AUTH.3B. --- ## 6b. SERVER INJECTION CONTRACT (Phase 6) — AUTH.2 im Code verifiziert ### Exakte ENV-Namen (im Code verifiziert, `vite.config.ts` Z.35-39) - `TOLARIA_VAULT_ROOT` → Default `/app/vault` - `TOLARIA_SAVE_TOKEN` → `saveToken` (Scope SAVE) - `TOLARIA_DELETE_TOKEN` → `deleteToken` (Scope DELETE) ### Verhalten (im Code verifiziert, `vault-write-guard.ts` Z.112-131) | Feld | Wert | |---|---| | SERVER_SAVE_ENV | `TOLARIA_SAVE_TOKEN` | | SERVER_DELETE_ENV | `TOLARIA_DELETE_TOKEN` | | MISSING_SAVE_BEHAVIOR | `expected.length === 0` → 401 "Write scope not configured" (fail-closed) | | MISSING_DELETE_BEHAVIOR | dito (fail-closed) | | EMPTY_TOKEN_BEHAVIOR | `|| ''` → leeres expected → 401 (fail-closed) | | WRONG_SCOPE_BEHAVIOR | `constantTimeEqual(extracted, expected)` → falscher Scope → 401 "Invalid credentials" | ### Fail-closed bestätigt - **Kein "Auth disabled because ENV missing".** Fehlende/leere Token-Konfiguration → mutierende Endpoints bleiben DENIED (401). - Scope-Trennung: SAVE-Token autorisiert NUR SAVE; DELETE-Token NUR DELETE. - Const-time-Vergleich (`constantTimeEqual`) gegen Timing-Angriffe. - Auth-before-Mutation: bei Auth-Fehler wird Response gesendet, KEINE Mutation. ### Fazit Phase 6 - **SERVER_FAIL_CLOSED_STATUS = ENFORCED** (im Code verifiziert). - Server erwartet exakt `TOLARIA_SAVE_TOKEN` + `TOLARIA_DELETE_TOKEN`. - Kein Master-Token, keine Scope-Abschwächung. --- ## 7b. CALLER INJECTION CONTRACT (Phase 7) — AUTH.3A im Code verifiziert ### ENV-Contract (im Code verifiziert, `rq_c5c.py` Z.100-101) - `ENV_TOLARIA_SAVE_TOKEN = "TOLARIA_SAVE_TOKEN"` - `ENV_TOLARIA_DELETE_TOKEN = "TOLARIA_DELETE_TOKEN"` ### Credential-Verwendung (im Code verifiziert) | Caller | ENV | Verwendung | Scope | |---|---|---|---| | C5C Writer (`C5CPropagator`) | `TOLARIA_SAVE_TOKEN` | `write()` Z.322: `self._require_token(self.save_token, "SAVE")` | SAVE | | DeleteExecutor | `TOLARIA_DELETE_TOKEN` | `delete()` Z.352: `self._require_token(self.delete_token, "DELETE")` | DELETE | | read/list | — | KEIN Credential | READ | ### Verifizierte Invarianten - **SAVE-Prozess bekommt DELETE nicht:** `write()` nutzt NUR `self.save_token`. - **DELETE-Prozess bekommt SAVE nicht:** `delete()` nutzt NUR `self.delete_token`. - **read/list brauchen nichts:** `read()`/`list()` senden kein Bearer. - **fehlendes Token => kein HTTP Write:** `_require_token` (Z.300-313) bricht lokal ab (RC_AUTH_FAILURE), HTTP wird NICHT aufgerufen (fail-closed, AUTH.1 §4). - **Retry behält Credential:** Client-Instanz hält Token über Retries hinweg. - **Replay behält Credential:** `c5-delete-replay` nutzt denselben `_delete_executor`. - **Token wird nicht persistiert:** kein Token in DB/Logs/Reports (AUTH.3A verifiziert). ### KRITISCHER BEFUND (Runtime-Separation) - **Sind C5C Writer und DeleteExecutor heute getrennte Runtime-Prozesse/Boundaries? NEIN.** - Beide laufen im **selben Container** (`06a4a73573d0`, RQ/Hermes) und werden als Library/CLI im selben Hermes-Gateway-Prozess aufgerufen. - **Konsequenz:** Die Credential-Separation ist NUR logisch (verschiedene ENV-Namen, verschiedene Klassen, verschiedene CLI-Commands). Wenn beide Tokens in die ENV dieses Containers injiziert würden, hätte RQ/Hermes technischen Zugriff auf BEIDE. - **Das wird NICHT als technische Separation behauptet.** Es ist explizit dokumentiert: CREDENTIAL_SEPARATION_STATUS = LOGICAL_ONLY (nicht technisch). ### Fazit Phase 7 - **CALLER_FAIL_CLOSED_STATUS = ENFORCED** (im Code verifiziert). - **CREDENTIAL_SEPARATION_STATUS = LOGICAL_ONLY** (nicht technisch, da gleiche Boundary). - Least Privilege im Code korrekt; Runtime-Separation fehlt (HARD STOP aus Phase 3). --- ## 8b. HUMAN APPROVAL INTERACTION (Phase 8) — AUTH4_WITH_OPEN_APPROVAL_GAP ### Kontext - **HUMAN_APPROVAL_AUTHENTICITY_GAP = OPEN** (aus AUTH.3A, NICHT repariert). Die DELETE-Approval erfüllt Invarianten A–N, aber die Provenance ist nicht kryptographisch an Christian gebunden (frei wählbares CLI-Argument `--approved-by`, `rq_c5_cli.py` Z.576). - **DELETE-Execution (AUTH.3A, `rq_c5_delete.py` Z.192-251):** 4 Pre-Gates: 1. ObjectChange existiert + operation == DELETE 2. Commit-Status == ST_DELETE_APPROVED 3. Approval existiert, APPROVED, passt exakt (Commit/Objekt/Pfad) ← **Human Gate** 4. Pre-Delete-Drift-Check (Ziel existiert noch) ### Wie interagiert das DELETE-Token mit dem Human Gate? - Das DELETE-Token (AUTH.2/AUTH.3A) ist eine **zusätzliche, unabhängige Bedingung** auf Transport-Ebene: `delete()` sendet Bearer DELETE-Token; Server verweigert ohne gültiges Token (401). - Das Human Approval Gate (Gate 3) ist eine **separate Bedingung auf Anwendungs-Ebene**: `execute()` verweigert ohne persistierte, exakt passende Approval. - **DELETE ist nur möglich, wenn BEIDES erfüllt ist:** A) gültiges DELETE-Credential (Server-Auth) UND B) bestehendes C5 Human Approval Gate (Gate 3). ### Verschärft AUTH.4 das Authenticity-Gap? - **NEIN.** AUTH.4 fügt eine zusätzliche Hürde (DELETE-Token) hinzu, die das bestehende Gap NICHT verschärft, sondern die DELETE-Ausführung zusätzlich absichert. - Das Gap (Provenance nicht kryptographisch an Christian gebunden) bleibt bestehen, wird aber durch das DELETE-Token NICHT schwächer. Ein Angreifer, der das Authenticity-Gap ausnutzt (frei wählbares `--approved-by`), bräuchte ZUSÄTZLICH das DELETE-Token, um tatsächlich zu löschen. - **Kein Risiko, dass durch das DELETE-Token ein schwächeres Human Gate akzeptiert wird.** Das Human Gate (Gate 3) bleibt unverändert ENFORCED. ### Klassifikation **AUTH4_WITH_OPEN_APPROVAL_GAP = SAFE_FOR_SERVER_AUTH_ONLY** Begründung: - Die Einführung des DELETE-Tokens (Server-Auth) verschärft das Authenticity-Gap NICHT — es fügt eine unabhängige, zusätzliche Hürde hinzu. - **ABER:** DELETE_OPERATION_ACTIVATION (tatsächliches Löschen) sollte erst nach Schließung des Gaps freigegeben werden, um das Risiko eines kombinierten Angriffs (Gap + gestohlenes Token) zu minimieren. - **SAFE_FOR_SERVER_AUTH_ONLY** bedeutet: Server-seitige Auth (AUTH.2) kann sicher aktiviert werden, ohne das Gap zu verschärfen. Die DELETE-Operation selbst bleibt bis zur Gap-Schließung zurückhaltend zu behandeln (siehe Phase 14 GO/NO-GO). --- ## 9b. DEPLOYMENT SEQUENCE DESIGN (Phase 9) — AUTH.4 atomar, KEIN Big-Bang > ⚠️ NUR DESIGN. KEINE AUSFÜHRUNG in AUTH.3B. ### Kernfrage: Caller zuerst vs Server zuerst? **Server zuerst (AUTH.2 aktivieren), dann Caller (AUTH.3A).** Begründung (kein Zeitfenster mit ungeschützten Writes): - Wenn der **Caller zuerst** das SAVE-Token erhält, aber der **Server noch ohne Auth** läuft, dann sendet der Caller zwar ein Bearer-Token, aber der Server ignoriert es (Produktion läuft aktuell OHNE AUTH.2) → **Writes bleiben ungeschützt** (ungültiges Zeitfenster). - Wenn der **Server zuerst** AUTH.2 aktiviert (fail-closed), dann verweigert er ALLE Writes ohne gültiges Token. In diesem Moment haben die Caller noch KEIN Token → **legitime C5-Writes fallen kurzzeitig aus** (kontrolliertes, kurzes Fenster). Das ist akzeptabel, weil es FAIL-CLOSED ist (kein ungeschützter Write). - **Kein Zeitfenster, in dem Writes ungeschützt bleiben:** Server-Auth zuerst schließt das Loch sofort; Caller-Token werden danach injiziert. - **Kein Zeitfenster, in dem DELETE ohne Human Gate möglich wird:** DELETE-Token wird erst injiziert, wenn das Human Gate (Gate 3) bereits ENFORCED ist (AUTH.3A Code ist deployed). DELETE bleibt doppelt abgesichert. ### Atomare AUTH.4-Reihenfolge (jeder Schritt einzeln, mit Gate) | # | Schritt | Aktion | Gate/Verifikation | |---|---|---|---| | 1 | **PRECHECK** | Produktiver Source == Forgejo `edcb4902`; AUTH.2/AUTH.3A Code deployed; kein Token in ENV | `git diff` leer, ENV-Namen ABSENT | | 2 | **BACKUP** | Vault + Compose + aktuelle ENV-Namen sichern (KEINE Tokenwerte) | Backup-Datei existiert | | 3 | **TOKEN_GENERATION** | Christian erzeugt SAVE+DELETE-Token (Phase 5 Contract), schreibt in Secret-Datei/Coolify | Token in Ziel-ENV, NICHT in Git/Logs | | 4 | **SERVER_SECRET_INJECTION** | `TOLARIA_SAVE_TOKEN` + `TOLARIA_DELETE_TOKEN` in Tolaria-Container-ENV (via .env/Coolify) | ENV-Namen PRESENT (Werte nicht prüfen) | | 5 | **CALLER_SECRET_INJECTION** | SAVE-Token an C5C Writer, DELETE-Token an DeleteExecutor (NUR nach Boundary-Fix, Phase 3) | Getrennte Boundaries ODER HARD STOP | | 6 | **CODE_DEPLOY** | AUTH.2-Source (edcb4902) in Produktion deployen (Container-Restart) | Server startet, Read funktioniert | | 7 | **SERVER_RESTART** | Tolaria-Container neu starten (liest neue ENV) | Healthcheck OK | | 8 | **READ_SMOKE** | `GET /api/vault/ping`, `/list`, `/content` ohne Token → 200 | Read funktioniert | | 9 | **UNAUTH_WRITE_NEGATIVE_TEST** | `POST /save` ohne Token → 401 (fail-closed) | Write DENIED | | 10 | **WRONG_SCOPE_NEGATIVE_TEST** | `POST /save` mit DELETE-Token → 401; `POST /delete` mit SAVE-Token → 401 | Scope-Trennung | | 11 | **AUTHORIZED_SAVE_TEST** | `POST /save` mit SAVE-Token → 200 (isolierte Fixture) | SAVE funktioniert | | 12 | **DELETE_GATE_NEGATIVE_TEST** | `POST /delete` mit DELETE-Token aber OHNE Human Approval → DENIED | Human Gate ENFORCED | | 13 | **AUTHORIZED_DELETE_TEST** | `POST /delete` mit DELETE-Token + Human Approval → 200 (NUR falls freigabefähig) | DELETE funktioniert | | 14 | **POST_DEPLOY_CHECK** | Read + Write + Scope + kein Token in Logs/inspect | Alle Checks grün | | 15 | **FRESH_CHECKER** | Unabhängiger Checker verifiziert alle Gates | PASS | ### Wichtige Design-Entscheidungen - **Kein Big-Bang:** Jeder Schritt hat ein eigenes Gate; bei Fehler → Rollback (Phase 10), nicht weiter. - **Schritt 5 (CALLER_SECRET_INJECTION) ist BLOCKED** bis die Boundary-Frage aus Phase 3 gelöst ist (C5-Caller in getrennten Container ODER RQ-undurchdringbare Injektion). Ohne das bleibt RQ credential-free NICHT erreichbar. - **Schritt 13 (AUTHORIZED_DELETE_TEST) ist CONDITIONALLY_READY** — nur falls DELETE-Operation freigabefähig ist (siehe Phase 14, Gap-Berücksichtigung). - **Server zuerst** minimiert das ungeschützte Write-Fenster auf null. --- ## 10b. ROLLBACK DESIGN (Phase 10) — FAIL CLOSED, Write-Degraded-Mode > ⚠️ NUR DESIGN. KEINE AUSFÜHRUNG in AUTH.3B. ### Grundprinzip - **FAIL CLOSED bevorzugen.** Bei Credential-/Auth-Problem NICHT automatisch auf unauthentifizierte Writes zurückrollen. - **Ein Rollback darf NICHT bedeuten:** "Auth ausschalten und unauthentifizierte Writes wieder erlauben", wenn dadurch die bereits identifizierte CRITICAL Gap (Produktion läuft aktuell OHNE Auth) wieder geöffnet wird. - **Bevorzugter Security-Rollback = WRITE_DEGRADED_MODE:** - **READ AVAILABLE** (Read-Endpunkte funktionieren weiter) - **WRITE DISABLED** (mutierende Endpunkte bleiben DENIED) ### Exakte Rollback-Pfade | Fall | Symptom | Rollback-Aktion | Security-Position | |---|---|---|---| | **A) Server startet nicht** | Container-Crash nach AUTH.2-Deploy | Source auf `b5a5e4bd` (Basisstand) zurück; ENV-Tokens entfernen; Restart | FAIL CLOSED (kein Write ohne Auth) | | **B) Read-Endpunkte kaputt** | `/ping`, `/list`, `/content` 500 | Source auf `b5a5e4bd` zurück; ENV-Tokens entfernen; Restart | FAIL CLOSED | | **C) C5C SAVE schlägt fehl** | SAVE-Writes 401/500 | SAVE-Token prüfen/erneuern; NICHT Auth deaktivieren | WRITE_DEGRADED (SAVE disabled, READ available) | | **D) DELETE-Caller schlägt fehl** | DELETE-Writes 401/500 | DELETE-Token prüfen/erneuern; NICHT Human Gate deaktivieren | WRITE_DEGRADED (DELETE disabled, READ available) | | **E) Token falsch injiziert** | Wrong-Scope 401 | Token korrekt injizieren; NICHT Auth deaktivieren | FAIL CLOSED | | **F) Token-Leak vermutet** | Token in Logs/inspect/Repo | Token SOFORT rotieren (Phase 11); NICHT Auth deaktivieren | FAIL CLOSED | | **G) Falscher Scope** | SAVE-Token autorisiert DELETE (o. umgekehrt) | Scope-Trennung prüfen; Token neu generieren | FAIL CLOSED | | **H) Regression nach Restart** | Read/Write unerwartet | Source auf `b5a5e4bd` zurück; ENV-Tokens entfernen; Restart | FAIL CLOSED | ### WRITE_DEGRADED_MODE (bevorzugter Security-Rollback) - **READ AVAILABLE:** `/api/vault/ping`, `/list`, `/content`, `/all-content`, `/entry`, `/search` funktionieren (kein Token nötig). - **WRITE DISABLED:** `/api/vault/save`, `/rename`, `/rename-filename`, `/delete`, `/command` bleiben DENIED (401) — fail-closed, weil Token-Konfiguration entfernt oder ungültig ist. - **Wie erreicht:** ENV-Tokens aus Tolaria-Container entfernen (oder auf ungültig setzen) + Restart. Server bleibt fail-closed (leeres expected → 401). - **WICHTIG:** Das ist KEIN "Auth ausschalten". Es ist "Auth auf DENIED-ALL setzen" — Writes sind blockiert, nicht ungeschützt. ### Warum NICHT auf unauthentifizierte Writes zurückrollen - Die Produktion läuft aktuell OHNE Auth (CRITICAL Gap, verifiziert in Phase 1). - Ein Rollback auf "Auth aus" würde dieses Gap wieder öffnen und Writes ungeschützt lassen. - WRITE_DEGRADED_MODE hält Writes geschützt (DENIED), während Read verfügbar bleibt — das ist die sichere Zwischenposition bis zur Fehlerbehebung. --- ## 11b. TOKEN ROTATION / REVOCATION (Phase 11) — SAVE/DELETE getrennt > ⚠️ NUR DESIGN. KEINE AUSFÜHRUNG in AUTH.3B. ### Unterstützt AUTH.2 nur einen Token pro Scope? - **JA.** `VaultAuthConfig` (`vite.config.ts` Z.36-39) hält `saveToken` und `deleteToken` als **einzelne Strings** (kein Array, keine Multi-Token-Unterstützung). - `authorizeVaultWrite` (Z.120-126) vergleicht gegen genau EINEN erwarteten Token pro Scope. - **Konsequenz:** Zero-downtime-Rotation (zwei gültige Tokens gleichzeitig) ist mit AUTH.2 NICHT möglich. Rotation erfordert ein kurzes Write-Downtime-Fenster. ### SAVE-Rotation (minimales Write-Downtime-Fenster) 1. Neues SAVE-Token erzeugen (Phase 5 Contract). 2. Neues Token in Tolaria-Container-ENV schreiben (ersetzt altes). 3. Tolaria-Container neu starten (liest neues Token). 4. C5C Writer erhält neues SAVE-Token (nach Boundary-Fix, Phase 3). 5. Altes SAVE-Token ist sofort ungültig (Server vergleicht nur gegen neues). 6. **Write-Downtime-Fenster:** zwischen Schritt 3 und 4 sendet C5C Writer noch altes Token → 401. Fenster = Zeit bis C5C Writer aktualisiert ist. 7. **Verifikation:** `POST /save` mit neuem Token → 200; mit altem → 401. ### DELETE-Rotation (analog, getrennt) 1. Neues DELETE-Token erzeugen. 2. In Tolaria-Container-ENV schreiben (ersetzt altes). 3. Tolaria-Container neu starten. 4. DeleteExecutor erhält neues DELETE-Token. 5. Altes DELETE-Token sofort ungültig. 6. **Verifikation:** `POST /delete` mit neuem Token + Human Approval → 200; mit altem → 401. ### Laufende Retries / queued Jobs - **Retries:** Ein laufender Retry mit altem Token schlägt nach Rotation fehl (401). Der Retry muss das neue Token verwenden (Client-Instanz neu konstruieren). - **Queued Jobs:** C5-Queue-Einträge, die vor Rotation geplant wurden, verwenden beim Ausführen das aktuelle Token (Client wird zur Laufzeit konstruiert). Nach Rotation nutzen sie das neue Token. - **Empfehlung:** Rotation in einem Wartungsfenster durchführen, wenn keine kritischen Writes anstehen. ### DELETE-Revocation (unabhängig von SAVE) - **DELETE-Revocation muss unabhängig von SAVE möglich sein:** Ja — DELETE-Token ist eine separate ENV-Variable (`TOLARIA_DELETE_TOKEN`). Entfernen/ersetzen dieser Variable + Restart widerruft DELETE, ohne SAVE zu beeinflussen. - **SAVE-Revocation analog:** `TOLARIA_SAVE_TOKEN` entfernen/ersetzen + Restart widerruft SAVE, ohne DELETE zu beeinflussen. - **Revocation = sofort wirksam** nach Container-Restart (Server liest ENV beim Start; kein Cache). ### Welche Komponenten müssen restart/reload? - **Tolaria-Server-Container:** Restart nötig (liest ENV beim Start). - **C5C Writer / DeleteExecutor:** Client-Instanz neu konstruieren (neues Token). Kein Container-Restart nötig, wenn Token via ENV/Config injiziert wird und der Prozess neu gestartet wird. ### Wie wird Rotation verifiziert? - **Positiv:** Write mit neuem Token → 200. - **Negativ:** Write mit altem Token → 401 (fail-closed). - **Scope:** SAVE-Token autorisiert nicht DELETE und umgekehrt. - **Kein Token-Leak:** neues Token nicht in Logs/inspect/Repo. --- ## 12b. BACKUP / RECOVERY (Phase 12) — Secret-Handling > ⚠️ NUR DESIGN. KEINE Backup-Konfiguration ändern in AUTH.3B. ### Werden Secret-Werte in normalen Backups erfasst? - **NEIN.** Das Tolaria-Backup-Skript (`/opt/data/bin/tolaria_backup.py`) sichert NUR Vault-Content (`.md`-Dateien) und App-Source über die read-only API (`/api/vault/list`, `/api/vault/content`). Es sichert KEINE ENV-Variablen, KEINE Compose-Datei, KEINE Secret-Dateien. - **Sollten sie enthalten sein?** NEIN. Secrets gehören NICHT in Backups. Sie werden separat (außerhalb des Backup-Pfads) verwaltet und bei Restore neu injiziert. ### Wie wird Disaster Recovery durchgeführt? 1. Vault-Content aus Backup wiederherstellen (via `tolaria_backup.py` oder Vault-Git-Restore). 2. App-Source aus Forgejo (`edcb4902`) neu deployen (rebuildbar, Forgejo=SoT). 3. **Secrets NEU injizieren** (nicht aus Backup): Christian erzeugt frische SAVE/DELETE-Tokens (Phase 5 Contract) und schreibt sie in die Container-ENV. ### Müssen Tokens nach Restore rotiert werden? - **JA, zwingend.** Nach einem Disaster Recovery werden frische Tokens erzeugt (nicht die alten aus dem Backup). Das verhindert, dass alte, möglicherweise kompromittierte Tokens weiterleben. ### Können alte Backups alte gültige Tokens enthalten? - **NEIN** (aktuell): Das Backup-Skript sichert keine Secrets. Aber falls in Zukunft ein Backup die Compose-Datei oder ENV mit aufnimmt, könnten alte Tokens enthalten sein. ### Wie verhindern wir Secret-Restore aus veraltetem Backup? - **Backup-Skript sichert keine Secrets** (verifiziert, Z.17 "Keine Secrets im Manifest/Log"). - **Restore-Prozedur injiziert IMMER frische Tokens** (nie aus Backup). - **Empfehlung:** Falls ein Backup je Compose/ENV aufnimmt, Secrets vor dem Backup strikt ausschließen (`.gitignore`-artige Exklusion) und nach Restore rotieren. ### Empfehlung (dokumentiert, KEINE Änderung) - Secrets NIE in Backups aufnehmen. - Nach jedem Restore frische Tokens erzeugen. - Backup-Manifest/Logs secret-frei halten (bereits der Fall). --- ## 13b. ISOLATED DEPLOYMENT TEST PLAN (Phase 13) — AUTH.4 > ⚠️ NUR TESTPLAN. KEINE produktiven Mutationsprobes in AUTH.3B. > Alle Tests werden in AUTH.4 in isolierter Umgebung (Fixture-Vault, synthetische > Tokens) ausgeführt, NICHT gegen Produktion. | ID | Test | Erwartung | Typ | |---|---|---|---| | T1 | READ ohne Token | `/ping`, `/list`, `/content` → 200 | Positiv | | T2 | SAVE ohne Token | `POST /save` → 401 (fail-closed) | Negativ | | T3 | SAVE wrong token | `POST /save` mit falschem Token → 401 | Negativ | | T4 | SAVE DELETE-token | `POST /save` mit DELETE-Token → 401 (Scope) | Negativ | | T5 | SAVE korrektes SAVE-token | `POST /save` mit SAVE-Token → 200 | Positiv | | T6 | DELETE ohne Token | `POST /delete` → 401 (fail-closed) | Negativ | | T7 | DELETE wrong token | `POST /delete` mit falschem Token → 401 | Negativ | | T8 | DELETE SAVE-token | `POST /delete` mit SAVE-Token → 401 (Scope) | Negativ | | T9 | DELETE korrektes Token, ohne Human Approval | → DENIED (Gate 3) | Negativ | | T10 | DELETE Approval, aber ohne Token | → 401 (fail-closed) | Negativ | | T11 | DELETE Token + Approval | → 200 NUR falls ausdrücklich freigegeben | Positiv | | T12 | missing server ENV | Server startet, Writes DENIED (fail-closed) | Negativ | | T13 | missing caller ENV | Caller bricht vor HTTP ab (fail-closed) | Negativ | | T14 | Restart erhält Security State | Nach Restart weiterhin fail-closed | Positiv | | T15 | kein Token in Logs | Logs secret-frei | Negativ | | T16 | kein Token in inspect | `docker inspect` secret-frei (soweit Architektur) | Negativ | | T17 | kein Token in Repo | Git-History secret-frei | Negativ | | T18 | kein Token im Vault | Vault-Content secret-frei | Negativ | | T19 | kein Token in DB | C5-DB secret-frei | Negativ | | T20 | Retry sicher | Retry behält Credential, kein Leak | Positiv | | T21 | Replay sicher | Replay behält Credential, kein Leak | Positiv | | T22 | READ während Write-Degraded-Mode | Read 200, Write DENIED | Positiv | | T23 | SAVE/DELETE getrennt widerrufbar | Revocation eines Scopes beeinflusst anderen nicht | Positiv | | T24 | Path traversal weiterhin denied | `../` → 401/400 | Negativ | | T25 | Symlink escape weiterhin denied | Symlink → 401/400 | Negativ | | T26 | `/api/vault/command` kann Auth nicht umgehen | Command ohne Token → 401 | Negativ | ### Test-Ausführungsregeln (AUTH.4) - Alle Tests in isolierter Umgebung (Fixture-Vault, synthetische Tokens `auth4-...`), NICHT gegen Produktion. - T11 (DELETE Token + Approval) NUR wenn DELETE-Operation freigabefähig ist (siehe Phase 14). - Keine produktiven Mutationsprobes in AUTH.3B. --- ## 14b. AUTH.4 GO/NO-GO MATRIX (Phase 14) > ⚠️ NUR BEWERTUNG. KEINE Aktivierung in AUTH.3B. | Punkt | Status | Konkrete Blocker | |---|---|---| | **SERVER_AUTH_DEPLOYMENT** | **CONDITIONALLY_READY** | AUTH.2-Code (edcb4902) ist fertig + getestet (70/70, Fresh Checker 17/17). Blocker: produktiver Source muss == Forgejo `edcb4902` sein; ENV-Tokens müssen injiziert werden; Container-Restart nötig. Kein Code-Blocker. | | **SAVE_ACTIVATION** | **CONDITIONALLY_READY** | AUTH.3A-Code (a11c1bb) fertig + getestet (19/19, 318/318). Blocker: SAVE-Token muss an C5C Writer injiziert werden; **Boundary-Frage (Phase 3) muss gelöst sein** — sonst hätte RQ Zugriff auf SAVE-Token. | | **DELETE_CREDENTIAL_ACTIVATION** | **BLOCKED** | DELETE-Token-Injektion an DeleteExecutor erfordert getrennte Boundary (Phase 3). Aktuell laufen SAVE+DELETE im selben Container → RQ hätte Zugriff auf BEIDE Tokens. **HARD STOP bis Boundary-Fix.** | | **DELETE_OPERATION_ACTIVATION** | **BLOCKED** | Zusätzlich zum Boundary-Fix: HUMAN_APPROVAL_AUTHENTICITY_GAP ist OPEN. DELETE-Operation erst nach Gap-Schließung freigeben (kombinierter Angriff Gap+Token). | | **HERMES_READ_ONLY_AUTONOMY** | **CONDITIONALLY_READY** | Read-Endpunkte brauchen kein Token; RQ bleibt credential-free für Read. Blocker: keine (Read ist bereits möglich). | | **HERMES_BOUNDED_AUTONOMY** | **BLOCKED** | Erfordert SAVE/DELETE-Aktivierung, die wiederum Boundary-Fix + Gap-Schließung voraussetzt. | ### Kern-Blocker (zusammenfassend) 1. **CREDENTIAL_SEPARATION (Phase 3):** SAVE+DELETE laufen im selben Container (`06a4a73573d0`). RQ credential-free ist technisch NICHT erreichbar, solange beide Tokens in die ENV dieses Containers injiziert würden. → **HARD STOP für DELETE_CREDENTIAL_ACTIVATION.** 2. **HUMAN_APPROVAL_AUTHENTICITY_GAP (OPEN):** DELETE-Operation erst nach Gap-Schließung. → **BLOCKED für DELETE_OPERATION_ACTIVATION.** 3. **SERVER_AUTH_DEPLOYMENT** und **SAVE_ACTIVATION** sind CONDITIONALLY_READY (Code fertig), aber SAVE_ACTIVATION hängt an der Boundary-Frage. ### Empfohlene Reihenfolge (AUTH.4, nach Freigabe) 1. SERVER_AUTH_DEPLOYMENT (AUTH.2 aktivieren) — sicher, verschärft Gap nicht. 2. Boundary-Fix (C5-Caller in getrennten Container ODER RQ-undurchdringbare Injektion) — VORAUSSETZUNG für SAVE/DELETE-Credential-Aktivierung. 3. SAVE_ACTIVATION (nach Boundary-Fix). 4. Gap-Schließung (separate Freigabe). 5. DELETE_CREDENTIAL_ACTIVATION + DELETE_OPERATION_ACTIVATION (nach 2+4). --- ## 15. INCIDENT (AUTH.3B, 2026-08-27) **INCIDENT_OCCURRED = TRUE** (während Phase 1 Discovery) - Versehentlicher mutierender POST `POST /api/vault/save` gegen Produktion (`_auth3b_probe.md`, Inhalt "x") — Verstoß gegen die verbindliche Incident-Regel (NO MUTATING HTTP METHOD PROBES). - **INCIDENT_RECOVERED = TRUE** — Datei sofort via `POST /api/vault/delete` entfernt, Read-Back bestätigt: Datei existiert nicht mehr. - **PERMANENT_DAMAGE = NONE VERIFIED** - **ROOT_CAUSE = unsafe mutating endpoint probe during read-only discovery** - **BESTÄTIGT:** Produktion läuft OHNE AUTH.2 (save ohne Token → 200, kein 401). - **LEHRE:** Keine weiteren mutierenden POSTs. Nur read-only GET/Code-Reading.