Route sandbox CLI launches through the shared sandbox manager (#60517)

## What changed

- Use `SandboxManager` to prepare `codex sandbox` commands, including permission profiles, workspace roots, and managed network proxy settings.
- Return a `WrappedSandboxCommand` that can produce an execution request or a configured process command, preserving native executable paths and Linux helper `argv[0]`. Require the session launcher for native Windows token sandboxes.
- Move macOS inherited-terminal policy handling into the shared manager, retaining Unix socket grants and the terminal input injection denial.
- Prepare managed network context alongside proxy environment variables and pass it through sandbox transformation.

## Testing

- Extend sandbox network proxy tests to macOS, covering blocked direct loopback access and explicitly allowed requests.
- Add coverage for Linux helper executable paths and dispatch names, including non-UTF-8 paths.

GitOrigin-RevId: 8b7396d21b2f34122699388f16047329a3f5e5c6
This commit is contained in:
viyatb-oai
2026-11-10 04:01:23 +00:00
committed by copyberry
parent 551fc719d6
commit d2efdf1986
12 changed files with 353 additions and 308 deletions
+11 -8
View File
@@ -350,7 +350,7 @@ pub async fn build_exec_request(
let ExecParams {
command,
cwd,
mut env,
env,
expiration,
capture_policy,
network,
@@ -372,13 +372,16 @@ pub async fn build_exec_request(
);
tracing::debug!("Sandbox type: {sandbox_type:?}");
if let Some(network) = network.as_ref() {
network
.apply_to_env_for_optional_environment(&mut env, network_environment_id.as_deref())
let (env, managed_network) = if let Some(network) = network.as_ref() {
let prepared = network
.prepare_for_optional_environment(env, network_environment_id.as_deref())
.map_err(|err| {
network_proxy_environment_error(network_environment_id.as_deref(), err)
})?;
}
(prepared.env, Some(prepared.sandbox_context))
} else {
(env, None)
};
let (program, args) = command.split_first().ok_or_else(|| {
CodexErr::Io(io::Error::new(
io::ErrorKind::InvalidInput,
@@ -394,7 +397,7 @@ pub async fn build_exec_request(
args: args.to_vec(),
cwd,
env,
managed_network: None,
managed_network,
additional_permissions: None,
};
let options = ExecOptions {
@@ -418,8 +421,8 @@ pub async fn build_exec_request(
},
use_legacy_landlock,
windows_sandbox_level,
})
.map_err(CodexErr::from)?;
})?
.into_command_request();
// These hints belong to the native Windows backend. Other backends use
// the materialized profile and must not project executor paths onto this host.
let windows_sandbox_workspace_roots = if sandbox_type == SandboxType::WindowsRestrictedToken {
+2 -1
View File
@@ -174,7 +174,8 @@ impl ShellSnapshotSandbox {
use_legacy_landlock: self.use_legacy_landlock,
windows_sandbox_level: self.windows_sandbox_level,
})
.context("failed to prepare shell snapshot sandbox")?;
.context("failed to prepare shell snapshot sandbox")?
.into_command_request();
let workspace_roots = self
.workspace_roots
.iter()
+4 -4
View File
@@ -513,8 +513,8 @@ impl<'a> SandboxAttempt<'a> {
sandbox_exe: self.sandbox_exe.map(std::path::PathBuf::as_path),
use_legacy_landlock: self.use_legacy_landlock,
windows_sandbox_level: self.windows_sandbox_level,
})
.map_err(CodexErr::from)?;
})?
.into_command_request();
request.sandbox_override = self.sandbox_override;
let workspace_roots = self
.workspace_roots
@@ -550,8 +550,8 @@ impl<'a> SandboxAttempt<'a> {
sandbox_exe: None,
use_legacy_landlock: self.use_legacy_landlock,
windows_sandbox_level: self.windows_sandbox_level,
})
.map_err(CodexErr::from)?;
})?
.into_command_request();
request.sandbox_override = self.sandbox_override;
let mut exec_request =
crate::sandboxing::ExecRequest::from_sandbox_exec_request(request, options, Vec::new())