# Offene Punkte — bei jedem Start prüfen und abhaken - [x] **„Projekt hinzufügen" verliert `archiveHome` — Ursache gefunden, behoben.** Der Verdacht (Add-Projekt-Pfad) war falsch. Ursache war ein verlustbehafteter Config-Round-Trip: `read_project_config_in` deserialisiert in `ProjectConfig`, serde verwirft dabei still jeden unbekannten Key, und `write_project_config_in` schreibt die Datei komplett neu. Geschrieben hat die Pool-Zuweisung (`ProjectList.vue:113` → `assign_pool_in`), ausgeführt von einem **älteren Build ohne das Feld `archive_home`** — daher der Halbzustand mit erhaltener Berechtigung in `.claude/settings.json` (anderer Schreibpfad). Fix: `#[serde(flatten)] rest` in `ProjectConfig` reicht unbekannte Keys unverändert durch; Regressionstest `pool_zuweisen_erhaelt_fremde_keys`. Einschränkung: Die Versionsdifferenz ist aus Zeitstempeln erschlossen, das alte Binary war schon überschrieben. Der Defekt selbst ist am Code belegt. Ursprünglicher Befund 2026-07-19 (claude-ai-control): - `archive/` existiert seit 21:03 samt Testdokument, war also gesetzt. - `.claude/settings.json` hat den Eintrag noch: `additionalDirectories: ~/claude-projects/claude-ai-control/archive` (geschrieben von `add_archive_permission`, archive.rs:56). - `ai-control.json` hat **kein** `archiveHome` mehr, mtime 21:18. - Halbzustand Recht-ohne-Config kann nicht vom Abwählen-Button kommen: `clear_project_archive_home` (archive.rs:96-104) nimmt beides zurück. - Folge: `panel-wiring.ts:45` blendet Wiki- und Suche-Tab aus. Zu prüfen war: Schreibpfade auf `PROJECT_FILE` in `domain/project.rs` (`write_project_config_in`, project.rs:81) — welcher davon eine frische Config ohne `archive_home` schreibt. - [ ] **Command-History braucht eine Identität statt Indizes.** Aufgefallen beim Fix von `commands_delete` (Panik bei Doppelklick, Löschen der falschen Kachel). Der Fix schickt jetzt den Befehlstext mit und gleicht serverseitig ab — das verhindert Schaden, ist aber nur ein Notnagel: Zwei identische Befehle im selben Record sind nicht unterscheidbar, und die Panel-Indizes hinken der Datei weiter um bis zu ein Watcher-Intervall (200 ms) hinterher. Sauber wäre eine ID je Eintrag beim Schreiben. - [ ] **`csp: null` in `tauri.conf.json` ersetzen.** Aufgefallen beim XSS-Fix: Es gibt keine zweite Schranke. Das Panel liegt im selben Webview wie das Terminal, dessen `term_write` die PTY über das Fensterlabel adressiert — eingeschleustes Skript könnte in die laufende Shell schreiben. Das Markdown-Rendering ist jetzt entschärft (`src/markdown.ts`), aber eine echte CSP wäre die Schranke dahinter. Braucht eine Runde Prüfen, was inline benötigt wird (Themes, xterm). Schon ein `default-src 'self'` würde auswärtige Requests und die Fremdnavigation unabhängig vom Sanitizer abschneiden. ## Aus der Sicherheitsrunde 2026-07-19 (vier Angriffsflächen geprüft) Behoben und gepusht (6d44f77): Befehlsinjektion im SessionStart-Hook über den Projektpfad, ungeprüfter Pool-Name als `CLAUDE_CONFIG_DIR`, `check_name` gegen Steuerzeichen (`.desktop`-Injektion), Bild-Beacon im Panel. Dazu `cargo audit` nachgeholt: `plist` auf 1.10.0, `quick-xml` auf 0.41.0 im Laufzeitpfad. Offen sind die vier Punkte, die eine Designentscheidung brauchen: - [ ] **`term_start` prüft das Fenster-Label nicht (`terminal.rs:96-211`).** Jedes Fenster des Terminal-Prozesses kann sich selbst in die Terminals-Map eintragen (Schlüssel ist `window.label()`, Zeile 207-210) und danach per `term_write` in eine frisch gestartete Shell schreiben. Damit ist auch das abgelöste Panel-Fenster gefährlich, nicht nur das angedockte — und jedes Skript im Webview wird zu Codeausführung, auch ohne XSS. Zu entscheiden: Soll das Panel-Fenster je ein eigenes Terminal starten dürfen? Wenn nein, ist die Prüfung auf `term-*` ein enger Fix. Strukturell dahinter: Die Fenster-ACL scheint für App-Commands nicht zu greifen (`gen/schemas/acl-manifests.json` enthält kein App-Manifest) — **vor dem Bauen darauf verifizieren**, die beiden Prüfagenten waren sich in diesem Punkt uneins. - [ ] **`write_panel(path)` liest jede Datei, ohne Rückfrage (`mcp.rs:256-259`).** Keine Prüfung gegen Projektordner oder Archiv-Home. Das Tool steht in `PANEL_PERMISSIONS` (`pool.rs:185-188`), läuft also prompt-frei — und umgeht damit das Read-Permission-Modell von Claude Code (`~/.ssh/id_rsa`, `.credentials.json`, fremde `.env`). Rückkanal zum Modell besteht über `write_panel` → `archive_panel` → `search_archive`. Zu entscheiden: Allowlist (Projektordner + Archiv-Home, nach `canonicalize`) oder `path` aus der prompt-freien Freigabe nehmen. Zusätzlich fehlt ein Größenlimit (`path=/dev/zero` hängt den Prozess). - [ ] **`archive_panel(dir)` vergibt dauerhaft Schreibrechte (`archive.rs:33-91`).** `dir` ist nicht nur Ablageort: Über `set_project_archive_home` → `add_archive_permission` landet `additionalDirectories += dir` **und** `allow += "Edit(dir/**)"` in der `.claude/settings.json` des Projekts. Der einzige Guard (archive.rs:41) lehnt nur Vorfahren des Home ab — `~/.claude` passiert, womit die nächste Session eigene **Hooks** schreiben darf. `create_dir_all` legt das Ziel vorher an. Vorschlag: `dir` aus dem MCP-Tool entfernen, Archiv-Home nur über die UI. - [ ] **Nicht-atomare Schreibvorgänge auf fremde Dateien.** Überall `fs::write` (truncate + write), nirgends temp + `rename`. Betrifft u. a. die `.claude/settings.json` der Projekte, Claudes `.claude.json` in den Pools (`pool.rs:289`), die Registry und die App-Settings. Die Leseseite haben wir gehärtet, die Schreibseite nicht: Absturz oder volle Platte hinterlässt abgeschnittenes JSON in Dateien, die der App nicht gehören. Kleinere Punkte aus derselben Runde, bewusst zurückgestellt: `panel_file` und Geschwister (`paths.rs:55-84`) ohne `check_name` (zweite Linie); `write_secret_file` (`unix.rs:48-55`) schreibt erst mit umask-Rechten und setzt danach 0600, `create_new` mit Modus löst das samt Symlink-Frage; API-Key steht unter macOS kurz in der Prozess-Kommandozeile (`macos.rs:101-103`, `ps`-sichtbar, Linux/Windows nicht betroffen); die PTY-Umgebung wird nicht bereinigt (`terminal.rs:134-144`, kein `env_clear` — ein `ANTHROPIC_API_KEY` aus dem Shell-Profil sticht den Pool-`apiKeyHelper`); Bidi-/Zero-Width-Zeichen in den Befehlskacheln (`commands-view.ts:123`), was Anzeige und Zwischenablage auseinanderlaufen lässt. Ausdrücklich **kein** Handlungsbedarf (Stand 2026-07-19): `sync_all_desktops` räumt `aicontrol-*.desktop` auf — der Präfix gehört uns. Falls es je stört, wäre `art.lintus.`-Präfix die saubere Variante. Nicht als Sicherheitsgrenze missverstehen: Pools trennen Konfiguration, nicht Zugriff. Die Keychain-Einträge sind bewusst über `/usr/bin/security` angelegt, damit der `apiKeyHelper` promptfrei liest — womit jeder Prozess des Nutzers jeden Pool-Key lesen kann. Beim Design so gewollt, aber nichts, worauf man Isolationsversprechen bauen sollte. - [ ] **`write_app_setting` verliert die übrigen App-Settings (`settings.rs:71`).** Dieselbe Fehlerklasse wie die `.claude.json` in `pool.rs`, nur eine Datei weiter — beim Simplify-Review gefunden, bewusst nicht mitgefixt. `read_app_settings` (settings.rs:11-14) wirft mit zweimal `.ok()?` fehlende Datei, Lesefehler und kaputtes JSON in denselben `None`; `write_app_setting` macht daraus `json!({})` und schreibt die Datei mit einem Key neu. Konkret: halb geschriebene `~/.config/ai-control/settings.json`, dann einmal Schriftgröße verstellen — `claudeCommand`, `poolSyncDir`, `syncOnSessionEnd` und `spellcheckLang` sind endgültig weg. Fix wie in `pool.rs`: nur eine *fehlende* Datei rechtfertigt ein frisches Objekt. - [ ] **`struct Pool` verliert unbekannte Keys beim Umbenennen (`pool.rs:20`).** Dritte Stelle derselben Klasse. `rename_pool_in` (pool.rs:402-408) liest typisiert in `Pool` (nur `name` + `credentialType`) und schreibt die ganze `pool.json` über `write_pool_json` neu — jeder künftige Key stirbt beim Umbenennen. `ProjectConfig` und `TerminalConfig` haben dafür inzwischen `#[serde(flatten)] rest`. Grundsätzlicher: `flatten` bildet pro Struct nach, was read-modify-write auf `serde_json::Value` von Natur aus kann (so macht es `add_archive_permission`, archive.rs:56-90). Statt es an jedem Struct einzeln zu wiederholen, wäre ein gemeinsamer Helfer die Lösung, die die Klasse wirklich schließt. - [ ] **Archiv-Dateinamen: `create_new` statt `exists()` (`archive.rs`, `free_path`).** Die Kollisionsprüfung schaut vorab nach (`exists()`), die Garantie liegt aber nicht im Schreibvorgang — klassisches TOCTOU. Als Einbenutzer-App folgenlos, **aber nicht mehr beim Maschinen-Sync**: Zwei Rechner können in derselben Minute mit derselben Titelzeile ins synchronisierte Archiv schreiben, und dann greift der Vorabblick zu spät. `OpenOptions::new().create_new(true)` in der Schleife gibt dieselbe Struktur, holt die Kollisionsfreiheit aber vom Dateisystem. Mitzudenken: Was der Sync-Mechanismus selbst bei zwei gleichen Namen macht (Konfliktkopien?) — der Fix deckt nur die lokale Seite. - [ ] **Projekt-Artefakte im Projektordner bündeln (`.ai-control/`?).** `ai-control.json` und das Projekt-Icon liegen heute lose im Projektordner. Idee: beides in ein Unterverzeichnis (z. B. `.ai-control/`) zusammenziehen, damit der Projektordner sauber bleibt und alles an einem Ort steht. Offen: Migrationspfad für bestehende Projekte, Rückwärtskompatibilität beim Lesen (altes Layout weiter erkennen). - [ ] **Migrations-Assistent: Projekt sauber löschen.** Löschen soll alle Ressourcen des Projekts aus dem Ordner entfernen (Config, Icon, ggf. Archiv-Rechte in `.claude/settings.json`, Registry-Eintrag in `projects.json`) — nicht nur den Registry-Eintrag. Vorher anzeigen, was entfernt wird. - [ ] **Archiv-Ordner-Handling sauber aufsetzen.** Beim Setzen eines Archiv-Homes explizit abfragen statt still anlegen: Zielordner bestätigen, bestehenden Inhalt erkennen, klarmachen was passiert. Wechsel eines bereits gesetzten Archiv-Homes braucht eine Migrationsmöglichkeit (Dokumente mitnehmen oder liegen lassen) — als kritisch einstufen: hier hängen echte Nutzerdaten dran, also nichts implizit verschieben oder überschreiben. - [ ] **`pool` gehört nicht in die projektbezogene `ai-control.json`.** Der Pool ist rechnerspezifisch: gleicher Claude-Account, aber pro Maschine ein anderer Pool. Versioniert im Projekt trägt die Datei die Zuordnung über Rechnergrenzen falsch weiter (aktuell steht dort die UUID `c39d96c9-…`, gepusht mit 5081efc). Zu klären: Trennung projektbezogen (archiveHome, Theme, Icon) vs. maschinenbezogen (pool). Optionen — projekt-lokale, nicht versionierte Datei, oder Pool pro Rechner zentral in der `projects.json`-Registry unter `~/.config/ai-control`. Nachdenken, noch keine Entscheidung.