diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 6e9358806f..4fcaf7dadb 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -449,16 +449,12 @@ impl Permissions { self.permission_profile_state.profile_workspace_roots() } - fn materialized_permission_profile(&self) -> PermissionProfile { - self.permission_profile() - .clone() - .materialize_project_roots_with_workspace_roots(&self.workspace_roots) - } - /// Effective runtime permissions after config requirements and runtime /// workspace-root materialization have been applied. pub fn effective_permission_profile(&self) -> PermissionProfile { - self.materialized_permission_profile() + self.permission_profile() + .clone() + .materialize_project_roots_with_workspace_roots(&self.workspace_roots) } /// Named profile selected by config, if the current profile has one. @@ -468,7 +464,7 @@ impl Permissions { /// Effective filesystem sandbox policy derived from the canonical profile. pub fn file_system_sandbox_policy(&self) -> FileSystemSandboxPolicy { - self.materialized_permission_profile() + self.effective_permission_profile() .file_system_sandbox_policy() } @@ -479,7 +475,7 @@ impl Permissions { /// Legacy compatibility projection derived from the canonical profile. pub fn legacy_sandbox_policy(&self, cwd: &Path) -> SandboxPolicy { - let permission_profile = self.materialized_permission_profile(); + let permission_profile = self.effective_permission_profile(); compatibility_sandbox_policy_for_permission_profile(&permission_profile, cwd) } diff --git a/codex-rs/core/src/exec.rs b/codex-rs/core/src/exec.rs index 0a0364da37..4e760db02d 100644 --- a/codex-rs/core/src/exec.rs +++ b/codex-rs/core/src/exec.rs @@ -30,7 +30,6 @@ 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::permissions::NetworkSandboxPolicy; use codex_protocol::protocol::Event; use codex_protocol::protocol::EventMsg; @@ -115,14 +114,12 @@ pub enum ExecCapturePolicy { } fn select_process_exec_tool_sandbox_type( - file_system_sandbox_policy: &FileSystemSandboxPolicy, - network_sandbox_policy: NetworkSandboxPolicy, + permission_profile: &PermissionProfile, windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel, enforce_managed_network: bool, ) -> SandboxType { SandboxManager::new().select_initial( - file_system_sandbox_policy, - network_sandbox_policy, + permission_profile, SandboxablePreference::Auto, windows_sandbox_level, enforce_managed_network, @@ -345,11 +342,8 @@ pub fn build_exec_request( } = params; let enforce_managed_network = network.is_some(); - let (file_system_sandbox_policy, network_sandbox_policy) = - permission_profile.to_runtime_permissions(); let sandbox_type = select_process_exec_tool_sandbox_type( - &file_system_sandbox_policy, - network_sandbox_policy, + permission_profile, windows_sandbox_level, enforce_managed_network, ); @@ -453,8 +447,6 @@ pub(crate) async fn execute_exec_request( windows_sandbox_level, windows_sandbox_private_desktop, permission_profile, - file_system_sandbox_policy: _, - network_sandbox_policy, windows_sandbox_filesystem_overrides, network_environment_id, arg0, @@ -463,6 +455,7 @@ pub(crate) async fn execute_exec_request( exec_server_managed_network: _, exec_server_network_proxy: _, } = exec_request; + let network_sandbox_policy = permission_profile.network_sandbox_policy(); // TODO(anp): Keep PathUri through the local process launch boundary. let cwd = cwd diff --git a/codex-rs/core/src/exec_tests.rs b/codex-rs/core/src/exec_tests.rs index 7a0af61fe8..0b4bd522f3 100644 --- a/codex-rs/core/src/exec_tests.rs +++ b/codex-rs/core/src/exec_tests.rs @@ -1,6 +1,7 @@ use super::*; use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::models::PermissionProfile; +use codex_protocol::permissions::FileSystemSandboxPolicy; use codex_sandboxing::SandboxType; use core_test_support::PathBufExt; use core_test_support::PathExt; @@ -1049,8 +1050,10 @@ fn process_exec_tool_call_uses_platform_sandbox_for_network_only_restrictions() assert_eq!( select_process_exec_tool_sandbox_type( - &FileSystemSandboxPolicy::unrestricted(), - NetworkSandboxPolicy::Restricted, + &PermissionProfile::from_runtime_permissions( + &FileSystemSandboxPolicy::unrestricted(), + NetworkSandboxPolicy::Restricted, + ), codex_protocol::config_types::WindowsSandboxLevel::Disabled, /*enforce_managed_network*/ false, ), diff --git a/codex-rs/core/src/sandboxing/mod.rs b/codex-rs/core/src/sandboxing/mod.rs index 9a59477709..db9159613f 100644 --- a/codex-rs/core/src/sandboxing/mod.rs +++ b/codex-rs/core/src/sandboxing/mod.rs @@ -22,8 +22,6 @@ use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::exec_output::ExecToolCallOutput; use codex_protocol::models::PermissionProfile; pub use codex_protocol::models::SandboxPermissions; -use codex_protocol::permissions::FileSystemSandboxPolicy; -use codex_protocol::permissions::NetworkSandboxPolicy; use codex_sandboxing::SandboxExecRequest; use codex_sandboxing::SandboxType; use codex_sandboxing::WindowsSandboxFilesystemOverrides; @@ -59,8 +57,6 @@ pub struct ExecRequest { pub windows_sandbox_level: WindowsSandboxLevel, pub windows_sandbox_private_desktop: bool, pub permission_profile: PermissionProfile, - pub file_system_sandbox_policy: FileSystemSandboxPolicy, - pub network_sandbox_policy: NetworkSandboxPolicy, pub(crate) windows_sandbox_filesystem_overrides: Option, pub arg0: Option, pub(crate) exec_server_sandbox: Option, @@ -88,8 +84,6 @@ impl ExecRequest { ) -> Self { let cwd = PathUri::from_abs_path(&cwd); let windows_sandbox_policy_cwd = cwd.clone(); - let (file_system_sandbox_policy, network_sandbox_policy) = - permission_profile.to_runtime_permissions(); Self { command, cwd, @@ -105,8 +99,6 @@ impl ExecRequest { windows_sandbox_level, windows_sandbox_private_desktop, permission_profile, - file_system_sandbox_policy, - network_sandbox_policy, windows_sandbox_filesystem_overrides: None, arg0, exec_server_sandbox: None, @@ -132,14 +124,14 @@ impl ExecRequest { windows_sandbox_level, windows_sandbox_private_desktop, permission_profile, - file_system_sandbox_policy, - network_sandbox_policy, arg0, + .. } = request; let ExecOptions { expiration, capture_policy, } = options; + let network_sandbox_policy = permission_profile.network_sandbox_policy(); if !network_sandbox_policy.is_enabled() { env.insert( CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR.to_string(), @@ -165,8 +157,6 @@ impl ExecRequest { windows_sandbox_level, windows_sandbox_private_desktop, permission_profile, - file_system_sandbox_policy, - network_sandbox_policy, windows_sandbox_filesystem_overrides: None, arg0, exec_server_sandbox: None, diff --git a/codex-rs/core/src/session/turn_context.rs b/codex-rs/core/src/session/turn_context.rs index 70fe47fb5c..e500a9da22 100644 --- a/codex-rs/core/src/session/turn_context.rs +++ b/codex-rs/core/src/session/turn_context.rs @@ -16,8 +16,7 @@ use codex_protocol::protocol::MultiAgentVersion; use codex_protocol::protocol::ThreadHistoryMode; use codex_protocol::protocol::TurnEnvironmentSelection; use codex_sandboxing::compatibility_sandbox_policy_for_permission_profile; -use codex_sandboxing::policy_transforms::effective_file_system_sandbox_policy; -use codex_sandboxing::policy_transforms::effective_network_sandbox_policy; +use codex_sandboxing::policy_transforms::effective_permission_profile; use codex_utils_path_uri::PathUri; use futures::FutureExt; use futures::future::BoxFuture; @@ -335,22 +334,10 @@ impl TurnContext { additional_permissions: Option, environment: &TurnEnvironment, ) -> FileSystemSandboxContext { - let permission_profile = self.config.permissions.permission_profile(); - let (base_file_system_sandbox_policy, base_network_sandbox_policy) = - permission_profile.to_runtime_permissions(); - let file_system_sandbox_policy = effective_file_system_sandbox_policy( - &base_file_system_sandbox_policy, + let permissions = effective_permission_profile( + self.config.permissions.permission_profile(), additional_permissions.as_ref(), ); - let network_sandbox_policy = effective_network_sandbox_policy( - base_network_sandbox_policy, - additional_permissions.as_ref(), - ); - let permissions = PermissionProfile::from_runtime_permissions_with_enforcement( - permission_profile.enforcement(), - &file_system_sandbox_policy, - network_sandbox_policy, - ); FileSystemSandboxContext { permissions: permissions.into(), cwd: Some(environment.cwd().clone()), diff --git a/codex-rs/core/src/tasks/user_shell.rs b/codex-rs/core/src/tasks/user_shell.rs index 4ce2201e35..3b5f352b0a 100644 --- a/codex-rs/core/src/tasks/user_shell.rs +++ b/codex-rs/core/src/tasks/user_shell.rs @@ -225,9 +225,7 @@ pub(crate) async fn execute_user_shell_command( .config .permissions .windows_sandbox_private_desktop, - permission_profile: permission_profile.clone(), - file_system_sandbox_policy: permission_profile.file_system_sandbox_policy(), - network_sandbox_policy: permission_profile.network_sandbox_policy(), + permission_profile, windows_sandbox_filesystem_overrides: None, arg0: None, exec_server_sandbox: None, diff --git a/codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs b/codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs index fc48f1ed81..3c2f6daf86 100644 --- a/codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs +++ b/codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs @@ -155,8 +155,7 @@ impl ExecCommandHandler { // permissions config below. Consult the configured platform-sandbox requirement before // deciding whether parsing may continue without that base path. let sandbox = SandboxManager::new().select_initial( - &turn.file_system_sandbox_policy(), - turn.network_sandbox_policy(), + &turn.permission_profile, SandboxablePreference::Auto, turn.windows_sandbox_level, turn.network.is_some(), diff --git a/codex-rs/core/src/tools/orchestrator.rs b/codex-rs/core/src/tools/orchestrator.rs index b154e1a140..073962db74 100644 --- a/codex-rs/core/src/tools/orchestrator.rs +++ b/codex-rs/core/src/tools/orchestrator.rs @@ -160,8 +160,7 @@ impl ToolOrchestrator { let permissions = permission_profile .clone() .materialize_project_roots_with_workspace_roots(&materialized_workspace_roots); - let (file_system_sandbox_policy, network_sandbox_policy) = - permissions.to_runtime_permissions(); + let file_system_sandbox_policy = permissions.file_system_sandbox_policy(); let requirement = tool.exec_approval_requirement(req).unwrap_or_else(|| { default_exec_approval_requirement(approval_policy, &file_system_sandbox_policy) }); @@ -235,16 +234,14 @@ impl ToolOrchestrator { let sandbox_requested = match sandbox_override { SandboxOverride::BypassSandboxFirstAttempt => false, SandboxOverride::NoOverride => self.sandbox.should_sandbox( - &file_system_sandbox_policy, - network_sandbox_policy, + &permissions, sandbox_preference, managed_network_active, ), }; let initial_sandbox = if sandbox_requested { self.sandbox.select_initial( - &file_system_sandbox_policy, - network_sandbox_policy, + &permissions, sandbox_preference, turn_ctx.windows_sandbox_level, managed_network_active, @@ -423,15 +420,13 @@ impl ToolOrchestrator { let retry_sandbox_requested = !unsandboxed_allowed && self.sandbox.should_sandbox( - &file_system_sandbox_policy, - network_sandbox_policy, + &permissions, sandbox_preference, managed_network_active, ); let retry_sandbox = if retry_sandbox_requested { self.sandbox.select_initial( - &file_system_sandbox_policy, - network_sandbox_policy, + &permissions, sandbox_preference, turn_ctx.windows_sandbox_level, managed_network_active, diff --git a/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs b/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs index 14a68c9df4..048d4debfa 100644 --- a/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs +++ b/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs @@ -36,8 +36,6 @@ use codex_protocol::exec_output::ExecToolCallOutput; use codex_protocol::exec_output::StreamOutput; use codex_protocol::models::AdditionalPermissionProfile; use codex_protocol::models::PermissionProfile; -use codex_protocol::permissions::FileSystemSandboxPolicy; -use codex_protocol::permissions::NetworkSandboxPolicy; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::GuardianCommandSource; use codex_protocol::protocol::NetworkPolicyRuleAction; @@ -160,8 +158,6 @@ pub(super) async fn try_run_zsh_fork( windows_sandbox_level, windows_sandbox_private_desktop: _windows_sandbox_private_desktop, permission_profile, - file_system_sandbox_policy, - network_sandbox_policy, windows_sandbox_filesystem_overrides: _windows_sandbox_filesystem_overrides, arg0, exec_server_sandbox: _, @@ -189,8 +185,6 @@ pub(super) async fn try_run_zsh_fork( command, cwd: sandbox_cwd, permission_profile, - file_system_sandbox_policy, - network_sandbox_policy, sandbox, env: sandbox_env, network: sandbox_network, @@ -240,7 +234,6 @@ pub(super) async fn try_run_zsh_fork( tool_name: GuardianCommandSource::Shell, approval_policy: ctx.turn.approval_policy.value(), permission_profile: command_executor.permission_profile.clone(), - file_system_sandbox_policy: command_executor.file_system_sandbox_policy.clone(), sandbox_permissions: req.sandbox_permissions, approval_sandbox_permissions, prompt_permissions: req.additional_permissions.clone(), @@ -302,8 +295,6 @@ pub(crate) async fn prepare_unified_exec_zsh_fork( command: exec_request.command.clone(), cwd, permission_profile: exec_request.permission_profile.clone(), - file_system_sandbox_policy: exec_request.file_system_sandbox_policy.clone(), - network_sandbox_policy: exec_request.network_sandbox_policy, sandbox: exec_request.sandbox, env: exec_request.env.clone(), network: exec_request.network.clone(), @@ -324,7 +315,6 @@ pub(crate) async fn prepare_unified_exec_zsh_fork( tool_name: GuardianCommandSource::UnifiedExec, approval_policy: ctx.turn.approval_policy.value(), permission_profile: exec_request.permission_profile.clone(), - file_system_sandbox_policy: exec_request.file_system_sandbox_policy.clone(), sandbox_permissions: req.sandbox_permissions, approval_sandbox_permissions: approval_sandbox_permissions( req.sandbox_permissions, @@ -359,7 +349,6 @@ struct CoreShellActionProvider { tool_name: GuardianCommandSource, approval_policy: AskForApproval, permission_profile: PermissionProfile, - file_system_sandbox_policy: FileSystemSandboxPolicy, sandbox_permissions: SandboxPermissions, approval_sandbox_permissions: SandboxPermissions, prompt_permissions: Option, @@ -404,13 +393,12 @@ impl CoreShellActionProvider { fn shell_request_escalation_execution( sandbox_permissions: SandboxPermissions, permission_profile: &PermissionProfile, - file_system_sandbox_policy: &FileSystemSandboxPolicy, additional_permissions: Option<&AdditionalPermissionProfile>, ) -> EscalationExecution { match sandbox_permissions { SandboxPermissions::UseDefault => EscalationExecution::TurnDefault, SandboxPermissions::RequireEscalated => { - if unsandboxed_execution_allowed(file_system_sandbox_policy) { + if unsandboxed_execution_allowed(&permission_profile.file_system_sandbox_policy()) { EscalationExecution::Unsandboxed } else { EscalationExecution::TurnDefault @@ -627,7 +615,8 @@ impl CoreShellActionProvider { // fallback function. let decision_driven_by_policy = Self::decision_driven_by_policy(&evaluation.matched_rules, evaluation.decision); - let unsandboxed_allowed = unsandboxed_execution_allowed(&self.file_system_sandbox_policy); + let unsandboxed_allowed = + unsandboxed_execution_allowed(&self.permission_profile.file_system_sandbox_policy()); let needs_escalation = match self.sandbox_permissions { SandboxPermissions::UseDefault => unsandboxed_allowed && decision_driven_by_policy, SandboxPermissions::RequireEscalated => unsandboxed_allowed, @@ -645,7 +634,6 @@ impl CoreShellActionProvider { DecisionSource::UnmatchedCommandFallback => Self::shell_request_escalation_execution( self.sandbox_permissions, &self.permission_profile, - &self.file_system_sandbox_policy, self.prompt_permissions.as_ref(), ), }; @@ -777,8 +765,6 @@ struct CoreShellCommandExecutor { command: Vec, cwd: AbsolutePathBuf, permission_profile: PermissionProfile, - file_system_sandbox_policy: FileSystemSandboxPolicy, - network_sandbox_policy: NetworkSandboxPolicy, sandbox: SandboxType, env: HashMap, network: Option, @@ -862,8 +848,6 @@ impl CoreShellCommandExecutor { windows_sandbox_level: self.windows_sandbox_level, windows_sandbox_private_desktop: false, permission_profile: self.permission_profile.clone(), - file_system_sandbox_policy: self.file_system_sandbox_policy.clone(), - network_sandbox_policy: self.network_sandbox_policy, windows_sandbox_filesystem_overrides: None, arg0: self.arg0.clone(), exec_server_sandbox: None, @@ -958,15 +942,12 @@ impl CoreShellCommandExecutor { permission_profile, additional_permissions, } = params; - let (file_system_sandbox_policy, network_sandbox_policy) = - permission_profile.to_runtime_permissions(); let (program, args) = command .split_first() .ok_or_else(|| anyhow::anyhow!("prepared command must not be empty"))?; let sandbox_manager = SandboxManager::new(); let sandbox = sandbox_manager.select_initial( - &file_system_sandbox_policy, - network_sandbox_policy, + permission_profile, SandboxablePreference::Auto, self.windows_sandbox_level, self.network.is_some(), diff --git a/codex-rs/core/src/tools/runtimes/shell/unix_escalation_tests.rs b/codex-rs/core/src/tools/runtimes/shell/unix_escalation_tests.rs index e50406f15c..2c41f015ac 100644 --- a/codex-rs/core/src/tools/runtimes/shell/unix_escalation_tests.rs +++ b/codex-rs/core/src/tools/runtimes/shell/unix_escalation_tests.rs @@ -317,13 +317,15 @@ fn shell_request_escalation_execution_is_explicit() { &file_system_sandbox_policy, network_sandbox_policy, ); - let read_only_file_system_policy = read_only_file_system_sandbox_policy(); + let read_only_permission_profile = PermissionProfile::from_runtime_permissions( + &read_only_file_system_sandbox_policy(), + network_sandbox_policy, + ); assert_eq!( CoreShellActionProvider::shell_request_escalation_execution( crate::sandboxing::SandboxPermissions::UseDefault, &permission_profile, - &file_system_sandbox_policy, /*additional_permissions*/ None, ), EscalationExecution::TurnDefault, @@ -331,8 +333,7 @@ fn shell_request_escalation_execution_is_explicit() { assert_eq!( CoreShellActionProvider::shell_request_escalation_execution( crate::sandboxing::SandboxPermissions::RequireEscalated, - &permission_profile, - &read_only_file_system_policy, + &read_only_permission_profile, /*additional_permissions*/ None, ), EscalationExecution::Unsandboxed, @@ -341,7 +342,6 @@ fn shell_request_escalation_execution_is_explicit() { CoreShellActionProvider::shell_request_escalation_execution( crate::sandboxing::SandboxPermissions::RequireEscalated, &permission_profile, - &file_system_sandbox_policy, /*additional_permissions*/ None, ), EscalationExecution::TurnDefault, @@ -350,7 +350,6 @@ fn shell_request_escalation_execution_is_explicit() { CoreShellActionProvider::shell_request_escalation_execution( crate::sandboxing::SandboxPermissions::WithAdditionalPermissions, &permission_profile, - &file_system_sandbox_policy, Some(&requested_permissions), ), EscalationExecution::Permissions(EscalationPermissions::ResolvedPermissionProfile( @@ -366,8 +365,6 @@ async fn unsandboxed_intercepted_exec_strips_managed_network_env() -> anyhow::Re command: Vec::new(), cwd: workdir.clone(), permission_profile: PermissionProfile::workspace_write(), - file_system_sandbox_policy: read_only_file_system_sandbox_policy(), - network_sandbox_policy: NetworkSandboxPolicy::Restricted, sandbox: SandboxType::None, env: HashMap::new(), network: None, @@ -435,7 +432,6 @@ async fn preapproved_additional_permissions_escalate_intercepted_exec() -> anyho tool_name: GuardianCommandSource::Shell, approval_policy: AskForApproval::OnRequest, permission_profile: permission_profile.clone(), - file_system_sandbox_policy: read_only_file_system_sandbox_policy(), sandbox_permissions: SandboxPermissions::WithAdditionalPermissions, approval_sandbox_permissions: SandboxPermissions::UseDefault, prompt_permissions: Some(requested_permissions), @@ -571,7 +567,6 @@ async fn execve_permission_request_hook_short_circuits_prompt() -> anyhow::Resul tool_name: GuardianCommandSource::Shell, approval_policy: AskForApproval::OnRequest, permission_profile: PermissionProfile::read_only(), - file_system_sandbox_policy: read_only_file_system_sandbox_policy(), sandbox_permissions: SandboxPermissions::RequireEscalated, approval_sandbox_permissions: SandboxPermissions::RequireEscalated, prompt_permissions: None, @@ -782,7 +777,6 @@ prefix_rule(pattern = ["{cat_path_literal}"], decision = "allow") tool_name: GuardianCommandSource::Shell, approval_policy: AskForApproval::OnRequest, permission_profile, - file_system_sandbox_policy, sandbox_permissions: SandboxPermissions::UseDefault, approval_sandbox_permissions: SandboxPermissions::UseDefault, prompt_permissions: None, @@ -825,7 +819,6 @@ async fn denied_reads_keep_granular_sandbox_rejection_for_escalation() -> anyhow mcp_elicitations: true, }), permission_profile, - file_system_sandbox_policy, sandbox_permissions: SandboxPermissions::RequireEscalated, approval_sandbox_permissions: SandboxPermissions::RequireEscalated, prompt_permissions: None, diff --git a/codex-rs/core/src/unified_exec/process_manager_tests.rs b/codex-rs/core/src/unified_exec/process_manager_tests.rs index 35c6a4e9aa..d2bce0fc2f 100644 --- a/codex-rs/core/src/unified_exec/process_manager_tests.rs +++ b/codex-rs/core/src/unified_exec/process_manager_tests.rs @@ -110,9 +110,6 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() { .expect("current dir") .try_into() .expect("absolute path"); - let file_system_sandbox_policy = - codex_protocol::permissions::FileSystemSandboxPolicy::unrestricted(); - let network_sandbox_policy = codex_protocol::permissions::NetworkSandboxPolicy::Restricted; let permission_profile = codex_protocol::models::PermissionProfile::Disabled; let managed_network = ManagedNetworkSandboxContext { loopback_ports: vec![43123], @@ -167,8 +164,6 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() { windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel::Disabled, windows_sandbox_private_desktop: false, permission_profile: permission_profile.clone(), - file_system_sandbox_policy, - network_sandbox_policy, windows_sandbox_filesystem_overrides: None, arg0: None, exec_server_sandbox: None, diff --git a/codex-rs/exec-server/src/fs_sandbox.rs b/codex-rs/exec-server/src/fs_sandbox.rs index e90205d9cf..26567f68cf 100644 --- a/codex-rs/exec-server/src/fs_sandbox.rs +++ b/codex-rs/exec-server/src/fs_sandbox.rs @@ -112,10 +112,8 @@ impl FileSystemSandboxRunner { ) -> Result { let helper = &self.runtime_paths.codex_self_exe; let sandbox_manager = SandboxManager::new(); - let (file_system_policy, network_policy) = permission_profile.to_runtime_permissions(); let sandbox = sandbox_manager.select_initial( - &file_system_policy, - network_policy, + permission_profile, SandboxablePreference::Auto, sandbox_context.windows_sandbox_level, /*has_managed_network_requirements*/ false, diff --git a/codex-rs/exec-server/src/process_sandbox.rs b/codex-rs/exec-server/src/process_sandbox.rs index 0c8327f585..133f4daf91 100644 --- a/codex-rs/exec-server/src/process_sandbox.rs +++ b/codex-rs/exec-server/src/process_sandbox.rs @@ -150,6 +150,7 @@ pub(crate) async fn prepare_exec_request( managed_mitm_ca_trust_bundle_path.as_ref(), native_sandbox_policy_cwd.as_path(), ); + #[cfg(unix)] let (file_system_policy, network_policy) = permissions.to_runtime_permissions(); #[cfg(unix)] let sandbox_helper_paths = params @@ -179,8 +180,7 @@ pub(crate) async fn prepare_exec_request( ); let sandbox_manager = SandboxManager::new(); let sandbox = sandbox_manager.select_initial( - &file_system_policy, - network_policy, + &permissions, SandboxablePreference::Require, sandbox_context.windows_sandbox_level, params.enforce_managed_network, diff --git a/codex-rs/sandboxing/src/manager.rs b/codex-rs/sandboxing/src/manager.rs index c3c6294380..cf4cb90c8d 100644 --- a/codex-rs/sandboxing/src/manager.rs +++ b/codex-rs/sandboxing/src/manager.rs @@ -120,8 +120,6 @@ pub struct SandboxExecRequest { pub windows_sandbox_level: WindowsSandboxLevel, pub windows_sandbox_private_desktop: bool, pub permission_profile: PermissionProfile, - pub file_system_sandbox_policy: FileSystemSandboxPolicy, - pub network_sandbox_policy: NetworkSandboxPolicy, pub arg0: Option, } @@ -160,8 +158,6 @@ struct PendingSandboxedExecRequest { native_command_cwd: AbsolutePathBuf, native_sandbox_policy_cwd: AbsolutePathBuf, effective_permission_profile: PermissionProfile, - effective_file_system_policy: FileSystemSandboxPolicy, - effective_network_policy: NetworkSandboxPolicy, } impl PendingSandboxedExecRequest { @@ -189,14 +185,10 @@ impl PendingSandboxedExecRequest { managed_mitm_ca_trust_bundle_path, native_sandbox_policy_cwd.as_path(), ); - let (effective_file_system_policy, effective_network_policy) = - effective_permission_profile.to_runtime_permissions(); Ok(Self { native_command_cwd, native_sandbox_policy_cwd, effective_permission_profile, - effective_file_system_policy, - effective_network_policy, }) } } @@ -279,18 +271,12 @@ impl SandboxManager { pub fn select_initial( &self, - file_system_policy: &FileSystemSandboxPolicy, - network_policy: NetworkSandboxPolicy, + permission_profile: &PermissionProfile, pref: SandboxablePreference, windows_sandbox_level: WindowsSandboxLevel, has_managed_network_requirements: bool, ) -> SandboxType { - if self.should_sandbox( - file_system_policy, - network_policy, - pref, - has_managed_network_requirements, - ) { + if self.should_sandbox(permission_profile, pref, has_managed_network_requirements) { get_platform_sandbox(windows_sandbox_level != WindowsSandboxLevel::Disabled) .unwrap_or(SandboxType::None) } else { @@ -302,19 +288,22 @@ impl SandboxManager { /// this host can provide a concrete sandbox implementation. pub fn should_sandbox( &self, - file_system_policy: &FileSystemSandboxPolicy, - network_policy: NetworkSandboxPolicy, + permission_profile: &PermissionProfile, pref: SandboxablePreference, has_managed_network_requirements: bool, ) -> bool { match pref { SandboxablePreference::Forbid => false, SandboxablePreference::Require => true, - SandboxablePreference::Auto => should_require_platform_sandbox( - file_system_policy, - network_policy, - has_managed_network_requirements, - ), + SandboxablePreference::Auto => { + let (file_system_policy, network_policy) = + permission_profile.to_runtime_permissions(); + should_require_platform_sandbox( + &file_system_policy, + network_policy, + has_managed_network_requirements, + ) + } } } @@ -348,8 +337,6 @@ impl SandboxManager { base_effective_permission_profile.clone(), managed_mitm_ca_trust_bundle_path.as_ref(), ); - let (base_file_system_policy, base_network_policy) = - base_effective_permission_profile.to_runtime_permissions(); let mut argv = Vec::with_capacity(1 + command.args.len()); argv.push(command.program); argv.extend(command.args.into_iter().map(OsString::from)); @@ -363,10 +350,13 @@ impl SandboxManager { use crate::seatbelt::create_seatbelt_command_args; let pending = pending_sandboxed_request?; + let (file_system_sandbox_policy, network_sandbox_policy) = pending + .effective_permission_profile + .to_runtime_permissions(); let mut args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams { command: os_argv_to_strings(argv), - file_system_sandbox_policy: &pending.effective_file_system_policy, - network_sandbox_policy: pending.effective_network_policy, + file_system_sandbox_policy: &file_system_sandbox_policy, + network_sandbox_policy, sandbox_policy_cwd: pending.native_sandbox_policy_cwd.as_path(), enforce_managed_network, managed_network, @@ -389,7 +379,9 @@ impl SandboxManager { let allow_proxy_network = allow_network_for_proxy(enforce_managed_network); #[cfg(target_os = "linux")] ensure_linux_bubblewrap_is_supported( - &pending.effective_file_system_policy, + &pending + .effective_permission_profile + .file_system_sandbox_policy(), use_legacy_landlock, allow_proxy_network, is_wsl1(), @@ -427,22 +419,11 @@ impl SandboxManager { // Unsandboxed exec-server requests may have foreign cwd values that cannot be prepared // locally, but their effective permissions must still be preserved. In that case, carry - // forward the base profile and its derived runtime policies. - let (permission_profile, file_system_sandbox_policy, network_sandbox_policy) = - pending_sandboxed_request.map_or( - ( - base_effective_permission_profile, - base_file_system_policy, - base_network_policy, - ), - |pending| { - ( - pending.effective_permission_profile, - pending.effective_file_system_policy, - pending.effective_network_policy, - ) - }, - ); + // forward the base profile. + let permission_profile = pending_sandboxed_request + .map_or(base_effective_permission_profile, |pending| { + pending.effective_permission_profile + }); Ok(SandboxExecRequest { command: argv, @@ -455,8 +436,6 @@ impl SandboxManager { windows_sandbox_level, windows_sandbox_private_desktop, permission_profile, - file_system_sandbox_policy, - network_sandbox_policy, arg0: arg0_override, }) } diff --git a/codex-rs/sandboxing/src/manager_tests.rs b/codex-rs/sandboxing/src/manager_tests.rs index 27afea1083..1fe2d51451 100644 --- a/codex-rs/sandboxing/src/manager_tests.rs +++ b/codex-rs/sandboxing/src/manager_tests.rs @@ -29,8 +29,7 @@ use tempfile::TempDir; fn danger_full_access_defaults_to_no_sandbox_without_network_requirements() { let manager = SandboxManager::new(); let sandbox = manager.select_initial( - &FileSystemSandboxPolicy::unrestricted(), - NetworkSandboxPolicy::Enabled, + &PermissionProfile::Disabled, SandboxablePreference::Auto, WindowsSandboxLevel::Disabled, /*has_managed_network_requirements*/ false, @@ -44,8 +43,7 @@ fn danger_full_access_uses_platform_sandbox_with_network_requirements() { let expected = get_platform_sandbox(/*windows_sandbox_enabled*/ false).unwrap_or(SandboxType::None); let sandbox = manager.select_initial( - &FileSystemSandboxPolicy::unrestricted(), - NetworkSandboxPolicy::Enabled, + &PermissionProfile::Disabled, SandboxablePreference::Auto, WindowsSandboxLevel::Disabled, /*has_managed_network_requirements*/ true, @@ -58,7 +56,7 @@ fn restricted_file_system_uses_platform_sandbox_without_managed_network() { let manager = SandboxManager::new(); let expected = get_platform_sandbox(/*windows_sandbox_enabled*/ false).unwrap_or(SandboxType::None); - let sandbox = manager.select_initial( + let permissions = PermissionProfile::from_runtime_permissions( &FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry { path: FileSystemPath::Special { value: FileSystemSpecialPath::Root, @@ -67,6 +65,9 @@ fn restricted_file_system_uses_platform_sandbox_without_managed_network() { missing_path_behavior: None, }]), NetworkSandboxPolicy::Enabled, + ); + let sandbox = manager.select_initial( + &permissions, SandboxablePreference::Auto, WindowsSandboxLevel::Disabled, /*has_managed_network_requirements*/ false, @@ -112,11 +113,11 @@ fn unsandboxed_transform_preserves_foreign_cwd_and_unrestricted_file_system_poli assert_eq!(exec_request.cwd, cwd_uri); assert_eq!(exec_request.sandbox_policy_cwd, cwd_uri); assert_eq!( - exec_request.file_system_sandbox_policy, + exec_request.permission_profile.file_system_sandbox_policy(), FileSystemSandboxPolicy::unrestricted() ); assert_eq!( - exec_request.network_sandbox_policy, + exec_request.permission_profile.network_sandbox_policy(), NetworkSandboxPolicy::Restricted ); } @@ -172,7 +173,7 @@ fn transform_additional_permissions_enable_network_for_external_sandbox() { } ); assert_eq!( - exec_request.network_sandbox_policy, + exec_request.permission_profile.network_sandbox_policy(), NetworkSandboxPolicy::Enabled ); } @@ -239,7 +240,7 @@ fn transform_additional_permissions_preserves_denied_entries() { .expect("transform"); assert_eq!( - exec_request.file_system_sandbox_policy, + exec_request.permission_profile.file_system_sandbox_policy(), FileSystemSandboxPolicy::restricted(vec![ FileSystemSandboxEntry { path: FileSystemPath::Special { @@ -261,7 +262,7 @@ fn transform_additional_permissions_preserves_denied_entries() { ]) ); assert_eq!( - exec_request.network_sandbox_policy, + exec_request.permission_profile.network_sandbox_policy(), NetworkSandboxPolicy::Restricted ); }