From d5033b4aaf66beb6c7ffafe6a15b6920f1acfe13 Mon Sep 17 00:00:00 2001 From: codebit0 <34156842+codebit0@users.noreply.github.com> Date: Sun, 21 Jun 2026 09:03:48 +0900 Subject: [PATCH] fix(exec): exempt venv python interpreter from .goclaw/ path deny (#1140) The ExecTool path-deny rule blocks any token containing `.goclaw/` unless it matches one of the AllowPathExemptions prefixes (skills-store, tenants). This silently rejected legitimate commands invoking the goclaw-managed Python interpreter via its absolute path: /home/user/.goclaw/venv/bin/python3 .../script.py The first token `/home/user/.goclaw/venv/bin/python3` matched the deny pattern but no exemption, so the entire command was denied. Naive exemption (".goclaw/venv/bin/") does not work: matchesAnyPathExemption resolves both tokens and exemption candidates via EvalSymlinks, and the venv's python3 is a symlink into the host's python cellar (e.g. linuxbrew). The token canonicalizes to /home/linuxbrew/.../python3.14 while a literal ".goclaw/venv/bin/" prefix never gets touched. Fix: resolve venv/bin/python3 once at startup and exempt the dirname of the resolved target. Failure to resolve (no venv present) silently falls through. Without this, ACP-driven agents either fail outright or work only via fragile heuristics (cwd-local symlinks generated on the fly by the LLM). Co-authored-by: Claude Opus 4.7 (1M context) --- cmd/gateway_setup.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmd/gateway_setup.go b/cmd/gateway_setup.go index 3f6ac2a4..1e212e45 100644 --- a/cmd/gateway_setup.go +++ b/cmd/gateway_setup.go @@ -222,6 +222,14 @@ func setupToolRegistry( filepath.Join(dataDir, "skills-store")+"/", filepath.Join(dataDir, "tenants")+"/", ) + // Allow the goclaw-managed Python venv interpreter to be invoked with its + // absolute path. venv/bin/python3 is a symlink to the real interpreter + // (e.g. linuxbrew cellar), and matchesAnyPathExemption resolves symlinks + // before comparing — so we must exempt the *resolved* target dir. + // Resolved at startup; falls back silently if venv not present. + if real, err := filepath.EvalSymlinks(filepath.Join(filepath.Dir(dataDir), "venv", "bin", "python3")); err == nil { + et.AllowPathExemptions(filepath.Dir(real) + "/") + } // Harden: block access to internal workspace files via shell commands. // Prevents `cat ../config.json`, `cat memory.db` etc. from user workspaces. et.DenyPaths(