Skip to content
Merged
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
29 changes: 16 additions & 13 deletions codex-rs/core/src/session/turn_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ impl TurnContext {
) -> FileSystemSandboxContext {
FileSystemSandboxContext {
sandbox_policy: self.sandbox_policy.get().clone(),
sandbox_policy_cwd: Some(self.cwd.clone()),
file_system_sandbox_policy: self.non_legacy_file_system_sandbox_policy(),
windows_sandbox_level: self.windows_sandbox_level,
windows_sandbox_private_desktop: self
.config
Expand All @@ -219,25 +221,26 @@ impl TurnContext {
}
}

fn non_legacy_file_system_sandbox_policy(&self) -> Option<FileSystemSandboxPolicy> {
// Omit the derived split filesystem policy when it is equivalent to
// the legacy sandbox policy. This keeps turn-context payloads stable
// while both fields exist; once callers consume only the split policy,
// this comparison and the legacy projection should go away.
let legacy_file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
self.sandbox_policy.get(),
&self.cwd,
);
(self.file_system_sandbox_policy != legacy_file_system_sandbox_policy)
.then(|| self.file_system_sandbox_policy.clone())
}

pub(crate) fn compact_prompt(&self) -> &str {
self.compact_prompt
.as_deref()
.unwrap_or(compact::SUMMARIZATION_PROMPT)
}

pub(crate) fn to_turn_context_item(&self) -> TurnContextItem {
let legacy_file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
self.sandbox_policy.get(),
&self.cwd,
);
// Omit the derived split filesystem policy when it is equivalent to
// the legacy sandbox policy. This keeps turn-context payloads stable
// while both fields exist; once callers consume only the split policy,
// this comparison and the legacy projection should go away.
let file_system_sandbox_policy = (self.file_system_sandbox_policy
!= legacy_file_system_sandbox_policy)
.then(|| self.file_system_sandbox_policy.clone());

