fix: preserve terminal env vars through sudo in macOS daemon mode
sudo resets the environment, stripping TERM, COLORTERM, COLUMNS, LINES, and other terminal-related variables that TUI apps need to render. This caused TUI apps like opencode to show a blank screen in daemon mode. Fix by injecting terminal and proxy env vars via `env` after `sudo` in the daemon mode command pipeline. Also move PTY device ioctl/read/write rules into the base sandbox profile so inherited terminals work without requiring AllowPty.
This commit is contained in:
@@ -556,6 +556,7 @@ func GenerateSandboxProfile(params MacOSSandboxParams) string {
|
||||
(allow file-ioctl (literal "/dev/urandom"))
|
||||
(allow file-ioctl (literal "/dev/dtracehelper"))
|
||||
(allow file-ioctl (literal "/dev/tty"))
|
||||
(allow file-ioctl (regex #"^/dev/ttys"))
|
||||
|
||||
(allow file-ioctl file-read-data file-write-data
|
||||
(require-all
|
||||
@@ -564,6 +565,9 @@ func GenerateSandboxProfile(params MacOSSandboxParams) string {
|
||||
)
|
||||
)
|
||||
|
||||
; Inherited terminal access (TUI apps need read/write on the actual PTY device)
|
||||
(allow file-read-data file-write-data (regex #"^/dev/ttys"))
|
||||
|
||||
`)
|
||||
|
||||
// Network rules
|
||||
@@ -630,19 +634,13 @@ func GenerateSandboxProfile(params MacOSSandboxParams) string {
|
||||
profile.WriteString(rule + "\n")
|
||||
}
|
||||
|
||||
// PTY support
|
||||
// PTY allocation support (creating new pseudo-terminals)
|
||||
if params.AllowPty {
|
||||
profile.WriteString(`
|
||||
; Pseudo-terminal (pty) support
|
||||
; Pseudo-terminal allocation (pty) support
|
||||
(allow pseudo-tty)
|
||||
(allow file-ioctl
|
||||
(literal "/dev/ptmx")
|
||||
(regex #"^/dev/ttys")
|
||||
)
|
||||
(allow file-read* file-write*
|
||||
(literal "/dev/ptmx")
|
||||
(regex #"^/dev/ttys")
|
||||
)
|
||||
(allow file-ioctl (literal "/dev/ptmx"))
|
||||
(allow file-read* file-write* (literal "/dev/ptmx"))
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -738,9 +736,16 @@ func WrapCommandMacOS(cfg *config.Config, command string, exposedPorts []int, da
|
||||
// pf routes all traffic from group _greywall through utun → tun2socks → proxy.
|
||||
// Using -u #<uid> preserves the user's identity (home dir, SSH keys, etc.)
|
||||
// while -g _greywall sets the effective GID for pf matching.
|
||||
//
|
||||
// sudo resets the environment, so we use `env` after sudo to re-inject
|
||||
// terminal vars (TERM, COLORTERM, etc.) needed for TUI apps and proxy vars.
|
||||
uid := fmt.Sprintf("#%d", os.Getuid())
|
||||
parts = append(parts, "sudo", "-u", uid, "-g", daemonSession.SandboxGroup,
|
||||
"sandbox-exec", "-p", profile, shellPath, "-c", command)
|
||||
proxyEnvs := GenerateProxyEnvVars(cfg.Network.ProxyURL)
|
||||
termEnvs := getTerminalEnvVars()
|
||||
parts = append(parts, "sudo", "-u", uid, "-g", daemonSession.SandboxGroup, "env")
|
||||
parts = append(parts, proxyEnvs...)
|
||||
parts = append(parts, termEnvs...)
|
||||
parts = append(parts, "sandbox-exec", "-p", profile, shellPath, "-c", command)
|
||||
} else {
|
||||
// Non-daemon mode: use proxy env vars for best-effort proxying.
|
||||
proxyEnvs := GenerateProxyEnvVars(cfg.Network.ProxyURL)
|
||||
|
||||
Reference in New Issue
Block a user