feat: pass helper executable paths via Arg0DispatchPaths (#12719)

## Why

`codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs` previously
located `codex-execve-wrapper` by scanning `PATH` and sibling
directories. That lookup is brittle and can select the wrong binary when
the runtime environment differs from startup assumptions.

We already pass `codex-linux-sandbox` from `codex-arg0`;
`codex-execve-wrapper` should use the same startup-driven path plumbing.

## What changed

- Introduced `Arg0DispatchPaths` in `codex-arg0` to carry both helper
executable paths:
  - `codex_linux_sandbox_exe`
  - `main_execve_wrapper_exe`
- Updated `arg0_dispatch_or_else()` to pass `Arg0DispatchPaths` to
top-level binaries and preserve helper paths created in
`prepend_path_entry_for_codex_aliases()`.
- Threaded `Arg0DispatchPaths` through entrypoints in `cli`, `exec`,
`tui`, `app-server`, and `mcp-server`.
- Added `main_execve_wrapper_exe` to core configuration plumbing
(`Config`, `ConfigOverrides`, and `SessionServices`).
- Updated zsh-fork shell escalation to consume the configured
`main_execve_wrapper_exe` and removed path-sniffing fallback logic.
- Updated app-server config reload paths so reloaded configs keep the
same startup-provided helper executable paths.

## References

- [`Arg0DispatchPaths`
definition](e355b43d5c/codex-rs/arg0/src/lib.rs (L20-L24))
- [`arg0_dispatch_or_else()` forwarding both
paths](e355b43d5c/codex-rs/arg0/src/lib.rs (L145-L176))
- [zsh-fork escalation using configured wrapper
path](e355b43d5c/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs (L109-L150))

## Testing

- `cargo check -p codex-arg0 -p codex-core -p codex-exec -p codex-tui -p
codex-mcp-server -p codex-app-server`
- `cargo test -p codex-arg0`
- `cargo test -p codex-core tools::runtimes::shell::unix_escalation:: --
--nocapture`
This commit is contained in:
Michael Bolin
2026-02-24 17:44:38 -08:00
committed by GitHub
parent 448fb6ac22
commit e88f74d140
19 changed files with 184 additions and 112 deletions

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::path::PathBuf;
use codex_arg0::Arg0DispatchPaths;
use codex_core::AuthManager;
use codex_core::ThreadManager;
use codex_core::config::Config;
@@ -38,7 +38,7 @@ use crate::outgoing_message::OutgoingMessageSender;
pub(crate) struct MessageProcessor {
outgoing: Arc<OutgoingMessageSender>,
initialized: bool,
codex_linux_sandbox_exe: Option<PathBuf>,
arg0_paths: Arg0DispatchPaths,
thread_manager: Arc<ThreadManager>,
running_requests_id_to_codex_uuid: Arc<Mutex<HashMap<RequestId, ThreadId>>>,
}
@@ -48,7 +48,7 @@ impl MessageProcessor {
/// `Sender` so handlers can enqueue messages to be written to stdout.
pub(crate) fn new(
outgoing: OutgoingMessageSender,
codex_linux_sandbox_exe: Option<PathBuf>,
arg0_paths: Arg0DispatchPaths,
config: Arc<Config>,
) -> Self {
let outgoing = Arc::new(outgoing);
@@ -66,7 +66,7 @@ impl MessageProcessor {
Self {
outgoing,
initialized: false,
codex_linux_sandbox_exe,
arg0_paths,
thread_manager,
running_requests_id_to_codex_uuid: Arc::new(Mutex::new(HashMap::new())),
}
@@ -352,10 +352,7 @@ impl MessageProcessor {
let arguments = arguments.map(serde_json::Value::Object);
let (initial_prompt, config): (String, Config) = match arguments {
Some(json_val) => match serde_json::from_value::<CodexToolCallParam>(json_val) {
Ok(tool_cfg) => match tool_cfg
.into_config(self.codex_linux_sandbox_exe.clone())
.await
{
Ok(tool_cfg) => match tool_cfg.into_config(self.arg0_paths.clone()).await {
Ok(cfg) => cfg,
Err(e) => {
let result = CallToolResult {