mirror of
https://github.com/openai/codex.git
synced 2026-09-15 12:08:01 +00:00
## What changed - Add explicit MXC backend selection and carry its identity through exec-server process reporting and sandbox violation classification. - Launch MXC through the Codex executable with the effective permission profile and command environment. - Reject exec-server MXC requests when native MXC is unavailable or when they request a TTY, an `arg0` override, or managed networking. Reject private desktop isolation during MXC preparation. - Allow an explicitly empty child environment and avoid exposing request payload values in launcher decode errors. ## Testing Add coverage for sandbox selection and unsupported-request rejection, plus Windows RPC tests for stdin writes and temporary-directory permissions derived from the command environment. Native MXC tests skip when MXC is unavailable. GitOrigin-RevId: 3626ff0f9ad7f9b812ce09b68c31ea9a5a9c72b1
113 lines
4.1 KiB
Rust
113 lines
4.1 KiB
Rust
//! Shared Windows sandbox behavior over the real exec-server RPC connection.
|
|
|
|
use super::*;
|
|
use codex_protocol::models::PermissionProfile;
|
|
use codex_protocol::permissions::FileSystemAccessMode;
|
|
use codex_protocol::permissions::FileSystemPath;
|
|
use codex_protocol::permissions::FileSystemSandboxEntry;
|
|
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
|
use codex_protocol::permissions::FileSystemSpecialPath;
|
|
use codex_protocol::permissions::NetworkSandboxPolicy;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[cfg_attr(not(windows), ignore = "requires a native Windows sandbox")]
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
#[serial_test::serial(remote_exec_server)]
|
|
async fn mxc_tmpdir_uses_command_environment_over_rpc() -> Result<()> {
|
|
if !selected_windows_sandbox_available(WindowsSandboxLevel::Mxc) {
|
|
eprintln!("skipping MXC enforcement test: native MXC is unavailable on this host");
|
|
return Ok(());
|
|
}
|
|
let root = TempDir::new()?;
|
|
let command_temp = root.path().join("command temp");
|
|
let server_temp = root.path().join("server temp");
|
|
std::fs::create_dir(&command_temp)?;
|
|
std::fs::create_dir(&server_temp)?;
|
|
let outside = server_temp.join("outside.txt");
|
|
std::fs::write(&outside, "original")?;
|
|
let server = common::exec_server::exec_server_with_env(
|
|
[
|
|
("TEMP", server_temp.as_os_str()),
|
|
("TMP", server_temp.as_os_str()),
|
|
],
|
|
&[],
|
|
)
|
|
.await?;
|
|
let environment = Environment::create_for_tests(Some(server.websocket_url().to_owned()))?;
|
|
let cwd = PathUri::from_host_native_path(root.path())?;
|
|
let fs = FileSystemSandboxPolicy::restricted(vec![
|
|
FileSystemSandboxEntry::new(
|
|
FileSystemPath::Special {
|
|
value: FileSystemSpecialPath::Root,
|
|
},
|
|
FileSystemAccessMode::Read,
|
|
),
|
|
FileSystemSandboxEntry::new(
|
|
FileSystemPath::Special {
|
|
value: FileSystemSpecialPath::Tmpdir,
|
|
},
|
|
FileSystemAccessMode::Write,
|
|
),
|
|
]);
|
|
let mut sandbox = FileSystemSandboxContext::from_permission_profile_with_cwd(
|
|
PermissionProfile::from_runtime_permissions(&fs, NetworkSandboxPolicy::Restricted),
|
|
cwd.clone(),
|
|
);
|
|
sandbox.windows_sandbox_level = WindowsSandboxLevel::Mxc;
|
|
let command_temp = command_temp.to_string_lossy().into_owned();
|
|
let started = environment
|
|
.get_exec_backend()
|
|
.start(ExecParams {
|
|
process_id: ProcessId::from("windows-sandbox-temp"),
|
|
metadata: None,
|
|
argv: vec![
|
|
r"C:\Windows\System32\cmd.exe".to_owned(),
|
|
"/D".to_owned(),
|
|
"/S".to_owned(),
|
|
"/C".to_owned(),
|
|
format!(
|
|
"echo allowed>\"%TEMP%\\allowed.txt\" & 2>\"%TEMP%\\denied.txt\" echo modified>\"{}\" & exit /b 0",
|
|
outside.display()
|
|
),
|
|
],
|
|
cwd,
|
|
env_policy: None,
|
|
shell_snapshot: None,
|
|
env: HashMap::from([
|
|
("SystemRoot".to_owned(), std::env::var("SystemRoot")?),
|
|
("TEMP".to_owned(), command_temp.clone()),
|
|
("TMP".to_owned(), command_temp),
|
|
]),
|
|
tty: false,
|
|
pipe_stdin: false,
|
|
arg0: None,
|
|
sandbox: Some(sandbox),
|
|
enforce_managed_network: false,
|
|
managed_network: None,
|
|
network_proxy: None,
|
|
})
|
|
.await?;
|
|
assert_eq!(
|
|
started.sandbox_type,
|
|
Some(codex_sandboxing::SandboxType::WindowsMxc)
|
|
);
|
|
assert_eq!(
|
|
collect_process_output_from_events_with_timeout(
|
|
started.process,
|
|
Duration::from_secs(/*secs*/ 30),
|
|
)
|
|
.await?,
|
|
(String::new(), String::new(), Some(0), true)
|
|
);
|
|
assert_eq!(
|
|
(
|
|
std::fs::read_to_string(root.path().join("command temp").join("allowed.txt"))?
|
|
.trim_end()
|
|
.to_owned(),
|
|
std::fs::read_to_string(outside)?
|
|
),
|
|
("allowed".to_owned(), "original".to_owned())
|
|
);
|
|
Ok(())
|
|
}
|