Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codex-rs/cli/src/debug_sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ async fn run_command_under_sandbox(
network_sandbox_policy,
sandbox_policy_cwd: sandbox_policy_cwd.as_path(),
enforce_managed_network,
managed_network: None,
environment_id: None,
network: network.as_ref(),
extra_allow_unix_sockets: allow_unix_sockets,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/core/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ pub fn build_exec_request(
args: args.to_vec(),
cwd,
env,
managed_network: None,
additional_permissions: None,
};
let options = ExecOptions {
Expand Down Expand Up @@ -458,6 +459,7 @@ pub(crate) async fn execute_exec_request(
arg0,
exec_server_sandbox: _,
exec_server_enforce_managed_network: _,
exec_server_managed_network: _,
} = exec_request;

// TODO(anp): Keep PathUri through the local process launch boundary.
Expand Down
4 changes: 4 additions & 0 deletions codex-rs/core/src/sandboxing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::exec::execute_exec_request;
use crate::spawn::CODEX_SANDBOX_ENV_VAR;
use crate::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR;
use codex_file_system::FileSystemSandboxContext;
use codex_network_proxy::ManagedNetworkSandboxContext;
use codex_network_proxy::NetworkProxy;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::exec_output::ExecToolCallOutput;
Expand Down Expand Up @@ -63,6 +64,7 @@ pub struct ExecRequest {
pub arg0: Option<String>,
pub(crate) exec_server_sandbox: Option<FileSystemSandboxContext>,
pub(crate) exec_server_enforce_managed_network: bool,
pub(crate) exec_server_managed_network: Option<ManagedNetworkSandboxContext>,
}

impl ExecRequest {
Expand Down Expand Up @@ -107,6 +109,7 @@ impl ExecRequest {
arg0,
exec_server_sandbox: None,
exec_server_enforce_managed_network: false,
exec_server_managed_network: None,
}
}

Expand Down Expand Up @@ -165,6 +168,7 @@ impl ExecRequest {
arg0,
exec_server_sandbox: None,
exec_server_enforce_managed_network: false,
exec_server_managed_network: None,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/src/tasks/user_shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ pub(crate) async fn execute_user_shell_command(
arg0: None,
exec_server_sandbox: None,
exec_server_enforce_managed_network: false,
exec_server_managed_network: None,
};

let stdout_stream = Some(StdoutStream {
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/src/tools/runtimes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub(crate) fn build_sandbox_command(
args: args.to_vec(),
cwd,
env: env.clone(),
managed_network: None,
additional_permissions,
})
}
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ pub(super) async fn try_run_zsh_fork(
arg0,
exec_server_sandbox: _,
exec_server_enforce_managed_network: _,
exec_server_managed_network: _,
} = sandbox_exec_request;
let ParsedShellCommand { script, login, .. } = extract_shell_script(&command)?;
let effective_timeout = Duration::from_millis(
Expand Down Expand Up @@ -902,6 +903,7 @@ impl CoreShellCommandExecutor {
arg0: self.arg0.clone(),
exec_server_sandbox: None,
exec_server_enforce_managed_network: false,
exec_server_managed_network: None,
},
/*stdout_stream*/ None,
after_spawn,
Expand Down Expand Up @@ -1010,6 +1012,7 @@ impl CoreShellCommandExecutor {
args: args.to_vec(),
cwd,
env,
managed_network: None,
additional_permissions,
};
let options = ExecOptions {
Expand Down
39 changes: 25 additions & 14 deletions codex-rs/core/src/tools/runtimes/unified_exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use crate::unified_exec::NoopSpawnLifecycle;
use crate::unified_exec::UnifiedExecError;
use crate::unified_exec::UnifiedExecProcess;
use crate::unified_exec::UnifiedExecProcessManager;
use codex_network_proxy::ManagedNetworkSandboxContext;
use codex_network_proxy::NetworkProxy;
use codex_protocol::error::CodexErr;
use codex_protocol::error::SandboxErr;
Expand Down Expand Up @@ -117,6 +118,7 @@ fn build_unified_exec_sandbox_command(
command: &[String],
cwd: &PathUri,
env: &HashMap<String, String>,
managed_network: Option<ManagedNetworkSandboxContext>,
additional_permissions: Option<AdditionalPermissionProfile>,
) -> Result<SandboxCommand, ToolError> {
let (program, args) = command
Expand All @@ -127,6 +129,7 @@ fn build_unified_exec_sandbox_command(
args: args.to_vec(),
cwd: cwd.clone(),
env: env.clone(),
managed_network,
additional_permissions,
})
}
Expand Down Expand Up @@ -321,22 +324,28 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
req.network.as_ref(),
launch_sandbox_permissions,
);
let mut env = exec_env_for_sandbox_permissions(&req.env, launch_sandbox_permissions);
if let Some(network) = managed_network {
network
.apply_to_env_for_optional_environment(
&mut env,
Some(&req.turn_environment.environment_id),
)
.map_err(|err| {
ToolError::Codex(CodexErr::Io(io::Error::other(format!(
"failed to prepare network proxy for environment `{}`: {err}",
req.turn_environment.environment_id
))))
})?;
}
let env = exec_env_for_sandbox_permissions(&req.env, launch_sandbox_permissions);
let (env, managed_network_context) = match managed_network {
Some(network) => {
let prepared = network
.prepare_for_optional_environment(
env,
Some(&req.turn_environment.environment_id),
)
.map_err(|err| {
ToolError::Codex(CodexErr::Io(io::Error::other(format!(
"failed to prepare network proxy for environment `{}`: {err}",
req.turn_environment.environment_id
))))
})?;
(prepared.env, Some(prepared.sandbox_context))
}
None => (env, None),
};
let explicit_env_overrides = req.explicit_env_overrides.clone();
#[cfg(unix)]
let mut env = env;
#[cfg(unix)]
let runtime_path_prepends = {
let mut runtime_path_prepends = RuntimePathPrepends::default();
if !environment_is_remote {
Expand Down Expand Up @@ -385,6 +394,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
&command,
&req.cwd,
&env,
managed_network_context.clone(),
req.additional_permissions.clone(),
)
.map_err(|error| match error {
Expand Down Expand Up @@ -450,6 +460,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
&command,
&req.cwd,
&env,
managed_network_context,
req.additional_permissions.clone(),
)
.map_err(|error| match error {
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/core/src/tools/sandboxing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ impl<'a> SandboxAttempt<'a> {
network: Option<&NetworkProxy>,
environment_id: Option<&str>,
) -> Result<crate::sandboxing::ExecRequest, CodexErr> {
let managed_network = command.managed_network.clone();
let exec_server_permissions = effective_permission_profile(
self.exec_server_permissions,
command.additional_permissions.as_ref(),
Expand Down Expand Up @@ -502,6 +503,7 @@ impl<'a> SandboxAttempt<'a> {
use_legacy_landlock: self.use_legacy_landlock,
});
exec_request.exec_server_enforce_managed_network = self.enforce_managed_network;
exec_request.exec_server_managed_network = managed_network;
}
Ok(exec_request)
}
Expand Down
8 changes: 7 additions & 1 deletion codex-rs/core/src/tools/sandboxing_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::*;
use crate::sandboxing::SandboxPermissions;
use crate::tools::hook_names::HookToolName;
use codex_network_proxy::ManagedNetworkSandboxContext;
use codex_protocol::permissions::FileSystemAccessMode;
use codex_protocol::permissions::FileSystemPath;
use codex_protocol::permissions::FileSystemSandboxEntry;
Expand Down Expand Up @@ -227,18 +228,22 @@ fn exec_server_env_keeps_command_native_and_carries_sandbox_context() {
windows_sandbox_private_desktop: false,
network_denial_cancellation_token: None,
};
let managed_network = ManagedNetworkSandboxContext {
loopback_ports: vec![43123],
allow_local_binding: false,
};
let command = SandboxCommand {
program: "/bin/bash".into(),
args: vec!["-lc".to_string(), "pwd".to_string()],
cwd: cwd_uri.clone(),
env: HashMap::new(),
managed_network: Some(managed_network.clone()),
additional_permissions: None,
};
let options = crate::sandboxing::ExecOptions {
expiration: crate::exec::ExecExpiration::DefaultTimeout,
capture_policy: crate::exec::ExecCapturePolicy::ShellTool,
};

let request = attempt
.env_for_exec_server(command, options, /*network*/ None, Some("remote"))
.expect("prepare remote exec request");
Expand All @@ -265,4 +270,5 @@ fn exec_server_env_keeps_command_native_and_carries_sandbox_context() {
})
);
assert!(request.exec_server_enforce_managed_network);
assert_eq!(request.exec_server_managed_network, Some(managed_network));
}
23 changes: 19 additions & 4 deletions codex-rs/core/src/unified_exec/process_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ use crate::unified_exec::process::OutputBuffer;
use crate::unified_exec::process::OutputHandles;
use crate::unified_exec::process::SpawnLifecycleHandle;
use crate::unified_exec::process::UnifiedExecProcess;
use codex_network_proxy::CUSTOM_CA_ENV_KEYS;
use codex_network_proxy::NetworkProxy;
use codex_network_proxy::PROXY_ENV_KEYS;
#[cfg(target_os = "macos")]
use codex_network_proxy::PROXY_GIT_SSH_COMMAND_ENV_KEY;
use codex_protocol::config_types::ShellEnvironmentPolicy;
use codex_protocol::error::CodexErr;
use codex_protocol::error::SandboxErr;
Expand Down Expand Up @@ -142,10 +146,20 @@ fn exec_server_env_for_request(
HashMap<String, String>,
) {
if let Some(exec_server_env_config) = &request.exec_server_env_config {
(
Some(exec_server_env_config.policy.clone()),
env_overlay_for_exec_server(&request.env, &exec_server_env_config.local_policy_env),
)
let mut env =
env_overlay_for_exec_server(&request.env, &exec_server_env_config.local_policy_env);
if request.exec_server_managed_network.is_some() {
for key in PROXY_ENV_KEYS.iter().chain(CUSTOM_CA_ENV_KEYS.iter()) {
if let Some(value) = request.env.get(*key) {
env.insert((*key).to_string(), value.clone());
}
}
#[cfg(target_os = "macos")]
if let Some(value) = request.env.get(PROXY_GIT_SSH_COMMAND_ENV_KEY) {
env.insert(PROXY_GIT_SSH_COMMAND_ENV_KEY.to_string(), value.clone());
}
}
(Some(exec_server_env_config.policy.clone()), env)
} else {
(None, request.env.clone())
}
Expand All @@ -168,6 +182,7 @@ fn exec_server_params_for_request(
arg0: request.arg0.clone(),
sandbox: request.exec_server_sandbox.clone(),
enforce_managed_network: request.exec_server_enforce_managed_network,
managed_network: request.exec_server_managed_network.clone(),
}
}

Expand Down
25 changes: 24 additions & 1 deletion codex-rs/core/src/unified_exec/process_manager_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use crate::unified_exec::clamp_yield_time;
use codex_network_proxy::ManagedNetworkSandboxContext;
use pretty_assertions::assert_eq;
use tokio::time::Duration;
use tokio::time::Instant;
Expand Down Expand Up @@ -76,13 +77,22 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() {
codex_protocol::permissions::FileSystemSandboxPolicy::unrestricted();
let network_sandbox_policy = codex_protocol::permissions::NetworkSandboxPolicy::Restricted;
let permission_profile = codex_protocol::models::PermissionProfile::Disabled;
let managed_network = ManagedNetworkSandboxContext {
loopback_ports: vec![43123],
allow_local_binding: false,
};
let request = ExecRequest {
command: vec!["bash".to_string(), "-lc".to_string(), "true".to_string()],
cwd: cwd.clone().into(),
env: HashMap::from([
("HOME".to_string(), "/client-home".to_string()),
("PATH".to_string(), "/sandbox-path".to_string()),
("CODEX_THREAD_ID".to_string(), "thread-1".to_string()),
(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43123".to_string(),
),
("CODEX_NETWORK_PROXY_ACTIVE".to_string(), "1".to_string()),
]),
exec_server_env_config: Some(ExecServerEnvConfig {
policy: codex_exec_server::ExecEnvPolicy {
Expand All @@ -95,6 +105,11 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() {
local_policy_env: HashMap::from([
("HOME".to_string(), "/client-home".to_string()),
("PATH".to_string(), "/client-path".to_string()),
(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43123".to_string(),
),
("CODEX_NETWORK_PROXY_ACTIVE".to_string(), "1".to_string()),
]),
}),
network: None,
Expand All @@ -112,20 +127,28 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() {
windows_sandbox_filesystem_overrides: None,
arg0: None,
exec_server_sandbox: None,
exec_server_enforce_managed_network: false,
exec_server_enforce_managed_network: true,
exec_server_managed_network: Some(managed_network.clone()),
};

let params =
exec_server_params_for_request(/*process_id*/ 123, &request, /*tty*/ true);

assert_eq!(params.process_id.as_str(), "123");
assert_eq!(params.cwd, request.cwd);
assert!(params.enforce_managed_network);
assert_eq!(params.managed_network, Some(managed_network));
assert!(params.env_policy.is_some());
assert_eq!(
params.env,
HashMap::from([
("PATH".to_string(), "/sandbox-path".to_string()),
("CODEX_THREAD_ID".to_string(), "thread-1".to_string()),
(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43123".to_string(),
),
("CODEX_NETWORK_PROXY_ACTIVE".to_string(), "1".to_string(),),
])
);
}
Expand Down
1 change: 1 addition & 0 deletions codex-rs/exec-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ codex-app-server-protocol = { workspace = true }
codex-api = { workspace = true }
codex-client = { workspace = true }
codex-file-system = { workspace = true }
codex-network-proxy = { workspace = true }
Comment thread
jif-oai marked this conversation as resolved.
codex-protocol = { workspace = true }
codex-sandboxing = { workspace = true }
codex-shell-command = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/exec-server/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,7 @@ mod tests {
arg0: None,
sandbox: None,
enforce_managed_network: false,
managed_network: None,
})
.await
.expect("start process");
Expand Down Expand Up @@ -1197,6 +1198,7 @@ mod tests {
arg0: None,
sandbox: Some(sandbox),
enforce_managed_network: false,
managed_network: None,
})
.await;
let Err(err) = result else {
Expand Down
1 change: 1 addition & 0 deletions codex-rs/exec-server/src/fs_sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ impl FileSystemSandboxRunner {
args: vec![CODEX_FS_HELPER_ARG1.to_string()],
cwd: cwd.uri.clone(),
env: self.helper_env.clone(),
managed_network: None,
additional_permissions: None,
};
let native_workspace_roots = sandbox_context
Expand Down
1 change: 1 addition & 0 deletions codex-rs/exec-server/src/local_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,7 @@ mod tests {
arg0: None,
sandbox: None,
enforce_managed_network: false,
managed_network: None,
}
}

Expand Down
Loading
Loading