remove granular tool permissions, add architecture docs
Granulare Tool-Permissions in der Diagnostic UI entfernt — sie hatten keinen Effekt weil Claude Code mit --dangerously-skip-permissions läuft (Alles-oder-Nichts). Ersetzt durch statischen Hinweis-Toggle. Neue Doku in aria-data/docs/tool-permissions.md: alle Erkenntnisse zu OpenClaw Tool-Permissions, 17 gescheiterte Versuche, finale Lösung (CLAUDE_CODE_BUBBLEWRAP=1). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+4
-169
@@ -990,10 +990,7 @@ wss.on("connection", (ws) => {
|
||||
} else if (msg.action === "read_brain_file") {
|
||||
handleReadBrainFile(ws, msg.filename);
|
||||
// ── Einstellungen ──
|
||||
} else if (msg.action === "list_permissions") {
|
||||
handleListPermissions(ws);
|
||||
} else if (msg.action === "save_permissions") {
|
||||
handleSavePermissions(ws, msg.allowedTools);
|
||||
// list_permissions / save_permissions entfernt — Alles-oder-Nichts via --dangerously-skip-permissions
|
||||
} else if (msg.action === "get_model") {
|
||||
handleGetModel(ws);
|
||||
} else if (msg.action === "set_model") {
|
||||
@@ -1448,171 +1445,9 @@ async function handleReadBrainFile(clientWs, filename) {
|
||||
}
|
||||
|
||||
// ── Einstellungen: Tool-Berechtigungen ──────────────────
|
||||
|
||||
const OPENCLAW_SETTINGS_PATHS = [
|
||||
"/home/node/.openclaw/settings.json",
|
||||
"/home/node/.openclaw/agents/main/agent/settings.json",
|
||||
"/home/node/.openclaw/config.json",
|
||||
"/home/node/.claude/settings.json", // Claude Code User-Level
|
||||
"/home/node/.openclaw/workspace/.claude/settings.json", // Claude Code Projekt-Level
|
||||
];
|
||||
|
||||
async function findSettingsFile() {
|
||||
// Pruefen welche Settings-Dateien existieren
|
||||
try {
|
||||
const raw = await dockerExec("aria-core", `
|
||||
for f in ${OPENCLAW_SETTINGS_PATHS.join(" ")}; do
|
||||
[ -f "$f" ] && echo "FOUND:$f"
|
||||
done
|
||||
`.trim());
|
||||
for (const line of raw.split("\n")) {
|
||||
if (line.startsWith("FOUND:")) return line.slice(6);
|
||||
}
|
||||
} catch {}
|
||||
// Default: erster Pfad (wird erstellt)
|
||||
return OPENCLAW_SETTINGS_PATHS[0];
|
||||
}
|
||||
|
||||
async function handleListPermissions(clientWs) {
|
||||
try {
|
||||
log("info", "server", "Lade Tool-Berechtigungen...");
|
||||
|
||||
// Alle moeglichen Settings-Dateien pruefen (Debug-Info)
|
||||
let allPaths = "";
|
||||
try {
|
||||
allPaths = await dockerExec("aria-core", `
|
||||
for f in ${OPENCLAW_SETTINGS_PATHS.join(" ")}; do
|
||||
if [ -f "$f" ]; then
|
||||
echo "EXISTS: $f ($(wc -c < "$f") bytes)"
|
||||
else
|
||||
echo "MISSING: $f"
|
||||
fi
|
||||
done
|
||||
`.trim());
|
||||
} catch {}
|
||||
|
||||
const settingsPath = await findSettingsFile();
|
||||
let settings = {};
|
||||
let rawContent = "";
|
||||
let info = "";
|
||||
|
||||
try {
|
||||
rawContent = await dockerExec("aria-core", `cat '${settingsPath}' 2>/dev/null || echo '{}'`);
|
||||
settings = JSON.parse(rawContent.trim() || "{}");
|
||||
info = `Geladen aus: ${settingsPath}`;
|
||||
} catch (e) {
|
||||
info = `Settings-Datei nicht lesbar (${settingsPath}) — Default-Berechtigungen`;
|
||||
}
|
||||
|
||||
// OpenClaw/Claude Code Format: allowedTools ist ein Array von Tool-Namen
|
||||
// Wenn leer/nicht vorhanden: alle Tools erlaubt
|
||||
const allowedTools = settings.allowedTools || [];
|
||||
const permissions = settings.permissions || {};
|
||||
|
||||
clientWs.send(JSON.stringify({
|
||||
type: "permissions_list",
|
||||
allowedTools,
|
||||
permissions,
|
||||
settingsPath,
|
||||
info,
|
||||
debug: { allPaths: allPaths.trim(), rawKeys: Object.keys(settings).join(", ") },
|
||||
}));
|
||||
log("info", "server", `Berechtigungen geladen (${allowedTools.length} Tools explizit erlaubt) aus ${settingsPath}`);
|
||||
if (allPaths) log("info", "server", `Settings-Dateien:\n${allPaths}`);
|
||||
} catch (err) {
|
||||
log("error", "server", `Berechtigungen laden fehlgeschlagen: ${err.message}`);
|
||||
clientWs.send(JSON.stringify({ type: "permissions_list", error: err.message, allowedTools: [], permissions: {} }));
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSavePermissions(clientWs, allowedTools) {
|
||||
if (!Array.isArray(allowedTools)) {
|
||||
clientWs.send(JSON.stringify({ type: "permissions_saved", ok: false, error: "Ungueltige Daten" }));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
log("info", "server", `Speichere ${allowedTools.length} Tool-Berechtigungen in alle Settings-Pfade`);
|
||||
|
||||
// In ALLE moeglichen Pfade schreiben, in BEIDEN Formaten:
|
||||
// 1. allowedTools: ["Bash", "Read", ...] — OpenClaw Format
|
||||
// 2. permissions.allow: ["Bash(*)", "Read(*)", ...] — Claude Code Format
|
||||
const script = [
|
||||
'const fs=require("fs");const path=require("path");',
|
||||
`const paths=${JSON.stringify(OPENCLAW_SETTINGS_PATHS)};`,
|
||||
`const tools=${JSON.stringify(allowedTools)};`,
|
||||
// Claude Code Format: Tool-Namen mit (*) Glob-Pattern
|
||||
'const ccAllow=tools.map(t=>t+"(*)");',
|
||||
'const ok=[];const fail=[];',
|
||||
'for(const f of paths){try{',
|
||||
'let s={};try{s=JSON.parse(fs.readFileSync(f,"utf8"));}catch(e){}',
|
||||
's.allowedTools=tools;',
|
||||
'if(!s.permissions)s.permissions={};',
|
||||
's.permissions.allow=ccAllow;',
|
||||
's.permissions.deny=[];',
|
||||
'const dir=path.dirname(f);',
|
||||
'try{fs.mkdirSync(dir,{recursive:true});}catch(e){}',
|
||||
'fs.writeFileSync(f,JSON.stringify(s,null,2));',
|
||||
'ok.push(f);',
|
||||
'}catch(e){fail.push(f+": "+e.message);}}',
|
||||
// Verify: nur erfolgreiche Pfade zuruecklesen
|
||||
'const result={ok:[],fail:fail,verified:{}};',
|
||||
'for(const f of ok){',
|
||||
'try{const d=JSON.parse(fs.readFileSync(f,"utf8"));',
|
||||
'result.verified[f]={allowedTools:d.allowedTools||[],permsAllow:(d.permissions&&d.permissions.allow)||[]};}',
|
||||
'catch(e){result.fail.push(f+": verify-read "+e.message);}',
|
||||
'}',
|
||||
'result.ok=ok;',
|
||||
'process.stdout.write(JSON.stringify(result));',
|
||||
].join("");
|
||||
const b64 = Buffer.from(script).toString("base64");
|
||||
const verifyRaw = await dockerExec("aria-core", `echo ${b64} | base64 -d | node`);
|
||||
|
||||
// Verify: gespeicherte Daten pruefen
|
||||
let verifyResult = {};
|
||||
let verified = false;
|
||||
let verifyDetails = [];
|
||||
try {
|
||||
verifyResult = JSON.parse(verifyRaw.trim());
|
||||
// Mindestens ein Pfad muss erfolgreich sein
|
||||
verified = verifyResult.ok && verifyResult.ok.length > 0;
|
||||
for (const f of (verifyResult.fail || [])) {
|
||||
verifyDetails.push(`FEHLER: ${f}`);
|
||||
}
|
||||
for (const [fpath, data] of Object.entries(verifyResult.verified || {})) {
|
||||
const ok = data.allowedTools.length === allowedTools.length
|
||||
&& allowedTools.every(t => data.allowedTools.includes(t));
|
||||
const ccOk = data.permsAllow.length === allowedTools.length;
|
||||
verifyDetails.push(`${fpath}: allowedTools=${ok?"OK":"FEHLER"} permissions.allow=${ccOk?"OK":"FEHLER"} (${data.allowedTools.length}/${data.permsAllow.length} Tools)`);
|
||||
if (!ok) verified = false;
|
||||
}
|
||||
} catch (e) {
|
||||
verifyDetails.push(`Parse-Fehler: ${e.message} — Raw: ${verifyRaw.substring(0, 200)}`);
|
||||
}
|
||||
log("info", "server", `Verify:\n${verifyDetails.join("\n")}`);
|
||||
|
||||
if (!verified) {
|
||||
clientWs.send(JSON.stringify({
|
||||
type: "permissions_saved", ok: false,
|
||||
error: `Verify fehlgeschlagen:\n${verifyDetails.join("\n")}`,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
const okCount = (verifyResult.ok || []).length;
|
||||
const failCount = (verifyResult.fail || []).length;
|
||||
const infoMsg = `${allowedTools.length} Tools gespeichert (${okCount} Pfade OK` + (failCount ? `, ${failCount} fehlgeschlagen` : '') + ')';
|
||||
clientWs.send(JSON.stringify({
|
||||
type: "permissions_saved", ok: true,
|
||||
info: infoMsg,
|
||||
details: verifyDetails,
|
||||
needsRestart: true,
|
||||
}));
|
||||
log("info", "server", infoMsg);
|
||||
} catch (err) {
|
||||
log("error", "server", `Berechtigungen speichern fehlgeschlagen: ${err.message}`);
|
||||
clientWs.send(JSON.stringify({ type: "permissions_saved", ok: false, error: err.message }));
|
||||
}
|
||||
}
|
||||
// ENTFERNT: Granulare Permissions haben nie funktioniert.
|
||||
// Claude Code laeuft mit --dangerously-skip-permissions (Alles oder Nichts).
|
||||
// Root-Check wird via CLAUDE_CODE_BUBBLEWRAP=1 in docker-compose.yml umgangen.
|
||||
|
||||
// ── Einstellungen: Model ────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user