Launch Linux pipe processes through a fresh setup helper (#47612)

## Why

Linux pipe launches need session, parent-death signal, and descriptor setup. Move this work into a fresh, single-threaded executable image to avoid forking the app-server for child setup.

## What changed

- Register an early setup helper and launch it through `posix_spawn` for Linux pipe processes.
- Start the helper with an empty environment, then transfer the target environment over a control socket so loader settings cannot interfere with helper startup.
- Await target execution asynchronously, propagate setup and execution errors, and kill incomplete launches on cancellation.
- Preserve direct spawning as a fallback when the helper is unavailable or fails before target execution.

## Testing

Add coverage for launch semantics, avoiding fork, loader environment isolation, early argument dispatch, closed standard descriptors, and fallback under bootstrap failure or descriptor pressure. Add an app-server regression test that reuses a process handle after an execution failure.

GitOrigin-RevId: 079c673f0f22ebd531f8c57e5338095cc98acfdc
This commit is contained in:
Free Wortley
2026-09-23 18:25:07 +00:00
committed by copyberry
parent 60f0ab6cbf
commit df3ecee6f0
15 changed files with 674 additions and 5 deletions
+14
View File
@@ -1251,6 +1251,20 @@ mod tests {
#[cfg(not(target_os = "windows"))]
use crate::protocol::NetworkPolicyRequestResponse;
#[cfg(target_os = "linux")]
#[ctor::ctor]
fn initialize_spawn_helper() {
use std::os::unix::ffi::OsStringExt;
let command_line = std::fs::read("/proc/self/cmdline").expect("test command line");
codex_utils_pty::init_spawn_helper(
command_line
.strip_suffix(&[0])
.unwrap_or(&command_line)
.split(|byte| *byte == 0)
.map(|arg| std::ffi::OsString::from_vec(arg.to_vec())),
);
}
fn test_exec_params(env: HashMap<String, String>) -> ExecParams {
ExecParams {
metadata: None,