From 347aade2fb40c25801f8f864368aebb185fc3cfc Mon Sep 17 00:00:00 2001 From: Keith Patrick Date: Mon, 9 Mar 2026 01:03:24 +0000 Subject: [PATCH] Add PICOCLAW_* env vars to child processes - Ensure PICOCLAW_HOME, PICOCLAW_CONFIG, PICOCLAW_EXE, PICOCLAW_SERVICE_NAME are passed to exec'd child processes - Remove hardcoded PICOCLAW_* from DefaultEnvAllowlist (now handled dynamically) --- pkg/tools/shell.go | 3 +++ pkg/tools/shell/env.go | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index b0405f763..b9103234f 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -148,6 +148,9 @@ func NewExecToolWithConfig(workingDir string, restrict bool, config *config.Conf envAllowlist = config.Tools.Exec.EnvAllowlist } + // Ensure PICOCLAW_* vars are set for child processes + envSet = shell.WithPicoclawEnvVars(envSet) + return &ExecTool{ workingDir: workingDir, timeout: timeout, diff --git a/pkg/tools/shell/env.go b/pkg/tools/shell/env.go index 40b1f61a5..8b2bc89e4 100644 --- a/pkg/tools/shell/env.go +++ b/pkg/tools/shell/env.go @@ -2,6 +2,7 @@ package shell import ( "os" + "path/filepath" "runtime" "strings" ) @@ -34,10 +35,6 @@ var DefaultEnvAllowlist = map[string]bool{ "HTTP_PROXY": true, "HTTPS_PROXY": true, "NO_PROXY": true, - "PICOCLAW_HOME": true, - "PICOCLAW_CONFIG": true, - "PICOCLAW_SERVICE_NAME": true, - "PICOCLAW_EXE": true, } // defaultEnvAllowPrefixes are env var prefixes that are always allowed. @@ -156,3 +153,36 @@ func isAllowedPrefix(name string) bool { } return false } + +// WithPicoclawEnvVars ensures PICOCLAW_* vars are set in envSet. +// These are needed for child processes to locate config, workspace, etc. +func WithPicoclawEnvVars(envSet map[string]string) map[string]string { + if envSet == nil { + envSet = make(map[string]string) + } + + // Always compute PICOCLAW_* vars - priority: env var > default + if v := os.Getenv("PICOCLAW_HOME"); v != "" { + envSet["PICOCLAW_HOME"] = v + } else if home, _ := os.UserHomeDir(); home != "" { + envSet["PICOCLAW_HOME"] = filepath.Join(home, ".picoclaw") + } + + if v := os.Getenv("PICOCLAW_CONFIG"); v != "" { + envSet["PICOCLAW_CONFIG"] = v + } else if home := envSet["PICOCLAW_HOME"]; home != "" { + envSet["PICOCLAW_CONFIG"] = filepath.Join(home, "config.json") + } + + if exe, err := os.Executable(); err == nil { + envSet["PICOCLAW_EXE"] = exe + } + + if v := os.Getenv("PICOCLAW_SERVICE_NAME"); v != "" { + envSet["PICOCLAW_SERVICE_NAME"] = v + } else { + envSet["PICOCLAW_SERVICE_NAME"] = "picoclaw" + } + + return envSet +}