TurnContextItem {
turn_id: Some(self.sub_id.clone()),
trace_id: self.trace_id.clone(),
Expand All @@ -247,7 +250,7 @@ impl TurnContext {
approval_policy: self.approval_policy.value(),
sandbox_policy: self.sandbox_policy.get().clone(),
network: self.turn_context_network_item(),
file_system_sandbox_policy,
file_system_sandbox_policy: self.non_legacy_file_system_sandbox_policy(),
model: self.model_info.slug.clone(),
personality: self.personality,
collaboration_mode: Some(self.collaboration_mode.clone()),
Expand Down
11 changes: 11 additions & 0 deletions codex-rs/core/src/tools/runtimes/apply_patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use codex_protocol::error::SandboxErr;
use codex_protocol::exec_output::ExecToolCallOutput;
use codex_protocol::exec_output::StreamOutput;
use codex_protocol::models::PermissionProfile;
use codex_protocol::permissions::FileSystemSandboxPolicy;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::Event;
use codex_protocol::protocol::EventMsg;
Expand Down Expand Up @@ -74,8 +75,18 @@ impl ApplyPatchRuntime {
return None;
}

let legacy_file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
attempt.policy,
attempt.sandbox_cwd,
);
let file_system_sandbox_policy = (attempt.file_system_policy
!= &legacy_file_system_sandbox_policy)
.then(|| attempt.file_system_policy.clone());

Some(FileSystemSandboxContext {
sandbox_policy: attempt.policy.clone(),
sandbox_policy_cwd: Some(attempt.sandbox_cwd.clone()),
file_system_sandbox_policy,
windows_sandbox_level: attempt.windows_sandbox_level,
windows_sandbox_private_desktop: attempt.windows_sandbox_private_desktop,
use_legacy_landlock: attempt.use_legacy_landlock,
Expand Down
56 changes: 55 additions & 1 deletion codex-rs/core/src/tools/runtimes/apply_patch_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use crate::tools::sandboxing::SandboxAttempt;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::models::FileSystemPermissions;
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::NetworkSandboxPolicy;
use codex_protocol::protocol::GranularApprovalConfig;
Expand Down Expand Up @@ -99,7 +102,12 @@ fn file_system_sandbox_context_uses_active_attempt() {
permissions_preapproved: false,
};
let sandbox_policy = SandboxPolicy::new_read_only_policy();
let file_system_policy = FileSystemSandboxPolicy::from(&sandbox_policy);
let mut file_system_policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, path.as_path());
file_system_policy.entries.push(FileSystemSandboxEntry {
path: FileSystemPath::Path { path: path.clone() },
access: FileSystemAccessMode::None,
});
let manager = SandboxManager::new();
let attempt = SandboxAttempt {
sandbox: SandboxType::MacosSeatbelt,
Expand All @@ -119,6 +127,11 @@ fn file_system_sandbox_context_uses_active_attempt() {
.expect("sandbox context");

assert_eq!(sandbox.sandbox_policy, sandbox_policy);
assert_eq!(sandbox.sandbox_policy_cwd, Some(path.clone()));
assert_eq!(
sandbox.file_system_sandbox_policy,
Some(file_system_policy.clone())
);
assert_eq!(sandbox.additional_permissions, Some(additional_permissions));
assert_eq!(
sandbox.windows_sandbox_level,
Expand All @@ -128,6 +141,47 @@ fn file_system_sandbox_context_uses_active_attempt() {
assert_eq!(sandbox.use_legacy_landlock, true);
}

#[test]
fn file_system_sandbox_context_omits_legacy_equivalent_policy() {
let path = std::env::temp_dir()
.join("apply-patch-runtime-legacy-equivalent.txt")
.abs();
let req = ApplyPatchRequest {
action: ApplyPatchAction::new_add_for_test(&path, "hello".to_string()),
file_paths: vec![path.clone()],
changes: HashMap::new(),
exec_approval_requirement: ExecApprovalRequirement::Skip {
bypass_sandbox: false,
proposed_execpolicy_amendment: None,
},
additional_permissions: None,
permissions_preapproved: false,
};
let sandbox_policy = SandboxPolicy::new_read_only_policy();
let file_system_policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, path.as_path());
let manager = SandboxManager::new();
let attempt = SandboxAttempt {
sandbox: SandboxType::MacosSeatbelt,
policy: &sandbox_policy,
file_system_policy: &file_system_policy,
network_policy: NetworkSandboxPolicy::Restricted,
enforce_managed_network: false,
manager: &manager,
sandbox_cwd: &path,
codex_linux_sandbox_exe: None,
use_legacy_landlock: true,
windows_sandbox_level: WindowsSandboxLevel::RestrictedToken,
windows_sandbox_private_desktop: true,
};

let sandbox = ApplyPatchRuntime::file_system_sandbox_context_for_attempt(&req, &attempt)
.expect("sandbox context");

assert_eq!(sandbox.sandbox_policy_cwd, Some(path));
assert_eq!(sandbox.file_system_sandbox_policy, None);
}

#[test]
fn no_sandbox_attempt_has_no_file_system_context() {
let path = std::env::temp_dir()
Expand Down
7 changes: 7 additions & 0 deletions codex-rs/exec-server/src/file_system.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use async_trait::async_trait;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::models::PermissionProfile;
use codex_protocol::permissions::FileSystemSandboxPolicy;
use codex_protocol::protocol::SandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
use tokio::io;
Expand Down Expand Up @@ -41,6 +42,10 @@ pub struct ReadDirectoryEntry {
#[serde(rename_all = "camelCase")]
pub struct FileSystemSandboxContext {
pub sandbox_policy: SandboxPolicy,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sandbox_policy_cwd: Option<AbsolutePathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub file_system_sandbox_policy: Option<FileSystemSandboxPolicy>,
pub windows_sandbox_level: WindowsSandboxLevel,
#[serde(default)]
pub windows_sandbox_private_desktop: bool,
Expand All @@ -53,6 +58,8 @@ impl FileSystemSandboxContext {
pub fn new(sandbox_policy: SandboxPolicy) -> Self {
Self {
sandbox_policy,
sandbox_policy_cwd: None,
file_system_sandbox_policy: None,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
use_legacy_landlock: false,
Expand Down
Loading
Loading