Skip to content
Open
5 changes: 4 additions & 1 deletion codex-rs/cli/src/debug_sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,10 @@ async fn run_command_under_sandbox(
let sandbox_policy_cwd = cwd.clone();

let stdio_policy = StdioPolicy::Inherit;
let env = create_env(&config.shell_environment_policy, None);
let mut env = create_env(&config.shell_environment_policy, None);
if let Some(network) = config.network.as_ref() {
network.apply_to_env(&mut env);
}

// Special-case Windows sandbox: execute and exit the process to emulate inherited stdio.
if let SandboxType::Windows = sandbox_type {
Expand Down
22 changes: 10 additions & 12 deletions codex-rs/core/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::sandboxing::CommandSpec;
use crate::sandboxing::ExecEnv;
use crate::sandboxing::SandboxManager;
use crate::sandboxing::SandboxPermissions;
use crate::spawn::SpawnChildRequest;
use crate::spawn::StdioPolicy;
use crate::spawn::spawn_child_async;
use crate::text_encoding::bytes_to_string_smart;
Expand Down Expand Up @@ -225,7 +226,7 @@ pub(crate) async fn execute_exec_env(
let ExecEnv {
command,
cwd,
mut env,
env,
expiration,
sandbox,
windows_sandbox_level,
Expand All @@ -234,10 +235,6 @@ pub(crate) async fn execute_exec_env(
arg0,
} = env;

if let Some(network) = network.as_ref() {
network.apply_to_env(&mut env);
}

let params = ExecParams {
command,
cwd,
Expand Down Expand Up @@ -694,7 +691,7 @@ async fn exec(
command,
cwd,
env,
network: _,
network,
arg0,
expiration,
windows_sandbox_level: _,
Expand All @@ -708,15 +705,16 @@ async fn exec(
))
})?;
let arg0_ref = arg0.as_deref();
let child = spawn_child_async(
PathBuf::from(program),
args.into(),
arg0_ref,
let child = spawn_child_async(SpawnChildRequest {
program: PathBuf::from(program),
args: args.into(),
arg0: arg0_ref,
cwd,
sandbox_policy,
StdioPolicy::RedirectForShellTool,
network: network.as_ref(),
stdio_policy: StdioPolicy::RedirectForShellTool,
env,
)
})
.await?;
consume_truncated_output(child, expiration, stdout_stream).await
}
Expand Down
41 changes: 35 additions & 6 deletions codex-rs/core/src/landlock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::protocol::SandboxPolicy;
use crate::spawn::SpawnChildRequest;
use crate::spawn::StdioPolicy;
use crate::spawn::spawn_child_async;
use codex_network_proxy::has_proxy_url_env_vars;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
Expand Down Expand Up @@ -33,20 +35,29 @@ where
sandbox_policy,
sandbox_policy_cwd,
use_bwrap_sandbox,
allow_network_for_proxy(sandbox_policy, &env),
);
let arg0 = Some("codex-linux-sandbox");
spawn_child_async(
codex_linux_sandbox_exe.as_ref().to_path_buf(),
spawn_child_async(SpawnChildRequest {
program: codex_linux_sandbox_exe.as_ref().to_path_buf(),
args,
arg0,
command_cwd,
cwd: command_cwd,
sandbox_policy,
network: None,
stdio_policy,
env,
)
})
.await
}

pub(crate) fn allow_network_for_proxy(
sandbox_policy: &SandboxPolicy,
env: &HashMap<String, String>,
) -> bool {
!sandbox_policy.has_full_network_access() && has_proxy_url_env_vars(env)
}

/// Converts the sandbox policy into the CLI invocation for `codex-linux-sandbox`.
///
/// The helper performs the actual sandboxing (bubblewrap + seccomp) after
Expand All @@ -56,6 +67,7 @@ pub(crate) fn create_linux_sandbox_command_args(
sandbox_policy: &SandboxPolicy,
sandbox_policy_cwd: &Path,
use_bwrap_sandbox: bool,
allow_network_for_proxy: bool,
) -> Vec<String> {
#[expect(clippy::expect_used)]
let sandbox_policy_cwd = sandbox_policy_cwd
Expand All @@ -76,6 +88,9 @@ pub(crate) fn create_linux_sandbox_command_args(
if use_bwrap_sandbox {
linux_cmd.push("--use-bwrap-sandbox".to_string());
}
if allow_network_for_proxy {
linux_cmd.push("--allow-network-for-proxy".to_string());
}

// Separator so that command arguments starting with `-` are not parsed as
// options of the helper itself.
Expand All @@ -98,16 +113,30 @@ mod tests {
let cwd = Path::new("/tmp");
let policy = SandboxPolicy::ReadOnly;

let with_bwrap = create_linux_sandbox_command_args(command.clone(), &policy, cwd, true);
let with_bwrap =
create_linux_sandbox_command_args(command.clone(), &policy, cwd, true, false);
assert_eq!(
with_bwrap.contains(&"--use-bwrap-sandbox".to_string()),
true
);

let without_bwrap = create_linux_sandbox_command_args(command, &policy, cwd, false);
let without_bwrap = create_linux_sandbox_command_args(command, &policy, cwd, false, false);
assert_eq!(
without_bwrap.contains(&"--use-bwrap-sandbox".to_string()),
false
);
}

#[test]
fn proxy_flag_is_included_when_requested() {
let command = vec!["/bin/true".to_string()];
let cwd = Path::new("/tmp");
let policy = SandboxPolicy::ReadOnly;

let args = create_linux_sandbox_command_args(command, &policy, cwd, true, true);
assert_eq!(
args.contains(&"--allow-network-for-proxy".to_string()),
true
);
}
}
5 changes: 4 additions & 1 deletion codex-rs/core/src/sandboxing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::exec::ExecToolCallOutput;
use crate::exec::SandboxType;
use crate::exec::StdoutStream;
use crate::exec::execute_exec_env;
use crate::landlock::allow_network_for_proxy;
use crate::landlock::create_linux_sandbox_command_args;
use crate::protocol::SandboxPolicy;
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -148,7 +149,7 @@ impl SandboxManager {
let mut seatbelt_env = HashMap::new();
seatbelt_env.insert(CODEX_SANDBOX_ENV_VAR.to_string(), "seatbelt".to_string());
let mut args =
create_seatbelt_command_args(command.clone(), policy, sandbox_policy_cwd);
create_seatbelt_command_args(command.clone(), policy, sandbox_policy_cwd, &env);
let mut full_command = Vec::with_capacity(1 + args.len());
full_command.push(MACOS_PATH_TO_SEATBELT_EXECUTABLE.to_string());
full_command.append(&mut args);
Expand All @@ -159,11 +160,13 @@ impl SandboxManager {
SandboxType::LinuxSeccomp => {
let exe = codex_linux_sandbox_exe
.ok_or(SandboxTransformError::MissingLinuxSandboxExecutable)?;
let allow_proxy_network = allow_network_for_proxy(policy, &env);
let mut args = create_linux_sandbox_command_args(
command.clone(),
policy,
sandbox_policy_cwd,
use_linux_sandbox_bwrap,
allow_proxy_network,
);
let mut full_command = Vec::with_capacity(1 + args.len());
full_command.push(exe.to_string_lossy().to_string());
Expand Down
Loading
Loading