fix(tools): clean up Windows exec merge leftovers + expand credentialed env (#963)

- shell.go: remove commented-out git conflict markers; restore load-bearing
  rationale for plain exec.Command vs CommandContext (process-group kill).
- credentialed_exec.go: pass through SYSTEMROOT, TEMP, APPDATA and other
  Windows runtime vars that native CLIs (gh, az, aws, npm) require. Missing
  SYSTEMROOT breaks networking/registry APIs in most Win32 programs. Switch
  to USERNAME (Windows) vs USER (POSIX) per platform convention.
This commit is contained in:
Viet Tran authored and GitHub committed 2026-04-19 14:23:26 +07:00
1 parent 2bc8e909f1
commit fe90f6fed9
2 files changed
+33 -21

No files matched your search

+29 -13
View File
@@ -496,25 +496,41 @@ func (t *ExecTool) executeCredentialedSandbox(ctx context.Context, absPath strin
// buildCredentialedEnv creates a minimal environment with injected credentials.
// Inherits PATH and HOME from parent process, adds credential env vars.
// On Windows, also passes through SYSTEMROOT / TEMP / APPDATA / etc. — these
// are not secrets and many native CLIs (gh, az, aws, npm) require them to run.
func buildCredentialedEnv(envMap map[string]string) []string {
var pathDefault string
var homeDefault string
var env []string
if runtime.GOOS == "windows" {
pathDefault = "C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem"
homeDefault = os.Getenv("USERPROFILE")
pathDefault := "C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem"
homeDefault := os.Getenv("USERPROFILE")
if homeDefault == "" {
homeDefault = "C:\\Users\\Default"
}
env = []string{
"PATH=" + getenvDefault("PATH", pathDefault),
"HOME=" + getenvDefault("HOME", homeDefault),
"LANG=" + getenvDefault("LANG", "en_US.UTF-8"),
"USERNAME=" + getenvDefault("USERNAME", "goclaw"),
}
// Pass through Windows runtime vars that native tools expect.
// Missing SYSTEMROOT breaks networking/registry in most Win32 programs.
for _, k := range []string{
"SYSTEMROOT", "SYSTEMDRIVE", "WINDIR", "COMSPEC", "PATHEXT",
"TEMP", "TMP", "USERPROFILE", "APPDATA", "LOCALAPPDATA",
"PROGRAMFILES", "PROGRAMFILES(X86)", "PROGRAMDATA",
"HOMEDRIVE", "HOMEPATH", "COMPUTERNAME",
} {
if v := os.Getenv(k); v != "" {
env = append(env, k+"="+v)
}
}
} else {
pathDefault = "/usr/local/bin:/usr/bin:/bin"
homeDefault = "/tmp"
}
env := []string{
"PATH=" + getenvDefault("PATH", pathDefault),
"HOME=" + getenvDefault("HOME", homeDefault),
"LANG=" + getenvDefault("LANG", "en_US.UTF-8"),
"USER=" + getenvDefault("USER", "goclaw"),
env = []string{
"PATH=" + getenvDefault("PATH", "/usr/local/bin:/usr/bin:/bin"),
"HOME=" + getenvDefault("HOME", "/tmp"),
"LANG=" + getenvDefault("LANG", "en_US.UTF-8"),
"USER=" + getenvDefault("USER", "goclaw"),
}
}
for k, v := range envMap {
env = append(env, k+"="+v)
+4 -8
View File
@@ -361,19 +361,15 @@ func (t *ExecTool) executeOnHost(ctx context.Context, command, cwd string) *Resu
ctx, cancel := context.WithTimeout(ctx, t.timeout)
defer cancel()
//<<<<<<< HEAD
// Use plain exec.Command (not CommandContext) so we control the kill sequence.
// CommandContext would SIGKILL only the direct child, leaving forked grandchildren alive.
// Route through the platform shell: cmd.exe on Windows, sh on POSIX.
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("cmd", "/c", command)
cmd = exec.Command("cmd", "/C", command)
} else {
cmd = exec.Command("sh", "-c", command)
}
//=======
// Use plain exec.Command (not CommandContext) so we control the kill sequence.
// CommandContext would SIGKILL only the direct child, leaving forked grandchildren alive.
// cmd := exec.Command("sh", "-c", command)
//>>>>>>> dev
cmd.Dir = cwd
// Scrub credential env vars so fall-through exec cannot exfiltrate