Files
zero/internal/tools/bash_proc_windows.go
Anandan 518d2e53ba fix(windows): use PowerShell for command execution (#804)
* fix(windows): prefer PowerShell for command execution

Detect PowerShell 7 or Windows PowerShell before falling back to cmd.exe, and share the selected host shell across agent tools and the interactive shell escape.

Configure UTF-8 output, preserve restricted-sandbox MSYS safeguards, and add Windows coverage for pipelines, workspace writes, and interactive stdin sessions.

* test(windows): align shell coverage with PowerShell

Make Windows command fixtures and guidance assertions follow the selected host shell, preserve cmd fallback coverage, and use a genuine MSYS executable when PowerShell aliases are available.

Remove the unsupported non-TTY PowerShell stdin assertion; Windows interactive stdin requires a separate PTY transport.

* fix(sandbox): classify Windows executable suffixes

Normalize .exe, .cmd, .bat, and .com command names before safety and network lookup so PowerShell invocations such as curl.cmd receive the same network permission handling as curl.

Add analyzer and engine-level regressions for the Windows PowerShell command shape observed in CI.

* fix(sandbox): normalize absolute Windows command paths

Extract drive-letter and UNC basenames before removing shell escape characters so fully qualified Windows executables continue matching canonical safety and network classifications.

Cover both drive and UNC curl paths with analyzer regressions.

* fix(sandbox): normalize relative Windows paths

Recognize drive-relative, explicit relative, and suffixed backslash executable paths before generic shell escape removal so Windows commands continue to match canonical sandbox risk entries.

* fix(windows): harden PowerShell execution

* fix(sandbox): classify PowerShell removal aliases
2026-07-27 13:21:47 +05:30

44 lines
1.5 KiB
Go

//go:build windows
package tools
import (
"os/exec"
"syscall"
"time"
"github.com/Gitlawb/zero/internal/execution"
zeroSandbox "github.com/Gitlawb/zero/internal/sandbox"
)
// bashWaitDelay bounds how long Wait blocks for the I/O pipes to drain after the
// process has exited or the context's Cancel has run, so a backgrounded child
// holding the pipes cannot make Run() hang past the timeout. Var (not const) so
// tests can shorten it.
var bashWaitDelay = 2 * time.Second
// hardenProcessLifetime makes a Windows shell command killable as a process
// tree. cmd.exe starts helper commands as child processes, so killing only the
// shell can leave a long-running child alive and holding cwd/temp handles after
// Zero exits.
func hardenProcessLifetime(command *exec.Cmd) {
command.WaitDelay = bashWaitDelay
command.Cancel = func() error {
if command.Process == nil {
return nil
}
return execution.KillProcessTree(command.Process.Pid)
}
}
// applyWindowsShellCommandLine overrides the cmd.exe fallback's raw child
// command line so commandText reaches cmd.exe unescaped. PowerShell consumes
// ordinary argv quoting and must not take this path. Wrapped commands are
// handled after unwrapping by the Windows sandbox runner.
func applyWindowsShellCommandLine(command *exec.Cmd, commandText string, wrapped bool, cmdFallback bool) {
if wrapped || !cmdFallback {
return
}
command.SysProcAttr = &syscall.SysProcAttr{CmdLine: zeroSandbox.WindowsShellCommandLine(commandText)}
}