fix env var map mutation and add lowercase proxy vars

- Use maps.Clone in WithAllowedEnv and WithPicoclawEnvVars to avoid mutating caller's map
- Add lowercase http_proxy, https_proxy, no_proxy to default allowlist

Address PR #1261 feedback.

💘 Generated with Crush

Assisted-by: MiniMax-M2.5 via Crush <crush@charm.land>
This commit is contained in:
Keith Patrick 2026-03-20 05:07:47 +00:00
parent 806825a04e
commit 9f1868d717

View file

@ -1,6 +1,7 @@
package shell
import (
"maps"
"os"
"path/filepath"
"runtime"
@ -33,8 +34,11 @@ var DefaultEnvAllowlist = map[string]bool{
"EDITOR": true,
"PAGER": true,
"HTTP_PROXY": true,
"http_proxy": true,
"HTTPS_PROXY": true,
"https_proxy": true,
"NO_PROXY": true,
"no_proxy": true,
// Locale
"LC_ALL": true,
@ -93,8 +97,8 @@ var windowsEnvAllowlist = map[string]bool{
// It starts with the provided env map, then adds allowed inherited vars (if not set).
// extraAllowlist adds to the default allowlist.
func WithAllowedEnv(envSet map[string]string, extraAllowlist []string) map[string]string {
// Start with provided envSet map
result := envSet
// Copy the map to avoid mutating the caller's map
result := maps.Clone(envSet)
if result == nil {
result = make(map[string]string)
}
@ -203,37 +207,39 @@ func envKey(k string) string {
// 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, workspace string) map[string]string {
if envSet == nil {
envSet = make(map[string]string)
// Copy the map to avoid mutating the caller's map
result := maps.Clone(envSet)
if result == nil {
result = make(map[string]string)
}
// Always compute PICOCLAW_* vars - priority: env var > default
if v := os.Getenv("PICOCLAW_HOME"); v != "" {
envSet["PICOCLAW_HOME"] = v
result["PICOCLAW_HOME"] = v
} else if home, _ := os.UserHomeDir(); home != "" {
envSet["PICOCLAW_HOME"] = filepath.Join(home, ".picoclaw")
result["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")
result["PICOCLAW_CONFIG"] = v
} else if home := result["PICOCLAW_HOME"]; home != "" {
result["PICOCLAW_CONFIG"] = filepath.Join(home, "config.json")
}
// Workspace - this is the agent's working directory
if workspace != "" {
envSet["PICOCLAW_AGENT_WORKSPACE"] = workspace
result["PICOCLAW_AGENT_WORKSPACE"] = workspace
}
if exe, err := os.Executable(); err == nil {
envSet["PICOCLAW_EXE"] = exe
result["PICOCLAW_EXE"] = exe
}
if v := os.Getenv("PICOCLAW_SERVICE_NAME"); v != "" {
envSet["PICOCLAW_SERVICE_NAME"] = v
result["PICOCLAW_SERVICE_NAME"] = v
} else {
envSet["PICOCLAW_SERVICE_NAME"] = "picoclaw"
result["PICOCLAW_SERVICE_NAME"] = "picoclaw"
}
return envSet
return result
}