mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
edacbf7b6e
zsh fork PR stack: - https://github.com/openai/codex/pull/12051 - https://github.com/openai/codex/pull/12052 👈 ### Summary This PR introduces a feature-gated native shell runtime path that routes shell execution through a patched zsh exec bridge, removing MCP-specific behavior from the shell hot path while preserving existing CommandExecution lifecycle semantics. When shell_zsh_fork is enabled, shell commands run via patched zsh with per-`execve` interception through EXEC_WRAPPER. Core receives wrapper IPC requests over a Unix socket, applies existing approval policy, and returns allow/deny before the subcommand executes. ### What’s included **1) New zsh exec bridge runtime in core** - Wrapper-mode entrypoint (maybe_run_zsh_exec_wrapper_mode) for EXEC_WRAPPER invocations. - Per-execution Unix-socket IPC handling for wrapper requests/responses. - Approval callback integration using existing core approval orchestration. - Streaming stdout/stderr deltas to existing command output event pipeline. - Error handling for malformed IPC, denial/abort, and execution failures. **2) Session lifecycle integration** SessionServices now owns a `ZshExecBridge`. Session startup initializes bridge state; shutdown tears it down cleanly. **3) Shell runtime routing (feature-gated)** When `shell_zsh_fork` is enabled: - Build execution env/spec as usual. - Add wrapper socket env wiring. - Execute via `zsh_exec_bridge.execute_shell_request(...)` instead of the regular shell path. - Non-zsh-fork behavior remains unchanged. **4) Config + feature wiring** - Added `Feature::ShellZshFork` (under development). - Added config support for `zsh_path` (optional absolute path to patched zsh): - `Config`, `ConfigToml`, `ConfigProfile`, overrides, and schema. - Session startup validates that `zsh_path` exists/usable when zsh-fork is enabled. - Added startup test for missing `zsh_path` failure mode. **5) Seatbelt/sandbox updates for wrapper IPC** - Extended seatbelt policy generation to optionally allow outbound connection to explicitly permitted Unix sockets. - Wired sandboxing path to pass wrapper socket path through to seatbelt policy generation. - Added/updated seatbelt tests for explicit socket allow rule and argument emission. **6) Runtime entrypoint hooks** - This allows the same binary to act as the zsh wrapper subprocess when invoked via `EXEC_WRAPPER`. **7) Tool selection behavior** - ToolsConfig now prefers ShellCommand type when shell_zsh_fork is enabled. - Added test coverage for precedence with unified-exec enabled.
64 lines
1.8 KiB
Rust
64 lines
1.8 KiB
Rust
use clap::Parser;
|
|
use codex_app_server::AppServerTransport;
|
|
use codex_app_server::run_main_with_transport;
|
|
use codex_arg0::arg0_dispatch_or_else;
|
|
use codex_core::config_loader::LoaderOverrides;
|
|
use codex_utils_cli::CliConfigOverrides;
|
|
use std::path::PathBuf;
|
|
|
|
// Debug-only test hook: lets integration tests point the server at a temporary
|
|
// managed config file without writing to /etc.
|
|
const MANAGED_CONFIG_PATH_ENV_VAR: &str = "CODEX_APP_SERVER_MANAGED_CONFIG_PATH";
|
|
|
|
#[derive(Debug, Parser)]
|
|
struct AppServerArgs {
|
|
/// Transport endpoint URL. Supported values: `stdio://` (default),
|
|
/// `ws://IP:PORT`.
|
|
#[arg(
|
|
long = "listen",
|
|
value_name = "URL",
|
|
default_value = AppServerTransport::DEFAULT_LISTEN_URL
|
|
)]
|
|
listen: AppServerTransport,
|
|
}
|
|
|
|
fn main() -> anyhow::Result<()> {
|
|
if codex_core::maybe_run_zsh_exec_wrapper_mode()? {
|
|
return Ok(());
|
|
}
|
|
arg0_dispatch_or_else(|codex_linux_sandbox_exe| async move {
|
|
let args = AppServerArgs::parse();
|
|
let managed_config_path = managed_config_path_from_debug_env();
|
|
let loader_overrides = LoaderOverrides {
|
|
managed_config_path,
|
|
..Default::default()
|
|
};
|
|
let transport = args.listen;
|
|
|
|
run_main_with_transport(
|
|
codex_linux_sandbox_exe,
|
|
CliConfigOverrides::default(),
|
|
loader_overrides,
|
|
false,
|
|
transport,
|
|
)
|
|
.await?;
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
fn managed_config_path_from_debug_env() -> Option<PathBuf> {
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
if let Ok(value) = std::env::var(MANAGED_CONFIG_PATH_ENV_VAR) {
|
|
return if value.is_empty() {
|
|
None
|
|
} else {
|
|
Some(PathBuf::from(value))
|
|
};
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|