Files
codex/codex-rs/sandboxing/src/launch.rs
T
viyatb-oai 9a7213ca37 Resolve workspace permissions at the sandbox launch boundary (#59530)
## What changed

Add optional executor workspace roots to `SandboxTransformRequest` and resolve symbolic workspace rules after merging additional permissions. Preserve explicit deny rules and treat an empty root list as granting no workspace access.

Route Windows restricted-token preparation through the shared transform path and use explicit roots when building its direct-spawn wrapper. Update Windows MXC debug launches to bind configured roots before adding the managed CA read grant.

## Testing

Extend sandbox manager tests to cover workspace and subpath expansion, empty root lists, deny preservation, and the roots and write permissions serialized into the Windows wrapper.

GitOrigin-RevId: 0bebdb08b67cbbc182c18b031b9d13a21a799682
2026-11-05 00:30:20 +00:00

56 lines
1.9 KiB
Rust

//! Bind filesystem and network inputs for sandbox preparation on the execution host.
use std::io;
use codex_protocol::models::PermissionProfile;
use codex_protocol::permissions::FileSystemPath;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
/// The authorized profile, resolved on the host that will enforce it.
#[derive(Debug)]
pub(super) struct PreparedLaunchPolicy {
pub(super) permissions: PermissionProfile,
}
impl PreparedLaunchPolicy {
/// An empty workspace list stays empty, even when the policy contains `:workspace_roots`.
pub(super) fn resolve(
permissions: PermissionProfile,
policy_cwd: &PathUri,
roots: Option<&[PathUri]>,
) -> io::Result<Self> {
let Some(roots) = roots else {
return Ok(Self { permissions });
};
native_path(policy_cwd, "sandbox policy cwd")?;
let workspace_roots = native_workspace_roots(roots)?;
let (file_system, network) = permissions.to_runtime_permissions();
for entry in &file_system.entries {
if let FileSystemPath::Path { path } = &entry.path {
native_path(path, "sandbox permission path")?;
}
}
let file_system =
file_system.materialize_project_roots_with_workspace_roots(&workspace_roots);
let permissions = PermissionProfile::from_runtime_permissions_with_enforcement(
permissions.enforcement(),
&file_system,
network,
);
Ok(Self { permissions })
}
}
pub(super) fn native_workspace_roots(roots: &[PathUri]) -> io::Result<Vec<AbsolutePathBuf>> {
roots
.iter()
.map(|root| native_path(root, "sandbox workspace root"))
.collect::<io::Result<Vec<_>>>()
}
fn native_path(path: &PathUri, field: &str) -> io::Result<AbsolutePathBuf> {
path.to_abs_path()
.map_err(|err| io::Error::new(err.kind(), format!("invalid {field}: {err}")))
}