From bdda5da56cae0a9fedf3428ac6d308767b4518f9 Mon Sep 17 00:00:00 2001 From: jif Date: Thu, 30 Jul 2026 11:05:20 +0000 Subject: [PATCH] Preserve executor workspace permissions for apply_patch (#36133) ## What changed Build the `apply_patch` filesystem sandbox context from the executor's canonical permission profile instead of the execution attempt's materialized profile. Continue merging any additional permissions requested by the patch while keeping workspace roots scoped separately to the attempt. ## Testing - Update the sandbox-context test to verify that executor `workspace-write` permissions are preserved when attempt workspace roots and additional file permissions are present. GitOrigin-RevId: 2a9a8c2e1b1945e300283c400d0f1e573225a553 --- codex-rs/core/src/tools/runtimes/apply_patch.rs | 6 ++++-- .../core/src/tools/runtimes/apply_patch_tests.rs | 15 +++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/codex-rs/core/src/tools/runtimes/apply_patch.rs b/codex-rs/core/src/tools/runtimes/apply_patch.rs index 2d59a4de0a..702f342bf9 100644 --- a/codex-rs/core/src/tools/runtimes/apply_patch.rs +++ b/codex-rs/core/src/tools/runtimes/apply_patch.rs @@ -91,8 +91,10 @@ impl ApplyPatchRuntime { return None; } - let permissions = - effective_permission_profile(attempt.permissions, req.additional_permissions.as_ref()); + let permissions = effective_permission_profile( + attempt.exec_server_permissions, + req.additional_permissions.as_ref(), + ); Some(FileSystemSandboxContext { permissions: permissions.into(), cwd: Some(attempt.sandbox_cwd.clone()), diff --git a/codex-rs/core/src/tools/runtimes/apply_patch_tests.rs b/codex-rs/core/src/tools/runtimes/apply_patch_tests.rs index 844612c478..3a879de8c9 100644 --- a/codex-rs/core/src/tools/runtimes/apply_patch_tests.rs +++ b/codex-rs/core/src/tools/runtimes/apply_patch_tests.rs @@ -4,7 +4,6 @@ use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::models::AdditionalPermissionProfile; use codex_protocol::models::FileSystemPermissions; use codex_protocol::models::PermissionProfile; -use codex_protocol::permissions::FileSystemSandboxPolicy; use codex_protocol::permissions::NetworkSandboxPolicy; use codex_protocol::protocol::GranularApprovalConfig; use codex_sandboxing::SandboxManager; @@ -179,7 +178,7 @@ async fn sandbox_cwd_uses_patch_action_cwd() { } #[tokio::test] -async fn file_system_sandbox_context_uses_active_attempt() { +async fn file_system_sandbox_context_preserves_executor_workspace_permissions() { let path = std::env::temp_dir() .join("apply-patch-runtime-attempt.txt") .abs(); @@ -205,18 +204,18 @@ async fn file_system_sandbox_context_uses_active_attempt() { additional_permissions: Some(additional_permissions.clone()), permissions_preapproved: false, }; - let file_system_policy = FileSystemSandboxPolicy::default(); - let permissions = PermissionProfile::from_runtime_permissions( - &file_system_policy, - NetworkSandboxPolicy::Restricted, - ); + let exec_server_permissions = PermissionProfile::workspace_write(); + let file_system_policy = exec_server_permissions.file_system_sandbox_policy(); + let permissions = exec_server_permissions + .clone() + .materialize_project_roots_with_workspace_roots(std::slice::from_ref(&path)); let manager = SandboxManager::new(); let sandbox_policy_cwd = PathUri::from_abs_path(&path); let attempt = SandboxAttempt { sandbox: SandboxType::MacosSeatbelt, sandbox_requested: true, permissions: &permissions, - exec_server_permissions: &permissions, + exec_server_permissions: &exec_server_permissions, enforce_managed_network: false, manager: &manager, sandbox_cwd: &sandbox_policy_cwd,