sandboxing: migrate cwd inputs to PathUri (#27816)

## Why

Sandbox cwd values can cross app-server and exec-server host boundaries.
They should retain URI semantics until the receiving host validates them
instead of being interpreted early as native paths.

## What

- Carry `PathUri` through filesystem sandbox contexts, sandbox commands,
and transform inputs.
- Convert command and policy cwd once in `SandboxManager::transform`,
then keep launch requests native.
- Preserve sandbox cwd over remote filesystem transport and reject
non-native URIs without fallback.
- Cache paired native/URI turn-environment cwd values during migration,
with immutable access to keep them synchronized.
- Extend existing protocol, forwarding, transform, and core runtime
tests.
This commit is contained in:
Adam Perry @ OpenAI authored and GitHub committed 2026-06-12 11:38:01 -07:00
1 parent 84520225b9
commit 52a50aec70
40 files changed
+546 -228

No files matched your search

+15 -13
View File
@@ -7,7 +7,6 @@ use codex_protocol::permissions::FileSystemSandboxPolicy;
use codex_protocol::permissions::FileSystemSpecialPath;
use codex_protocol::permissions::NetworkSandboxPolicy;
use codex_protocol::protocol::SandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
use std::future::Future;
use std::io;
@@ -51,7 +50,7 @@ pub struct ReadDirectoryEntry {
pub struct FileSystemSandboxContext {
pub permissions: PermissionProfile,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cwd: Option<AbsolutePathBuf>,
pub cwd: Option<PathUri>,
pub windows_sandbox_level: WindowsSandboxLevel,
#[serde(default)]
pub windows_sandbox_private_desktop: bool,
@@ -60,32 +59,35 @@ pub struct FileSystemSandboxContext {
}
impl FileSystemSandboxContext {
pub fn from_legacy_sandbox_policy(sandbox_policy: SandboxPolicy, cwd: AbsolutePathBuf) -> Self {
pub fn from_legacy_sandbox_policy(
sandbox_policy: SandboxPolicy,
cwd: PathUri,
) -> io::Result<Self> {
// Legacy policy projection materializes native roots, so convert at the receiving-host
// boundary while retaining the URI in the resulting sandbox context.
let native_cwd = cwd.to_abs_path()?;
let file_system_sandbox_policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, &cwd);
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
&sandbox_policy,
&native_cwd,
);
let permissions = PermissionProfile::from_runtime_permissions_with_enforcement(
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
&file_system_sandbox_policy,
NetworkSandboxPolicy::from(&sandbox_policy),
);
Self::from_permission_profile_with_cwd(permissions, cwd)
Ok(Self::from_permission_profile_with_cwd(permissions, cwd))
}
pub fn from_permission_profile(permissions: PermissionProfile) -> Self {
Self::from_permissions_and_cwd(permissions, /*cwd*/ None)
}
pub fn from_permission_profile_with_cwd(
permissions: PermissionProfile,
cwd: AbsolutePathBuf,
) -> Self {
pub fn from_permission_profile_with_cwd(permissions: PermissionProfile, cwd: PathUri) -> Self {
Self::from_permissions_and_cwd(permissions, Some(cwd))
}
fn from_permissions_and_cwd(
permissions: PermissionProfile,
cwd: Option<AbsolutePathBuf>,
) -> Self {
fn from_permissions_and_cwd(permissions: PermissionProfile, cwd: Option<PathUri>) -> Self {
Self {
permissions,
cwd,