diff --git a/codex-rs/exec-server/src/fs_helper_main.rs b/codex-rs/exec-server/src/fs_helper_main.rs index d65ff32f8c..b8a488ac80 100644 --- a/codex-rs/exec-server/src/fs_helper_main.rs +++ b/codex-rs/exec-server/src/fs_helper_main.rs @@ -45,6 +45,9 @@ async fn run_main() -> Result<(), Box> { } async fn read_request_input() -> Result, Box> { + // Normal helper launches send the JSON request over stdin. The Windows + // sandbox capture path cannot pipe stdin into the sandboxed child, so it + // passes a temporary request-file path as the second helper argument. if let Some(path) = std::env::args_os().nth(2) { return Ok(tokio::fs::read(PathBuf::from(path)).await?); } diff --git a/codex-rs/exec-server/src/fs_sandbox.rs b/codex-rs/exec-server/src/fs_sandbox.rs index 992e2295e2..adc2dea7e0 100644 --- a/codex-rs/exec-server/src/fs_sandbox.rs +++ b/codex-rs/exec-server/src/fs_sandbox.rs @@ -85,6 +85,11 @@ impl FileSystemSandboxRunner { fn helper_exe_for_launch(&self) -> Result { #[cfg(target_os = "windows")] { + // Windows sandbox launch grants are prepared around the executable + // path that the sandbox will spawn. When exec-server is embedded or + // hosted, `current_exe()` can point at the host process instead of + // the configured Codex binary, so materialize the runtime-provided + // helper and use that exact path for both launch and read roots. let codex_home = codex_utils_home_dir::find_codex_home().map_err(|err| { internal_error(format!( "windows fs sandbox helper failed to resolve CODEX_HOME: {err}" @@ -377,6 +382,11 @@ fn write_windows_fs_helper_request_file( helper_program: &str, request_json: &[u8], ) -> Result { + // The Windows sandbox capture helpers expose argv/env/cwd/stdout/stderr, + // but not a stdin pipe. Write the helper request next to the materialized + // helper executable and pass that path as an argv item instead. That + // directory is already included in the helper read roots for the sandboxed + // child, and the file is removed after the capture returns. let helper_dir = std::path::Path::new(helper_program) .parent() .ok_or_else(|| { diff --git a/codex-rs/windows-sandbox-rs/src/helper_materialization.rs b/codex-rs/windows-sandbox-rs/src/helper_materialization.rs index bcc09f1250..ffc300e7ca 100644 --- a/codex-rs/windows-sandbox-rs/src/helper_materialization.rs +++ b/codex-rs/windows-sandbox-rs/src/helper_materialization.rs @@ -99,6 +99,13 @@ pub fn resolve_current_exe_for_launch(codex_home: &Path, fallback_executable: &s resolve_exe_for_launch(&source, codex_home) } +/// Returns the executable path that should be launched from a Windows sandbox. +/// +/// Windows sandbox launch setup may grant access to helper binaries under +/// CODEX_HOME/.sandbox-bin. Callers that already know the intended helper +/// binary should pass it here instead of relying on `current_exe()`, which can +/// name a host process rather than the Codex helper in embedded exec-server +/// scenarios. pub fn resolve_exe_for_launch(source: &Path, codex_home: &Path) -> PathBuf { let Some(file_name) = source.file_name() else { return source.to_path_buf();