mirror of
https://github.com/openai/codex.git
synced 2026-04-19 12:14:48 +00:00
Compare commits
7 Commits
pr18028
...
pakrym/cur
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5754a6c145 | ||
|
|
fb5e86e8fc | ||
|
|
dc6abde998 | ||
|
|
f0124c0f0d | ||
|
|
1b5636e0fb | ||
|
|
6182298401 | ||
|
|
aca877b2d4 |
2
codex-rs/Cargo.lock
generated
2
codex-rs/Cargo.lock
generated
@@ -1985,6 +1985,7 @@ dependencies = [
|
||||
"codex-utils-oss",
|
||||
"codex-utils-sandbox-summary",
|
||||
"core_test_support",
|
||||
"ctor 0.6.3",
|
||||
"libc",
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
@@ -2170,6 +2171,7 @@ dependencies = [
|
||||
"codex-core",
|
||||
"codex-protocol",
|
||||
"codex-utils-absolute-path",
|
||||
"ctor 0.6.3",
|
||||
"landlock",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
|
||||
@@ -518,7 +518,6 @@ impl CodexMessageProcessor {
|
||||
message: format!("failed to reload config: {err}"),
|
||||
data: None,
|
||||
})?;
|
||||
config.codex_linux_sandbox_exe = self.arg0_paths.codex_linux_sandbox_exe.clone();
|
||||
config.main_execve_wrapper_exe = self.arg0_paths.main_execve_wrapper_exe.clone();
|
||||
Ok(config)
|
||||
}
|
||||
@@ -1731,7 +1730,6 @@ impl CodexMessageProcessor {
|
||||
),
|
||||
};
|
||||
|
||||
let codex_linux_sandbox_exe = self.arg0_paths.codex_linux_sandbox_exe.clone();
|
||||
let outgoing = self.outgoing.clone();
|
||||
let request_for_task = request.clone();
|
||||
let started_network_proxy_for_task = started_network_proxy;
|
||||
@@ -1751,7 +1749,6 @@ impl CodexMessageProcessor {
|
||||
&effective_file_system_sandbox_policy,
|
||||
effective_network_sandbox_policy,
|
||||
sandbox_cwd.as_path(),
|
||||
&codex_linux_sandbox_exe,
|
||||
use_legacy_landlock,
|
||||
) {
|
||||
Ok(exec_request) => {
|
||||
@@ -2153,7 +2150,6 @@ impl CodexMessageProcessor {
|
||||
approvals_reviewer: approvals_reviewer
|
||||
.map(codex_app_server_protocol::ApprovalsReviewer::to_core),
|
||||
sandbox_mode: sandbox.map(SandboxMode::to_core),
|
||||
codex_linux_sandbox_exe: self.arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: self.arg0_paths.main_execve_wrapper_exe.clone(),
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
|
||||
@@ -19,7 +19,6 @@ const TOKIO_WORKER_STACK_SIZE_BYTES: usize = 16 * 1024 * 1024;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Arg0DispatchPaths {
|
||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
pub main_execve_wrapper_exe: Option<PathBuf>,
|
||||
}
|
||||
|
||||
@@ -133,9 +132,7 @@ pub fn arg0_dispatch() -> Option<Arg0PathEntryGuard> {
|
||||
///
|
||||
/// 1. Load `.env` values from `~/.codex/.env` before creating any threads.
|
||||
/// 2. Construct a Tokio multi-thread runtime.
|
||||
/// 3. Derive the path to the current executable (so children can re-invoke the
|
||||
/// sandbox) when running on Linux.
|
||||
/// 4. Execute the provided async `main_fn` inside that runtime, forwarding any
|
||||
/// 3. Execute the provided async `main_fn` inside that runtime, forwarding any
|
||||
/// error. Note that `main_fn` receives [`Arg0DispatchPaths`], which
|
||||
/// contains the helper executable paths needed to construct
|
||||
/// [`codex_core::config::Config`].
|
||||
@@ -156,17 +153,7 @@ where
|
||||
// async entry-point.
|
||||
let runtime = build_runtime()?;
|
||||
runtime.block_on(async move {
|
||||
let current_exe = std::env::current_exe().ok();
|
||||
let paths = Arg0DispatchPaths {
|
||||
codex_linux_sandbox_exe: if cfg!(target_os = "linux") {
|
||||
current_exe.or_else(|| {
|
||||
path_entry
|
||||
.as_ref()
|
||||
.and_then(|path_entry| path_entry.paths().codex_linux_sandbox_exe.clone())
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
main_execve_wrapper_exe: path_entry
|
||||
.as_ref()
|
||||
.and_then(|path_entry| path_entry.paths().main_execve_wrapper_exe.clone()),
|
||||
@@ -324,16 +311,6 @@ pub fn prepend_path_entry_for_codex_aliases() -> std::io::Result<Arg0PathEntryGu
|
||||
}
|
||||
|
||||
let paths = Arg0DispatchPaths {
|
||||
codex_linux_sandbox_exe: {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
Some(path.join(LINUX_SANDBOX_ARG0))
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
},
|
||||
main_execve_wrapper_exe: {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
|
||||
@@ -33,10 +33,7 @@ use crate::exit_status::handle_exit_status;
|
||||
use seatbelt::DenialLogger;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub async fn run_command_under_seatbelt(
|
||||
command: SeatbeltCommand,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
pub async fn run_command_under_seatbelt(command: SeatbeltCommand) -> anyhow::Result<()> {
|
||||
let SeatbeltCommand {
|
||||
full_auto,
|
||||
log_denials,
|
||||
@@ -47,7 +44,6 @@ pub async fn run_command_under_seatbelt(
|
||||
full_auto,
|
||||
command,
|
||||
config_overrides,
|
||||
codex_linux_sandbox_exe,
|
||||
SandboxType::Seatbelt,
|
||||
log_denials,
|
||||
)
|
||||
@@ -55,17 +51,11 @@ pub async fn run_command_under_seatbelt(
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub async fn run_command_under_seatbelt(
|
||||
_command: SeatbeltCommand,
|
||||
_codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
pub async fn run_command_under_seatbelt(_command: SeatbeltCommand) -> anyhow::Result<()> {
|
||||
anyhow::bail!("Seatbelt sandbox is only available on macOS");
|
||||
}
|
||||
|
||||
pub async fn run_command_under_landlock(
|
||||
command: LandlockCommand,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
pub async fn run_command_under_landlock(command: LandlockCommand) -> anyhow::Result<()> {
|
||||
let LandlockCommand {
|
||||
full_auto,
|
||||
config_overrides,
|
||||
@@ -75,17 +65,13 @@ pub async fn run_command_under_landlock(
|
||||
full_auto,
|
||||
command,
|
||||
config_overrides,
|
||||
codex_linux_sandbox_exe,
|
||||
SandboxType::Landlock,
|
||||
/*log_denials*/ false,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn run_command_under_windows(
|
||||
command: WindowsCommand,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
pub async fn run_command_under_windows(command: WindowsCommand) -> anyhow::Result<()> {
|
||||
let WindowsCommand {
|
||||
full_auto,
|
||||
config_overrides,
|
||||
@@ -95,7 +81,6 @@ pub async fn run_command_under_windows(
|
||||
full_auto,
|
||||
command,
|
||||
config_overrides,
|
||||
codex_linux_sandbox_exe,
|
||||
SandboxType::Windows,
|
||||
/*log_denials*/ false,
|
||||
)
|
||||
@@ -113,7 +98,6 @@ async fn run_command_under_sandbox(
|
||||
full_auto: bool,
|
||||
command: Vec<String>,
|
||||
config_overrides: CliConfigOverrides,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
sandbox_type: SandboxType,
|
||||
log_denials: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -121,7 +105,6 @@ async fn run_command_under_sandbox(
|
||||
config_overrides
|
||||
.parse_overrides()
|
||||
.map_err(anyhow::Error::msg)?,
|
||||
codex_linux_sandbox_exe,
|
||||
full_auto,
|
||||
)
|
||||
.await?;
|
||||
@@ -273,10 +256,6 @@ async fn run_command_under_sandbox(
|
||||
.await?
|
||||
}
|
||||
SandboxType::Landlock => {
|
||||
#[expect(clippy::expect_used)]
|
||||
let codex_linux_sandbox_exe = config
|
||||
.codex_linux_sandbox_exe
|
||||
.expect("codex-linux-sandbox executable not found");
|
||||
let use_legacy_landlock = config.features.use_legacy_landlock();
|
||||
let args = create_linux_sandbox_command_args_for_policies(
|
||||
command,
|
||||
@@ -290,7 +269,7 @@ async fn run_command_under_sandbox(
|
||||
);
|
||||
let network_policy = config.permissions.network_sandbox_policy;
|
||||
spawn_debug_sandbox_child(
|
||||
codex_linux_sandbox_exe,
|
||||
std::env::current_exe()?,
|
||||
args,
|
||||
Some("codex-linux-sandbox"),
|
||||
cwd,
|
||||
@@ -373,30 +352,19 @@ async fn spawn_debug_sandbox_child(
|
||||
|
||||
async fn load_debug_sandbox_config(
|
||||
cli_overrides: Vec<(String, TomlValue)>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
full_auto: bool,
|
||||
) -> anyhow::Result<Config> {
|
||||
load_debug_sandbox_config_with_codex_home(
|
||||
cli_overrides,
|
||||
codex_linux_sandbox_exe,
|
||||
full_auto,
|
||||
/*codex_home*/ None,
|
||||
)
|
||||
.await
|
||||
load_debug_sandbox_config_with_codex_home(cli_overrides, full_auto, /*codex_home*/ None).await
|
||||
}
|
||||
|
||||
async fn load_debug_sandbox_config_with_codex_home(
|
||||
cli_overrides: Vec<(String, TomlValue)>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
full_auto: bool,
|
||||
codex_home: Option<PathBuf>,
|
||||
) -> anyhow::Result<Config> {
|
||||
let config = build_debug_sandbox_config(
|
||||
cli_overrides.clone(),
|
||||
ConfigOverrides {
|
||||
codex_linux_sandbox_exe: codex_linux_sandbox_exe.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
ConfigOverrides::default(),
|
||||
codex_home.clone(),
|
||||
)
|
||||
.await?;
|
||||
@@ -414,7 +382,6 @@ async fn load_debug_sandbox_config_with_codex_home(
|
||||
cli_overrides,
|
||||
ConfigOverrides {
|
||||
sandbox_mode: Some(create_sandbox_mode(full_auto)),
|
||||
codex_linux_sandbox_exe,
|
||||
..Default::default()
|
||||
},
|
||||
codex_home,
|
||||
@@ -503,13 +470,9 @@ mod tests {
|
||||
)
|
||||
.await?;
|
||||
|
||||
let config = load_debug_sandbox_config_with_codex_home(
|
||||
Vec::new(),
|
||||
None,
|
||||
false,
|
||||
Some(codex_home_path),
|
||||
)
|
||||
.await?;
|
||||
let config =
|
||||
load_debug_sandbox_config_with_codex_home(Vec::new(), false, Some(codex_home_path))
|
||||
.await?;
|
||||
|
||||
assert!(config_uses_permission_profiles(&config));
|
||||
assert!(
|
||||
@@ -539,7 +502,6 @@ mod tests {
|
||||
|
||||
let err = load_debug_sandbox_config_with_codex_home(
|
||||
Vec::new(),
|
||||
None,
|
||||
true,
|
||||
Some(codex_home.path().to_path_buf()),
|
||||
)
|
||||
|
||||
@@ -783,8 +783,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
&mut cloud_cli.config_overrides,
|
||||
root_config_overrides.clone(),
|
||||
);
|
||||
codex_cloud_tasks::run_main(cloud_cli, arg0_paths.codex_linux_sandbox_exe.clone())
|
||||
.await?;
|
||||
codex_cloud_tasks::run_main(cloud_cli).await?;
|
||||
}
|
||||
Some(Subcommand::Sandbox(sandbox_args)) => match sandbox_args.cmd {
|
||||
SandboxCommand::Macos(mut seatbelt_cli) => {
|
||||
@@ -793,11 +792,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
&mut seatbelt_cli.config_overrides,
|
||||
root_config_overrides.clone(),
|
||||
);
|
||||
codex_cli::debug_sandbox::run_command_under_seatbelt(
|
||||
seatbelt_cli,
|
||||
arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
)
|
||||
.await?;
|
||||
codex_cli::debug_sandbox::run_command_under_seatbelt(seatbelt_cli).await?;
|
||||
}
|
||||
SandboxCommand::Linux(mut landlock_cli) => {
|
||||
reject_remote_mode_for_subcommand(root_remote.as_deref(), "sandbox linux")?;
|
||||
@@ -805,11 +800,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
&mut landlock_cli.config_overrides,
|
||||
root_config_overrides.clone(),
|
||||
);
|
||||
codex_cli::debug_sandbox::run_command_under_landlock(
|
||||
landlock_cli,
|
||||
arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
)
|
||||
.await?;
|
||||
codex_cli::debug_sandbox::run_command_under_landlock(landlock_cli).await?;
|
||||
}
|
||||
SandboxCommand::Windows(mut windows_cli) => {
|
||||
reject_remote_mode_for_subcommand(root_remote.as_deref(), "sandbox windows")?;
|
||||
@@ -817,11 +808,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
&mut windows_cli.config_overrides,
|
||||
root_config_overrides.clone(),
|
||||
);
|
||||
codex_cli::debug_sandbox::run_command_under_windows(
|
||||
windows_cli,
|
||||
arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
)
|
||||
.await?;
|
||||
codex_cli::debug_sandbox::run_command_under_windows(windows_cli).await?;
|
||||
}
|
||||
},
|
||||
Some(Subcommand::Debug(DebugCommand { subcommand })) => match subcommand {
|
||||
|
||||
@@ -15,7 +15,6 @@ use owo_colors::Stream;
|
||||
use std::cmp::Ordering;
|
||||
use std::io::IsTerminal;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
@@ -729,7 +728,7 @@ fn spawn_apply(
|
||||
// (no standalone patch summarizer needed – UI displays raw diffs)
|
||||
|
||||
/// Entry point for the `codex cloud` subcommand.
|
||||
pub async fn run_main(cli: Cli, _codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()> {
|
||||
pub async fn run_main(cli: Cli) -> anyhow::Result<()> {
|
||||
if let Some(command) = cli.command {
|
||||
return match command {
|
||||
crate::cli::Command::Exec(args) => run_exec_command(args).await,
|
||||
|
||||
@@ -254,7 +254,6 @@ mod reload {
|
||||
ConfigOverrides {
|
||||
cwd: Some(config.cwd.clone()),
|
||||
model_provider: preserve_current_provider.then(|| config.model_provider_id.clone()),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: config.main_execve_wrapper_exe.clone(),
|
||||
js_repl_node_path: config.js_repl_node_path.clone(),
|
||||
..Default::default()
|
||||
|
||||
@@ -160,7 +160,6 @@ async fn apply_role_preserves_unspecified_keys() {
|
||||
TomlValue::String("base-model".to_string()),
|
||||
)])
|
||||
.await;
|
||||
config.codex_linux_sandbox_exe = Some(PathBuf::from("/tmp/codex-linux-sandbox"));
|
||||
config.main_execve_wrapper_exe = Some(PathBuf::from("/tmp/codex-execve-wrapper"));
|
||||
let role_path = write_role_config(
|
||||
&home,
|
||||
@@ -183,10 +182,6 @@ async fn apply_role_preserves_unspecified_keys() {
|
||||
|
||||
assert_eq!(config.model.as_deref(), Some("base-model"));
|
||||
assert_eq!(config.model_reasoning_effort, Some(ReasoningEffort::High));
|
||||
assert_eq!(
|
||||
config.codex_linux_sandbox_exe,
|
||||
Some(PathBuf::from("/tmp/codex-linux-sandbox"))
|
||||
);
|
||||
assert_eq!(
|
||||
config.main_execve_wrapper_exe,
|
||||
Some(PathBuf::from("/tmp/codex-execve-wrapper"))
|
||||
|
||||
@@ -823,7 +823,6 @@ pub(crate) struct TurnContext {
|
||||
pub(crate) features: ManagedFeatures,
|
||||
pub(crate) ghost_snapshot: GhostSnapshotConfig,
|
||||
pub(crate) final_output_json_schema: Option<Value>,
|
||||
pub(crate) codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
pub(crate) tool_call_gate: Arc<ReadinessFlag>,
|
||||
pub(crate) truncation_policy: TruncationPolicy,
|
||||
pub(crate) js_repl: Arc<JsReplHandle>,
|
||||
@@ -930,7 +929,6 @@ impl TurnContext {
|
||||
features,
|
||||
ghost_snapshot: self.ghost_snapshot.clone(),
|
||||
final_output_json_schema: self.final_output_json_schema.clone(),
|
||||
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe.clone(),
|
||||
tool_call_gate: Arc::new(ReadinessFlag::new()),
|
||||
truncation_policy,
|
||||
js_repl: Arc::clone(&self.js_repl),
|
||||
@@ -1378,7 +1376,6 @@ impl Session {
|
||||
features: per_turn_config.features.clone(),
|
||||
ghost_snapshot: per_turn_config.ghost_snapshot.clone(),
|
||||
final_output_json_schema: None,
|
||||
codex_linux_sandbox_exe: per_turn_config.codex_linux_sandbox_exe.clone(),
|
||||
tool_call_gate: Arc::new(ReadinessFlag::new()),
|
||||
truncation_policy: model_info.truncation_policy.into(),
|
||||
js_repl,
|
||||
@@ -1906,7 +1903,6 @@ impl Session {
|
||||
// MCP server immediately after it becomes ready (avoiding blocking).
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: session_configuration.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: session_configuration.cwd.clone(),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
@@ -2379,7 +2375,6 @@ impl Session {
|
||||
if sandbox_policy_changed {
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: per_turn_config.permissions.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: per_turn_config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: per_turn_config.cwd.clone(),
|
||||
use_legacy_landlock: per_turn_config.features.use_legacy_landlock(),
|
||||
};
|
||||
@@ -4050,7 +4045,6 @@ impl Session {
|
||||
let auth_statuses = compute_auth_statuses(mcp_servers.iter(), store_mode).await;
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: turn_context.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: turn_context.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: turn_context.cwd.clone(),
|
||||
use_legacy_landlock: turn_context.features.use_legacy_landlock(),
|
||||
};
|
||||
@@ -5276,7 +5270,6 @@ async fn spawn_review_thread(
|
||||
shell_environment_policy: parent_turn_context.shell_environment_policy.clone(),
|
||||
cwd: parent_turn_context.cwd.clone(),
|
||||
final_output_json_schema: None,
|
||||
codex_linux_sandbox_exe: parent_turn_context.codex_linux_sandbox_exe.clone(),
|
||||
tool_call_gate: Arc::new(ReadinessFlag::new()),
|
||||
js_repl: Arc::clone(&sess.js_repl),
|
||||
dynamic_tools: parent_turn_context.dynamic_tools.clone(),
|
||||
|
||||
@@ -24,7 +24,6 @@ use codex_protocol::models::function_call_output_content_items_to_text;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use core_test_support::codex_linux_sandbox_exe_or_skip;
|
||||
use core_test_support::responses::ev_assistant_message;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
@@ -68,7 +67,6 @@ async fn guardian_allows_shell_additional_permissions_requests_past_policy_valid
|
||||
.await;
|
||||
|
||||
let (mut session, mut turn_context_raw) = make_session_and_context().await;
|
||||
turn_context_raw.codex_linux_sandbox_exe = codex_linux_sandbox_exe_or_skip!();
|
||||
turn_context_raw
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)
|
||||
|
||||
@@ -4298,7 +4298,6 @@ fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
file_opener: UriBasedFileOpener::VsCode,
|
||||
codex_linux_sandbox_exe: None,
|
||||
main_execve_wrapper_exe: None,
|
||||
js_repl_node_path: None,
|
||||
js_repl_node_module_dirs: Vec::new(),
|
||||
@@ -4441,7 +4440,6 @@ fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
file_opener: UriBasedFileOpener::VsCode,
|
||||
codex_linux_sandbox_exe: None,
|
||||
main_execve_wrapper_exe: None,
|
||||
js_repl_node_path: None,
|
||||
js_repl_node_module_dirs: Vec::new(),
|
||||
@@ -4582,7 +4580,6 @@ fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
file_opener: UriBasedFileOpener::VsCode,
|
||||
codex_linux_sandbox_exe: None,
|
||||
main_execve_wrapper_exe: None,
|
||||
js_repl_node_path: None,
|
||||
js_repl_node_module_dirs: Vec::new(),
|
||||
@@ -4709,7 +4706,6 @@ fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
file_opener: UriBasedFileOpener::VsCode,
|
||||
codex_linux_sandbox_exe: None,
|
||||
main_execve_wrapper_exe: None,
|
||||
js_repl_node_path: None,
|
||||
js_repl_node_module_dirs: Vec::new(),
|
||||
|
||||
@@ -450,14 +450,6 @@ pub struct Config {
|
||||
/// output will be hyperlinked using the specified URI scheme.
|
||||
pub file_opener: UriBasedFileOpener,
|
||||
|
||||
/// Path to the `codex-linux-sandbox` executable. This must be set if
|
||||
/// [`crate::exec::SandboxType::LinuxSeccomp`] is used. Note that this
|
||||
/// cannot be set in the config file: it must be set in code via
|
||||
/// [`ConfigOverrides`].
|
||||
///
|
||||
/// When this program is invoked, arg0 will be set to `codex-linux-sandbox`.
|
||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
|
||||
/// Path to the `codex-execve-wrapper` executable used for shell
|
||||
/// escalation. This cannot be set in the config file: it must be set in
|
||||
/// code via [`ConfigOverrides`].
|
||||
@@ -846,8 +838,7 @@ impl Config {
|
||||
/// designed to use [AskForApproval::Never] exclusively.
|
||||
///
|
||||
/// Further, [ConfigOverrides] contains some options that are not supported
|
||||
/// in [ConfigToml], such as `cwd`, `codex_linux_sandbox_exe`, and
|
||||
/// `main_execve_wrapper_exe`.
|
||||
/// in [ConfigToml], such as `cwd` and `main_execve_wrapper_exe`.
|
||||
pub async fn load_with_cli_overrides_and_harness_overrides(
|
||||
cli_overrides: Vec<(String, TomlValue)>,
|
||||
harness_overrides: ConfigOverrides,
|
||||
@@ -1931,7 +1922,6 @@ pub struct ConfigOverrides {
|
||||
pub model_provider: Option<String>,
|
||||
pub service_tier: Option<Option<ServiceTier>>,
|
||||
pub config_profile: Option<String>,
|
||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
pub main_execve_wrapper_exe: Option<PathBuf>,
|
||||
pub js_repl_node_path: Option<PathBuf>,
|
||||
pub js_repl_node_module_dirs: Option<Vec<PathBuf>>,
|
||||
@@ -2129,7 +2119,6 @@ impl Config {
|
||||
model_provider,
|
||||
service_tier: service_tier_override,
|
||||
config_profile: config_profile_key,
|
||||
codex_linux_sandbox_exe,
|
||||
main_execve_wrapper_exe,
|
||||
js_repl_node_path: js_repl_node_path_override,
|
||||
js_repl_node_module_dirs: js_repl_node_module_dirs_override,
|
||||
@@ -2730,7 +2719,6 @@ impl Config {
|
||||
history,
|
||||
ephemeral: ephemeral.unwrap_or_default(),
|
||||
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
|
||||
codex_linux_sandbox_exe,
|
||||
main_execve_wrapper_exe,
|
||||
js_repl_node_path,
|
||||
js_repl_node_module_dirs,
|
||||
|
||||
@@ -211,7 +211,6 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_options_and_status(
|
||||
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
|
||||
@@ -151,9 +151,6 @@ pub enum CodexErr {
|
||||
#[error("sandbox error: {0}")]
|
||||
Sandbox(#[from] SandboxErr),
|
||||
|
||||
#[error("codex-linux-sandbox was required but not provided")]
|
||||
LandlockSandboxExecutableNotProvided,
|
||||
|
||||
#[error("unsupported operation: {0}")]
|
||||
UnsupportedOperation(String),
|
||||
|
||||
@@ -207,7 +204,6 @@ impl CodexErr {
|
||||
| CodexErr::RefreshTokenFailed(_)
|
||||
| CodexErr::UnsupportedOperation(_)
|
||||
| CodexErr::Sandbox(_)
|
||||
| CodexErr::LandlockSandboxExecutableNotProvided
|
||||
| CodexErr::RetryLimit(_)
|
||||
| CodexErr::ContextWindowExceeded
|
||||
| CodexErr::ThreadNotFound(_)
|
||||
|
||||
@@ -217,7 +217,6 @@ pub async fn process_exec_tool_call(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_cwd: &Path,
|
||||
codex_linux_sandbox_exe: &Option<PathBuf>,
|
||||
use_legacy_landlock: bool,
|
||||
stdout_stream: Option<StdoutStream>,
|
||||
) -> Result<ExecToolCallOutput> {
|
||||
@@ -227,7 +226,6 @@ pub async fn process_exec_tool_call(
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
sandbox_cwd,
|
||||
codex_linux_sandbox_exe,
|
||||
use_legacy_landlock,
|
||||
)?;
|
||||
|
||||
@@ -243,7 +241,6 @@ pub fn build_exec_request(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_cwd: &Path,
|
||||
codex_linux_sandbox_exe: &Option<PathBuf>,
|
||||
use_legacy_landlock: bool,
|
||||
) -> Result<ExecRequest> {
|
||||
let windows_sandbox_level = params.windows_sandbox_level;
|
||||
@@ -304,7 +301,6 @@ pub fn build_exec_request(
|
||||
sandbox_policy_cwd: sandbox_cwd,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: codex_linux_sandbox_exe.as_ref(),
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level,
|
||||
windows_sandbox_private_desktop,
|
||||
@@ -625,9 +621,7 @@ pub(crate) mod errors {
|
||||
impl From<SandboxTransformError> for CodexErr {
|
||||
fn from(err: SandboxTransformError) -> Self {
|
||||
match err {
|
||||
SandboxTransformError::MissingLinuxSandboxExecutable => {
|
||||
CodexErr::LandlockSandboxExecutableNotProvided
|
||||
}
|
||||
SandboxTransformError::CurrentExecutableUnavailable(err) => CodexErr::Io(err),
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
SandboxTransformError::SeatbeltUnavailable => CodexErr::UnsupportedOperation(
|
||||
"seatbelt sandbox is only available on macOS".to_string(),
|
||||
|
||||
@@ -358,7 +358,6 @@ async fn process_exec_tool_call_preserves_full_buffer_capture_policy() -> Result
|
||||
&FileSystemSandboxPolicy::from(&sandbox_policy),
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
cwd.as_path(),
|
||||
&None,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
@@ -662,7 +661,6 @@ async fn process_exec_tool_call_respects_cancellation_token() -> Result<()> {
|
||||
&FileSystemSandboxPolicy::from(&SandboxPolicy::DangerFullAccess),
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
cwd.as_path(),
|
||||
&None,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -115,7 +115,6 @@ struct GuardianReviewSessionReuseKey {
|
||||
compact_prompt: Option<String>,
|
||||
cwd: PathBuf,
|
||||
mcp_servers: Constrained<HashMap<String, McpServerConfig>>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
main_execve_wrapper_exe: Option<PathBuf>,
|
||||
js_repl_node_path: Option<PathBuf>,
|
||||
js_repl_node_module_dirs: Vec<PathBuf>,
|
||||
@@ -142,7 +141,6 @@ impl GuardianReviewSessionReuseKey {
|
||||
compact_prompt: spawn_config.compact_prompt.clone(),
|
||||
cwd: spawn_config.cwd.clone(),
|
||||
mcp_servers: spawn_config.mcp_servers.clone(),
|
||||
codex_linux_sandbox_exe: spawn_config.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: spawn_config.main_execve_wrapper_exe.clone(),
|
||||
js_repl_node_path: spawn_config.js_repl_node_path.clone(),
|
||||
js_repl_node_module_dirs: spawn_config.js_repl_node_module_dirs.clone(),
|
||||
|
||||
@@ -19,8 +19,7 @@ use tokio::process::Child;
|
||||
/// split filesystem/network policies as JSON so the helper can migrate
|
||||
/// incrementally without breaking older call sites.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn spawn_command_under_linux_sandbox<P>(
|
||||
codex_linux_sandbox_exe: P,
|
||||
pub async fn spawn_command_under_linux_sandbox(
|
||||
command: Vec<String>,
|
||||
command_cwd: PathBuf,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
@@ -29,10 +28,7 @@ pub async fn spawn_command_under_linux_sandbox<P>(
|
||||
stdio_policy: StdioPolicy,
|
||||
network: Option<&NetworkProxy>,
|
||||
env: HashMap<String, String>,
|
||||
) -> std::io::Result<Child>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
) -> std::io::Result<Child> {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, sandbox_policy_cwd);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(sandbox_policy);
|
||||
@@ -48,7 +44,7 @@ where
|
||||
);
|
||||
let arg0 = Some("codex-linux-sandbox");
|
||||
spawn_child_async(SpawnChildRequest {
|
||||
program: codex_linux_sandbox_exe.as_ref().to_path_buf(),
|
||||
program: std::env::current_exe()?,
|
||||
args,
|
||||
arg0,
|
||||
cwd: command_cwd,
|
||||
|
||||
@@ -277,7 +277,6 @@ pub async fn collect_mcp_snapshot(config: &Config) -> McpListToolsResponseEvent
|
||||
// Use ReadOnly sandbox policy for MCP snapshot collection (safest default)
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
|
||||
@@ -588,7 +588,6 @@ pub const MCP_SANDBOX_STATE_METHOD: &str = "codex/sandbox-state/update";
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SandboxState {
|
||||
pub sandbox_policy: SandboxPolicy,
|
||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
pub sandbox_cwd: PathBuf,
|
||||
#[serde(default)]
|
||||
pub use_legacy_landlock: bool,
|
||||
|
||||
@@ -97,7 +97,6 @@ pub(crate) struct SandboxTransformRequest<'a> {
|
||||
pub sandbox_policy_cwd: &'a Path,
|
||||
#[cfg(target_os = "macos")]
|
||||
pub macos_seatbelt_profile_extensions: Option<&'a MacOsSeatbeltProfileExtensions>,
|
||||
pub codex_linux_sandbox_exe: Option<&'a PathBuf>,
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
@@ -111,8 +110,8 @@ pub enum SandboxPreference {
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub(crate) enum SandboxTransformError {
|
||||
#[error("missing codex-linux-sandbox executable path")]
|
||||
MissingLinuxSandboxExecutable,
|
||||
#[error("failed to resolve current executable for linux sandbox launch: {0}")]
|
||||
CurrentExecutableUnavailable(std::io::Error),
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[error("seatbelt sandbox is only available on macOS")]
|
||||
SeatbeltUnavailable,
|
||||
@@ -595,7 +594,6 @@ impl SandboxManager {
|
||||
sandbox_policy_cwd,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions,
|
||||
codex_linux_sandbox_exe,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level,
|
||||
windows_sandbox_private_desktop,
|
||||
@@ -670,8 +668,8 @@ impl SandboxManager {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
SandboxType::MacosSeatbelt => return Err(SandboxTransformError::SeatbeltUnavailable),
|
||||
SandboxType::LinuxSeccomp => {
|
||||
let exe = codex_linux_sandbox_exe
|
||||
.ok_or(SandboxTransformError::MissingLinuxSandboxExecutable)?;
|
||||
let exe = std::env::current_exe()
|
||||
.map_err(SandboxTransformError::CurrentExecutableUnavailable)?;
|
||||
let allow_proxy_network = allow_network_for_proxy(enforce_managed_network);
|
||||
let mut args = create_linux_sandbox_command_args_for_policies(
|
||||
command.clone(),
|
||||
|
||||
@@ -174,7 +174,6 @@ fn transform_preserves_unrestricted_file_system_policy_for_restricted_network()
|
||||
sandbox_policy_cwd: cwd.as_path(),
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
@@ -544,7 +543,6 @@ fn transform_additional_permissions_enable_network_for_external_sandbox() {
|
||||
sandbox_policy_cwd: cwd.as_path(),
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
@@ -618,7 +616,6 @@ fn transform_additional_permissions_preserves_denied_entries() {
|
||||
sandbox_policy_cwd: cwd.as_path(),
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
|
||||
@@ -206,7 +206,6 @@ impl ToolHandler for ApplyPatchHandler {
|
||||
permissions_preapproved: effective_additional_permissions
|
||||
.permissions_preapproved,
|
||||
timeout_ms: None,
|
||||
codex_exe: turn.codex_linux_sandbox_exe.clone(),
|
||||
};
|
||||
|
||||
let mut orchestrator = ToolOrchestrator::new();
|
||||
@@ -310,7 +309,6 @@ pub(crate) async fn intercept_apply_patch(
|
||||
permissions_preapproved: effective_additional_permissions
|
||||
.permissions_preapproved,
|
||||
timeout_ms,
|
||||
codex_exe: turn.codex_linux_sandbox_exe.clone(),
|
||||
};
|
||||
|
||||
let mut orchestrator = ToolOrchestrator::new();
|
||||
|
||||
@@ -305,7 +305,6 @@ fn apply_spawn_agent_runtime_overrides(
|
||||
FunctionCallError::RespondToModel(format!("approval_policy is invalid: {err}"))
|
||||
})?;
|
||||
config.permissions.shell_environment_policy = turn.shell_environment_policy.clone();
|
||||
config.codex_linux_sandbox_exe = turn.codex_linux_sandbox_exe.clone();
|
||||
config.cwd = turn.cwd.clone();
|
||||
config
|
||||
.permissions
|
||||
|
||||
@@ -28,7 +28,6 @@ use pretty_assertions::assert_eq;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -1552,7 +1551,6 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
};
|
||||
let temp_dir = tempfile::tempdir().expect("temp dir");
|
||||
turn.cwd = temp_dir.path().to_path_buf();
|
||||
turn.codex_linux_sandbox_exe = Some(PathBuf::from("/bin/echo"));
|
||||
let sandbox_policy = pick_allowed_sandbox_policy(
|
||||
&turn.config.permissions.sandbox_policy,
|
||||
turn.config.permissions.sandbox_policy.get().clone(),
|
||||
@@ -1579,7 +1577,6 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
expected.developer_instructions = turn.developer_instructions.clone();
|
||||
expected.compact_prompt = turn.compact_prompt.clone();
|
||||
expected.permissions.shell_environment_policy = turn.shell_environment_policy.clone();
|
||||
expected.codex_linux_sandbox_exe = turn.codex_linux_sandbox_exe.clone();
|
||||
expected.cwd = turn.cwd.clone();
|
||||
expected
|
||||
.permissions
|
||||
@@ -1633,7 +1630,6 @@ async fn build_agent_resume_config_clears_base_instructions() {
|
||||
expected.developer_instructions = turn.developer_instructions.clone();
|
||||
expected.compact_prompt = turn.compact_prompt.clone();
|
||||
expected.permissions.shell_environment_policy = turn.shell_environment_policy.clone();
|
||||
expected.codex_linux_sandbox_exe = turn.codex_linux_sandbox_exe.clone();
|
||||
expected.cwd = turn.cwd.clone();
|
||||
expected
|
||||
.permissions
|
||||
|
||||
@@ -1070,7 +1070,6 @@ impl JsReplManager {
|
||||
sandbox_policy_cwd: &turn.cwd,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: turn.codex_linux_sandbox_exe.as_ref(),
|
||||
use_legacy_landlock: turn.features.use_legacy_landlock(),
|
||||
windows_sandbox_level: turn.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: turn
|
||||
|
||||
@@ -199,7 +199,6 @@ impl ToolOrchestrator {
|
||||
enforce_managed_network: has_managed_network_requirements,
|
||||
manager: &self.sandbox,
|
||||
sandbox_cwd: &turn_ctx.cwd,
|
||||
codex_linux_sandbox_exe: turn_ctx.codex_linux_sandbox_exe.as_ref(),
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level: turn_ctx.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: turn_ctx
|
||||
@@ -330,7 +329,6 @@ impl ToolOrchestrator {
|
||||
enforce_managed_network: has_managed_network_requirements,
|
||||
manager: &self.sandbox,
|
||||
sandbox_cwd: &turn_ctx.cwd,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level: turn_ctx.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: turn_ctx
|
||||
|
||||
@@ -43,7 +43,6 @@ pub struct ApplyPatchRequest {
|
||||
pub additional_permissions: Option<PermissionProfile>,
|
||||
pub permissions_preapproved: bool,
|
||||
pub timeout_ms: Option<u64>,
|
||||
pub codex_exe: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -71,20 +70,11 @@ impl ApplyPatchRuntime {
|
||||
req: &ApplyPatchRequest,
|
||||
_codex_home: &std::path::Path,
|
||||
) -> Result<CommandSpec, ToolError> {
|
||||
let exe = if let Some(path) = &req.codex_exe {
|
||||
path.clone()
|
||||
} else {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
codex_windows_sandbox::resolve_current_exe_for_launch(_codex_home, "codex.exe")
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
std::env::current_exe().map_err(|e| {
|
||||
ToolError::Rejected(format!("failed to determine codex exe: {e}"))
|
||||
})?
|
||||
}
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
let exe = codex_windows_sandbox::resolve_current_exe_for_launch(_codex_home, "codex.exe");
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let exe = std::env::current_exe()
|
||||
.map_err(|e| ToolError::Rejected(format!("failed to determine codex exe: {e}")))?;
|
||||
let program = exe.to_string_lossy().to_string();
|
||||
Ok(CommandSpec {
|
||||
program,
|
||||
|
||||
@@ -52,7 +52,6 @@ fn guardian_review_request_includes_patch_context() {
|
||||
additional_permissions: None,
|
||||
permissions_preapproved: false,
|
||||
timeout_ms: None,
|
||||
codex_exe: None,
|
||||
};
|
||||
|
||||
let guardian_request = ApplyPatchRuntime::build_guardian_review_request(&request, "call-1");
|
||||
|
||||
@@ -164,7 +164,6 @@ pub(super) async fn try_run_zsh_fork(
|
||||
.permissions
|
||||
.macos_seatbelt_profile_extensions
|
||||
.clone(),
|
||||
codex_linux_sandbox_exe: ctx.turn.codex_linux_sandbox_exe.clone(),
|
||||
use_legacy_landlock: ctx.turn.features.use_legacy_landlock(),
|
||||
};
|
||||
let main_execve_wrapper_exe = ctx
|
||||
@@ -270,7 +269,6 @@ pub(crate) async fn prepare_unified_exec_zsh_fork(
|
||||
.permissions
|
||||
.macos_seatbelt_profile_extensions
|
||||
.clone(),
|
||||
codex_linux_sandbox_exe: ctx.turn.codex_linux_sandbox_exe.clone(),
|
||||
use_legacy_landlock: ctx.turn.features.use_legacy_landlock(),
|
||||
};
|
||||
let escalation_policy = CoreShellActionProvider {
|
||||
@@ -863,7 +861,6 @@ struct CoreShellCommandExecutor {
|
||||
sandbox_policy_cwd: PathBuf,
|
||||
#[cfg_attr(not(target_os = "macos"), allow(dead_code))]
|
||||
macos_seatbelt_profile_extensions: Option<MacOsSeatbeltProfileExtensions>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
use_legacy_landlock: bool,
|
||||
}
|
||||
|
||||
@@ -1063,7 +1060,6 @@ impl CoreShellCommandExecutor {
|
||||
sandbox_policy_cwd: &self.sandbox_policy_cwd,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions,
|
||||
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe.as_ref(),
|
||||
use_legacy_landlock: self.use_legacy_landlock,
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: false,
|
||||
|
||||
@@ -668,7 +668,6 @@ async fn prepare_escalated_exec_turn_default_preserves_macos_seatbelt_extensions
|
||||
macos_preferences: MacOsPreferencesPermission::ReadWrite,
|
||||
..Default::default()
|
||||
}),
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
};
|
||||
|
||||
@@ -717,7 +716,6 @@ async fn prepare_escalated_exec_permissions_preserve_macos_seatbelt_extensions()
|
||||
arg0: None,
|
||||
sandbox_policy_cwd: cwd.to_path_buf(),
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
};
|
||||
|
||||
@@ -795,7 +793,6 @@ async fn prepare_escalated_exec_permission_profile_unions_turn_and_requested_mac
|
||||
macos_preferences: MacOsPreferencesPermission::ReadOnly,
|
||||
..Default::default()
|
||||
}),
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
};
|
||||
|
||||
|
||||
@@ -330,7 +330,6 @@ pub(crate) struct SandboxAttempt<'a> {
|
||||
pub enforce_managed_network: bool,
|
||||
pub(crate) manager: &'a SandboxManager,
|
||||
pub(crate) sandbox_cwd: &'a Path,
|
||||
pub codex_linux_sandbox_exe: Option<&'a std::path::PathBuf>,
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
@@ -354,7 +353,6 @@ impl<'a> SandboxAttempt<'a> {
|
||||
sandbox_policy_cwd: self.sandbox_cwd,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe,
|
||||
use_legacy_landlock: self.use_legacy_landlock,
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: self.windows_sandbox_private_desktop,
|
||||
|
||||
@@ -162,12 +162,7 @@ pub async fn load_default_config_for_test(codex_home: &TempDir) -> Config {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn default_test_overrides() -> ConfigOverrides {
|
||||
ConfigOverrides {
|
||||
codex_linux_sandbox_exe: Some(
|
||||
find_codex_linux_sandbox_exe().expect("should find binary for codex-linux-sandbox"),
|
||||
),
|
||||
..ConfigOverrides::default()
|
||||
}
|
||||
ConfigOverrides::default()
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
@@ -175,23 +170,6 @@ fn default_test_overrides() -> ConfigOverrides {
|
||||
ConfigOverrides::default()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn find_codex_linux_sandbox_exe() -> Result<PathBuf, CargoBinError> {
|
||||
if let Ok(path) = std::env::current_exe() {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
if let Some(path) = TEST_ARG0_PATH_ENTRY
|
||||
.get()
|
||||
.and_then(Option::as_ref)
|
||||
.and_then(|path_entry| path_entry.paths().codex_linux_sandbox_exe.clone())
|
||||
{
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
codex_utils_cargo_bin::cargo_bin("codex-linux-sandbox")
|
||||
}
|
||||
|
||||
/// Builds an SSE stream body from a JSON fixture.
|
||||
///
|
||||
/// The fixture must contain an array of objects where each object represents a
|
||||
@@ -525,42 +503,6 @@ macro_rules! skip_if_no_network {
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! codex_linux_sandbox_exe_or_skip {
|
||||
() => {{
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
match $crate::find_codex_linux_sandbox_exe() {
|
||||
Ok(path) => Some(path),
|
||||
Err(err) => {
|
||||
eprintln!("codex-linux-sandbox binary not available, skipping test: {err}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}};
|
||||
($return_value:expr $(,)?) => {{
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
match $crate::find_codex_linux_sandbox_exe() {
|
||||
Ok(path) => Some(path),
|
||||
Err(err) => {
|
||||
eprintln!("codex-linux-sandbox binary not available, skipping test: {err}");
|
||||
return $return_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! skip_if_windows {
|
||||
($return_value:expr $(,)?) => {{
|
||||
|
||||
@@ -561,18 +561,6 @@ impl TestCodexBuilder {
|
||||
for hook in self.pre_build_hooks.drain(..) {
|
||||
hook(home.path());
|
||||
}
|
||||
if let Ok(path) = codex_utils_cargo_bin::cargo_bin("codex") {
|
||||
config.codex_linux_sandbox_exe = Some(path);
|
||||
} else if let Ok(exe) = std::env::current_exe()
|
||||
&& let Some(path) = exe
|
||||
.parent()
|
||||
.and_then(|parent| parent.parent())
|
||||
.map(|parent| parent.join("codex"))
|
||||
&& path.is_file()
|
||||
{
|
||||
config.codex_linux_sandbox_exe = Some(path);
|
||||
}
|
||||
|
||||
let mut mutators = vec![];
|
||||
swap(&mut self.config_mutators, &mut mutators);
|
||||
for mutator in mutators {
|
||||
|
||||
@@ -56,7 +56,6 @@ async fn run_test_cmd(tmp: TempDir, cmd: Vec<&str>) -> Result<ExecToolCallOutput
|
||||
&FileSystemSandboxPolicy::from(&policy),
|
||||
NetworkSandboxPolicy::from(&policy),
|
||||
tmp.path(),
|
||||
&None,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -58,6 +58,7 @@ assert_cmd = { workspace = true }
|
||||
codex-apply-patch = { workspace = true }
|
||||
codex-utils-cargo-bin = { workspace = true }
|
||||
core_test_support = { workspace = true }
|
||||
ctor = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
opentelemetry = { workspace = true }
|
||||
opentelemetry_sdk = { workspace = true }
|
||||
|
||||
@@ -345,7 +345,6 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
|
||||
cwd: resolved_cwd,
|
||||
model_provider: model_provider.clone(),
|
||||
service_tier: None,
|
||||
codex_linux_sandbox_exe: arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: arg0_paths.main_execve_wrapper_exe.clone(),
|
||||
js_repl_node_path: None,
|
||||
js_repl_node_module_dirs: None,
|
||||
|
||||
@@ -1,4 +1,49 @@
|
||||
// Aggregates all former standalone integration tests as modules.
|
||||
use codex_arg0::Arg0PathEntryGuard;
|
||||
use codex_arg0::arg0_dispatch;
|
||||
use ctor::ctor;
|
||||
use tempfile::TempDir;
|
||||
|
||||
struct TestCodexAliasesGuard {
|
||||
_codex_home: TempDir,
|
||||
_arg0: Arg0PathEntryGuard,
|
||||
}
|
||||
|
||||
const CODEX_HOME_ENV_VAR: &str = "CODEX_HOME";
|
||||
|
||||
// This code runs before any other tests are run.
|
||||
// It allows the test binary to behave like codex-exec and dispatch to
|
||||
// codex-linux-sandbox based on the arg0.
|
||||
#[ctor]
|
||||
pub static CODEX_ALIASES_TEMP_DIR: TestCodexAliasesGuard = unsafe {
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let codex_home = tempfile::Builder::new()
|
||||
.prefix("codex-exec-tests")
|
||||
.tempdir()
|
||||
.unwrap();
|
||||
let previous_codex_home = std::env::var_os(CODEX_HOME_ENV_VAR);
|
||||
|
||||
// Safety: #[ctor] runs before test threads start.
|
||||
unsafe {
|
||||
std::env::set_var(CODEX_HOME_ENV_VAR, codex_home.path());
|
||||
}
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let arg0 = arg0_dispatch().unwrap();
|
||||
match previous_codex_home.as_ref() {
|
||||
Some(value) => unsafe {
|
||||
std::env::set_var(CODEX_HOME_ENV_VAR, value);
|
||||
},
|
||||
None => unsafe {
|
||||
std::env::remove_var(CODEX_HOME_ENV_VAR);
|
||||
},
|
||||
}
|
||||
|
||||
TestCodexAliasesGuard {
|
||||
_codex_home: codex_home,
|
||||
_arg0: arg0,
|
||||
}
|
||||
};
|
||||
|
||||
mod add_dir;
|
||||
mod apply_patch;
|
||||
mod auth_env;
|
||||
|
||||
@@ -43,10 +43,7 @@ async fn spawn_command_under_sandbox(
|
||||
env: HashMap<String, String>,
|
||||
) -> std::io::Result<Child> {
|
||||
use codex_core::landlock::spawn_command_under_linux_sandbox;
|
||||
let codex_linux_sandbox_exe = codex_utils_cargo_bin::cargo_bin("codex-exec")
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, err))?;
|
||||
spawn_command_under_linux_sandbox(
|
||||
codex_linux_sandbox_exe,
|
||||
command,
|
||||
command_cwd,
|
||||
sandbox_policy,
|
||||
|
||||
@@ -28,6 +28,7 @@ serde_json = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
||||
ctor = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tokio = { workspace = true, features = [
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![cfg(target_os = "linux")]
|
||||
|
||||
// Single integration test binary that aggregates all test modules.
|
||||
// The submodules live in `tests/suite/`.
|
||||
mod suite;
|
||||
|
||||
@@ -6,8 +6,11 @@ use codex_core::error::Result;
|
||||
use codex_core::error::SandboxErr;
|
||||
use codex_core::exec::ExecCapturePolicy;
|
||||
use codex_core::exec::ExecParams;
|
||||
use codex_core::exec::ExecToolCallOutput;
|
||||
use codex_core::exec::StreamOutput;
|
||||
use codex_core::exec::process_exec_tool_call;
|
||||
use codex_core::exec_env::create_env;
|
||||
use codex_core::landlock::create_linux_sandbox_command_args_for_policies;
|
||||
use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
@@ -22,17 +25,21 @@ use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Stdio;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
use tempfile::NamedTempFile;
|
||||
use tokio::process::Command;
|
||||
|
||||
// At least on GitHub CI, the arm64 tests appear to need longer timeouts.
|
||||
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
const SHORT_TIMEOUT_MS: u64 = 200;
|
||||
const SHORT_TIMEOUT_MS: u64 = 2_000;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
const SHORT_TIMEOUT_MS: u64 = 5_000;
|
||||
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
const LONG_TIMEOUT_MS: u64 = 1_000;
|
||||
const LONG_TIMEOUT_MS: u64 = 5_000;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
const LONG_TIMEOUT_MS: u64 = 5_000;
|
||||
|
||||
@@ -112,34 +119,66 @@ async fn run_cmd_result_with_policies(
|
||||
use_legacy_landlock: bool,
|
||||
) -> Result<codex_core::exec::ExecToolCallOutput> {
|
||||
let cwd = std::env::current_dir().expect("cwd should exist");
|
||||
let sandbox_cwd = cwd.clone();
|
||||
let params = ExecParams {
|
||||
command: cmd.iter().copied().map(str::to_owned).collect(),
|
||||
cwd,
|
||||
expiration: timeout_ms.into(),
|
||||
capture_policy: ExecCapturePolicy::ShellTool,
|
||||
env: create_env_from_core_vars(),
|
||||
network: None,
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
justification: None,
|
||||
arg0: None,
|
||||
};
|
||||
let sandbox_program = env!("CARGO_BIN_EXE_codex-linux-sandbox");
|
||||
let codex_linux_sandbox_exe = Some(PathBuf::from(sandbox_program));
|
||||
|
||||
process_exec_tool_call(
|
||||
params,
|
||||
let args = create_linux_sandbox_command_args_for_policies(
|
||||
cmd.iter().copied().map(str::to_owned).collect(),
|
||||
cwd.as_path(),
|
||||
&sandbox_policy,
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
sandbox_cwd.as_path(),
|
||||
&codex_linux_sandbox_exe,
|
||||
cwd.as_path(),
|
||||
use_legacy_landlock,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
/*allow_network_for_proxy*/ false,
|
||||
);
|
||||
|
||||
run_linux_sandbox_command(args, cwd, timeout_ms).await
|
||||
}
|
||||
|
||||
async fn run_linux_sandbox_command(
|
||||
args: Vec<String>,
|
||||
cwd: PathBuf,
|
||||
timeout_ms: u64,
|
||||
) -> Result<ExecToolCallOutput> {
|
||||
let start = Instant::now();
|
||||
let mut command = Command::new(env!("CARGO_BIN_EXE_codex-linux-sandbox"));
|
||||
command
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.env_clear()
|
||||
.envs(create_env_from_core_vars())
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
|
||||
let output =
|
||||
match tokio::time::timeout(Duration::from_millis(timeout_ms), command.output()).await {
|
||||
Ok(output) => output.map_err(CodexErr::Io)?,
|
||||
Err(_) => {
|
||||
let exec_output = ExecToolCallOutput {
|
||||
exit_code: 124,
|
||||
stdout: StreamOutput::new(String::new()),
|
||||
stderr: StreamOutput::new(String::new()),
|
||||
aggregated_output: StreamOutput::new(String::new()),
|
||||
duration: start.elapsed(),
|
||||
timed_out: true,
|
||||
};
|
||||
return Err(CodexErr::Sandbox(SandboxErr::Timeout {
|
||||
output: Box::new(exec_output),
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
let aggregated_output = format!("{stdout}{stderr}");
|
||||
|
||||
Ok(ExecToolCallOutput {
|
||||
exit_code: output.status.code().unwrap_or(-1),
|
||||
stdout: StreamOutput::new(stdout),
|
||||
stderr: StreamOutput::new(stderr),
|
||||
aggregated_output: StreamOutput::new(aggregated_output),
|
||||
duration: start.elapsed(),
|
||||
timed_out: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn is_bwrap_unavailable_output(output: &codex_core::exec::ExecToolCallOutput) -> bool {
|
||||
@@ -388,15 +427,12 @@ async fn assert_network_blocked(cmd: &[&str]) {
|
||||
};
|
||||
|
||||
let sandbox_policy = SandboxPolicy::new_read_only_policy();
|
||||
let sandbox_program = env!("CARGO_BIN_EXE_codex-linux-sandbox");
|
||||
let codex_linux_sandbox_exe: Option<PathBuf> = Some(PathBuf::from(sandbox_program));
|
||||
let result = process_exec_tool_call(
|
||||
params,
|
||||
&sandbox_policy,
|
||||
&FileSystemSandboxPolicy::from(&sandbox_policy),
|
||||
NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
sandbox_cwd.as_path(),
|
||||
&codex_linux_sandbox_exe,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
// Aggregates all former standalone integration tests as modules.
|
||||
use ctor::ctor;
|
||||
use std::path::Path;
|
||||
|
||||
const LINUX_SANDBOX_ARG0: &str = "codex-linux-sandbox";
|
||||
|
||||
// This code runs before any other tests are run.
|
||||
// It allows the test binary to behave like codex-linux-sandbox when re-execed
|
||||
// via current_exe() with argv[0] overridden.
|
||||
#[ctor]
|
||||
fn dispatch_linux_sandbox_arg0() {
|
||||
let argv0 = std::env::args_os().next().unwrap_or_default();
|
||||
let exe_name = Path::new(&argv0)
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if exe_name == LINUX_SANDBOX_ARG0 {
|
||||
codex_linux_sandbox::run_main();
|
||||
}
|
||||
}
|
||||
|
||||
mod landlock;
|
||||
mod managed_proxy;
|
||||
|
||||
@@ -176,7 +176,6 @@ impl CodexToolCallParam {
|
||||
cwd: cwd.map(PathBuf::from),
|
||||
approval_policy: approval_policy.map(Into::into),
|
||||
sandbox_mode: sandbox.map(Into::into),
|
||||
codex_linux_sandbox_exe: arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: arg0_paths.main_execve_wrapper_exe.clone(),
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
|
||||
@@ -416,7 +416,6 @@ pub async fn run_main(
|
||||
cwd,
|
||||
model_provider: model_provider_override.clone(),
|
||||
config_profile: cli.config_profile.clone(),
|
||||
codex_linux_sandbox_exe: arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: arg0_paths.main_execve_wrapper_exe.clone(),
|
||||
show_raw_agent_reasoning: cli.oss.then_some(true),
|
||||
additional_writable_roots: additional_dirs,
|
||||
|
||||
@@ -738,7 +738,6 @@ pub async fn run_main(
|
||||
cwd,
|
||||
model_provider: model_provider_override.clone(),
|
||||
config_profile: cli.config_profile.clone(),
|
||||
codex_linux_sandbox_exe: arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: arg0_paths.main_execve_wrapper_exe.clone(),
|
||||
show_raw_agent_reasoning: cli.oss.then_some(true),
|
||||
additional_writable_roots: additional_dirs,
|
||||
|
||||
Reference in New Issue
Block a user