Sicherheitsrunde II: PTY-Label, Tool-Grenzen, atomare Schreibvorgänge

- term_start nur noch für das eigene term-<projekt>-Fenster — das
  (abgelöste) Panel-Fenster kann keine Shell mehr starten und beschreiben.
  Die Tauri-ACL greift für App-Commands nachweislich nicht (kein
  __app-acl__-Manifest, Prüfung gegen tauri 2.11.5); die Label-Prüfung
  ist damit die Schranke, nicht deren Verdopplung.
- archive_panel verliert das dir-Argument: Archiv-Home samt dauerhafter
  Rechtevergabe (additionalDirectories + Edit-Allow) setzt nur noch die
  UI mit Nutzer-Dialog, kein Tool-Argument des Modells.
- write_panel(path) liest nur noch aus Projekt-, Arbeits- und
  Archiv-Ordnern (canonicalize, symlink-fest), reguläre Dateien bis 2 MB
  mit hartem Byte-Cap — der promptfreie Weg umgeht das
  Read-Permission-Modell von Claude Code nicht mehr.
- write_atomic (temp + rename) für alle JSON-Config-Schreiber: Projekt-
  Config, .claude/settings.json, Registry, App-Settings, pool.json,
  Pool-settings.json, claudes .claude.json, Todo-Hook.
- write_secret_file: create_new mit 0600 statt schreiben-und-abdichten;
  kein umask-Fenster, Symlinks werden nicht gefolgt.
- PTY-Umgebung: geerbte ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN entfernt.
- panel_file & Geschwister prüfen die Projekt-ID (zweite Linie).
- Befehlskacheln filtern Bidi-/Zero-Width-Zeichen aus Anzeige und
  Zwischenablage; der Lösch-Abgleich behält den Originaltext.
This commit is contained in:
marcus hinz
2026-07-20 12:01:21 +02:00
parent 23f6562f50
commit b743de5f34
12 changed files with 196 additions and 47 deletions
+15 -3
View File
@@ -7,6 +7,13 @@
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
/// Entfernt Bidi- und Zero-Width-Steuerzeichen (U+200B200F, U+202A202E,
/// U+20602064, U+20662069, U+FEFF) aus Befehlstexten.
function stripInvisibles(s: string): string {
return s.replace(/[\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g, "");
}
interface CommandEntry {
cmd: string;
note?: string;
@@ -106,7 +113,7 @@ export function initCommandsView(
all.className = "cmd-all";
all.textContent = "Alle kopieren";
all.addEventListener("click", async () => {
await writeText(cmds.map((c) => c.cmd).join("\n"));
await writeText(cmds.map((c) => stripInvisibles(c.cmd)).join("\n"));
flash(all, "copied");
});
head.append(all);
@@ -114,13 +121,18 @@ export function initCommandsView(
block.append(head);
cmds.forEach((entry, j) => {
// Unsichtbare Steuerzeichen (Bidi, Zero-Width) aus Anzeige UND
// Kopie halten — sonst sieht der Nutzer einen anderen Befehl, als
// die Zwischenablage enthält. Der Lösch-Abgleich läuft weiter über
// den Original-String.
const visible = stripInvisibles(entry.cmd);
const tile = document.createElement("div");
tile.className = "cmd-tile";
const body = document.createElement("div");
body.className = "cmd-body";
const cmd = document.createElement("div");
cmd.className = "cmd-text";
cmd.textContent = entry.cmd;
cmd.textContent = visible;
body.append(cmd);
if (entry.note) {
const note = document.createElement("div");
@@ -128,7 +140,7 @@ export function initCommandsView(
note.textContent = entry.note;
body.append(note);
}
tile.append(body, copyBtn(() => entry.cmd), deleteBtn(() => onDelete(i, j, entry.cmd)));
tile.append(body, copyBtn(() => visible), deleteBtn(() => onDelete(i, j, entry.cmd)));
block.append(tile);
});
container.append(block);