diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index cba1234c14..5e86ea9e4a 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -126,7 +126,6 @@ use codex_protocol::models::BaseInstructionsProvenance; use codex_protocol::models::PermissionProfile; pub use codex_protocol::models::PermissionProfileSnapshot; use codex_protocol::models::ProfileWorkspaceRoot; -use codex_protocol::models::SandboxEnforcement; use codex_protocol::openai_models::ModelsResponse; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::permissions::DenyReadValidator; @@ -510,14 +509,8 @@ impl Permissions { sandbox_policy: &SandboxPolicy, cwd: &Path, ) -> ConstraintResult<()> { - let file_system_sandbox_policy = - FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(sandbox_policy, cwd); - let network_sandbox_policy = NetworkSandboxPolicy::from(sandbox_policy); - let permission_profile = PermissionProfile::from_runtime_permissions_with_enforcement( - SandboxEnforcement::from_legacy_sandbox_policy(sandbox_policy), - &file_system_sandbox_policy, - network_sandbox_policy, - ); + let permission_profile = + PermissionProfile::from_legacy_sandbox_policy_for_cwd(sandbox_policy, cwd); self.can_set_permission_profile(&permission_profile) } @@ -529,14 +522,8 @@ impl Permissions { cwd: &Path, ) -> ConstraintResult<()> { self.can_set_legacy_sandbox_policy(&sandbox_policy, cwd)?; - let file_system_sandbox_policy = - FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, cwd); - let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy); - let permission_profile = PermissionProfile::from_runtime_permissions_with_enforcement( - SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy), - &file_system_sandbox_policy, - network_sandbox_policy, - ); + let permission_profile = + PermissionProfile::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, cwd); self.workspace_roots = match &sandbox_policy { SandboxPolicy::WorkspaceWrite { writable_roots, .. } => { let mut workspace_roots = vec![ @@ -1788,20 +1775,6 @@ impl Config { self.permissions.legacy_sandbox_policy(self.cwd.as_path()) } - pub fn set_legacy_sandbox_policy( - &mut self, - sandbox_policy: SandboxPolicy, - ) -> ConstraintResult<()> { - self.workspace_roots_explicit = matches!( - &sandbox_policy, - SandboxPolicy::WorkspaceWrite { writable_roots, .. } if !writable_roots.is_empty() - ); - self.permissions - .set_legacy_sandbox_policy(sandbox_policy, self.cwd.as_path())?; - self.workspace_roots = self.permissions.workspace_roots().to_vec(); - Ok(()) - } - /// Combine runtime and profile roots without interpreting them on the current host. pub fn effective_workspace_roots(&self) -> Vec { let mut workspace_roots = self diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 0b3313840c..0927131d14 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -4241,21 +4241,24 @@ async fn record_initial_history_assigns_and_persists_id_for_forked_response_item async fn session_configured_reports_permission_profile_for_external_sandbox() -> anyhow::Result<()> { let server = start_mock_server().await; - let sandbox_policy = SandboxPolicy::ExternalSandbox { - network_access: codex_protocol::protocol::NetworkAccess::Restricted, - }; let permission_profile = PermissionProfile::External { network: NetworkSandboxPolicy::Restricted, }; let expected_permission_profile = permission_profile.clone(); let mut builder = test_codex().with_config(move |config| { + config.workspace_roots_explicit = false; config .permissions - .set_permission_profile(permission_profile.clone()) + .can_set_permission_profile(&permission_profile) .expect("set permission profile"); config - .set_legacy_sandbox_policy(sandbox_policy) - .expect("set sandbox policy"); + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; diff --git a/codex-rs/core/tests/suite/approvals.rs b/codex-rs/core/tests/suite/approvals.rs index 699d88133c..0a5176c9ea 100644 --- a/codex-rs/core/tests/suite/approvals.rs +++ b/codex-rs/core/tests/suite/approvals.rs @@ -1980,9 +1980,23 @@ async fn run_scenario(scenario: &ScenarioSpec) -> Result<()> { id: thread_store_id, }; config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy.clone()) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); for feature in features { config .features @@ -2156,9 +2170,23 @@ async fn approving_apply_patch_for_session_skips_future_prompts_for_same_file() .with_model("gpt-5.5") .with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); config.approvals_reviewer = ApprovalsReviewer::User; }); let test = builder.build(&server).await?; @@ -2299,9 +2327,23 @@ async fn approving_execpolicy_amendment_emits_one_saved_prefix_notice( .features .disable(Feature::DeferredExecutor) .expect("test config should allow feature update"); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; @@ -2410,9 +2452,23 @@ async fn approving_execpolicy_amendment_persists_policy_and_skips_future_prompts let sandbox_policy_for_config = sandbox_policy.clone(); let mut builder = test_codex().with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; let allow_prefix_path = test.cwd.path().join("allow-prefix.txt"); @@ -2583,9 +2639,23 @@ async fn spawned_subagent_execpolicy_amendment_propagates_to_parent_session() -> let sandbox_policy_for_config = sandbox_policy.clone(); let mut builder = test_codex().with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); config .features .enable(Feature::Collab) @@ -3907,9 +3977,23 @@ async fn invalid_requested_prefix_rule_falls_back_for_compound_command() -> Resu let sandbox_policy_for_config = sandbox_policy.clone(); let mut builder = test_codex().with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; @@ -3960,9 +4044,23 @@ async fn approving_fallback_rule_for_compound_command_works() -> Result<()> { let sandbox_policy_for_config = sandbox_policy.clone(); let mut builder = test_codex().with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; @@ -4100,9 +4198,23 @@ allow_local_binding = true .with_cloud_config_bundle(managed_network_requirements_loader()) .with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; assert!( @@ -4712,9 +4824,23 @@ async fn compound_command_with_one_safe_command_still_requires_approval() -> Res let sandbox_policy_for_config = sandbox_policy.clone(); let mut builder = test_codex().with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; diff --git a/codex-rs/core/tests/suite/cyber_exec_policy.rs b/codex-rs/core/tests/suite/cyber_exec_policy.rs index 9ac9402cca..f92645f793 100644 --- a/codex-rs/core/tests/suite/cyber_exec_policy.rs +++ b/codex-rs/core/tests/suite/cyber_exec_policy.rs @@ -4,6 +4,7 @@ use codex_core::config::Config; use codex_core::config::Constrained; use codex_core::sandboxing::SandboxPermissions; use codex_protocol::config_types::ApprovalsReviewer; +use codex_protocol::models::PermissionProfile; use codex_protocol::openai_models::MODEL_SPECIALTY_CYBER; use codex_protocol::openai_models::ModelMessages; use codex_protocol::openai_models::PermissionMessages; @@ -54,14 +55,28 @@ fn configure_saved_prefix_and_guardian(config: &mut Config) { .expect("write saved command prefix rule"); config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::AutoReview; - config - .set_legacy_sandbox_policy(SandboxPolicy::WorkspaceWrite { + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::WorkspaceWrite { writable_roots: vec![], network_access: false, exclude_tmpdir_env_var: true, exclude_slash_tmp: true, - }) - .expect("set workspace sandbox policy"); + }, + config.cwd.as_path(), + ); + config + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); } fn command_response(response_id: &str, call_id: &str) -> Result { diff --git a/codex-rs/core/tests/suite/guardian_authorization.rs b/codex-rs/core/tests/suite/guardian_authorization.rs index 91f93d838c..ea7cfbe98b 100644 --- a/codex-rs/core/tests/suite/guardian_authorization.rs +++ b/codex-rs/core/tests/suite/guardian_authorization.rs @@ -13,6 +13,7 @@ use codex_features::Feature; use codex_history::RolloutItem; use codex_protocol::config_types::ApprovalsReviewer; use codex_protocol::models::ImageReference; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::GuardianAssessmentStatus; @@ -157,9 +158,23 @@ async fn guardian_revalidates_owning_session_before_allow( config.model_provider.base_url = Some(base_url); config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::AutoReview; + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::new_workspace_write_policy(), + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy()) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); for feature in [ Feature::CodeMode, Feature::CodeModeInterrupt, diff --git a/codex-rs/core/tests/suite/guardian_cyber_access_program_tests.rs b/codex-rs/core/tests/suite/guardian_cyber_access_program_tests.rs index cc54d9e183..2cd64a99da 100644 --- a/codex-rs/core/tests/suite/guardian_cyber_access_program_tests.rs +++ b/codex-rs/core/tests/suite/guardian_cyber_access_program_tests.rs @@ -8,6 +8,7 @@ use codex_features::Feature; use codex_login::CodexAuth; use codex_protocol::approvals::GuardianAssessmentStatus; use codex_protocol::config_types::ApprovalsReviewer; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::SandboxPolicy; @@ -47,9 +48,23 @@ async fn guardian_reused_reviewer_respects_parent_program_scope( .with_config(|config| { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::AutoReview; + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::new_workspace_write_policy(), + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy()) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); config .features .enable(Feature::ApiKeyCyberAccessPrograms) diff --git a/codex-rs/core/tests/suite/guardian_retry.rs b/codex-rs/core/tests/suite/guardian_retry.rs index 30fdbc6e90..7bdf4bbf92 100644 --- a/codex-rs/core/tests/suite/guardian_retry.rs +++ b/codex-rs/core/tests/suite/guardian_retry.rs @@ -7,6 +7,7 @@ use codex_core::context::UserGoalUpdate; use codex_protocol::AgentPath; use codex_protocol::approvals::GuardianAssessmentStatus; use codex_protocol::config_types::ApprovalsReviewer; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::InterAgentCommunication; @@ -110,9 +111,23 @@ async fn interrupted_guardian_review_preserves_evidence_once( config.model_provider.stream_idle_timeout_ms = Some(600_000); config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::AutoReview; + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::new_workspace_write_policy(), + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy()) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }) .build_with_auto_env(&server) .await?; @@ -250,9 +265,23 @@ async fn guardian_retry_executes_only_after_a_completed_approval() -> Result<()> let mut builder = test_codex().with_config(|config| { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::AutoReview; + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::new_workspace_write_policy(), + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy()) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build_with_auto_env(&server).await?; let responses = vec![ @@ -445,9 +474,23 @@ async fn guardian_stale_approval_replaces_review_and_preserves_earlier_context() config.model_provider.base_url = Some(base_url); config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::AutoReview; + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::new_workspace_write_policy(), + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy()) - .expect("sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }) .build_with_auto_env(&server) .await?; diff --git a/codex-rs/core/tests/suite/guardian_review.rs b/codex-rs/core/tests/suite/guardian_review.rs index 6c593c946c..6ef2177fe0 100644 --- a/codex-rs/core/tests/suite/guardian_review.rs +++ b/codex-rs/core/tests/suite/guardian_review.rs @@ -2274,9 +2274,23 @@ async fn interrupted_guardian_review_across_model_change_does_not_execute_the_co config.features.enable(Feature::StepModelSwitching).unwrap(); config.permissions.approval_policy = Constrained::allow_any(approval_policy); config.approvals_reviewer = ApprovalsReviewer::AutoReview; + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }) .build_with_auto_env(&server) .await?; @@ -2462,9 +2476,23 @@ async fn guardian_denial_rejects_tool_call_with_rationale( tls: None, }; config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build_with_auto_env(&server).await?; @@ -2880,9 +2908,23 @@ async fn cyber_model_guardian_denial_interrupts_turn_immediately( }) .with_config(move |config| { config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let cached_calls = Arc::new(std::sync::atomic::AtomicUsize::new(/*v*/ 0)); if matches!(approval_path, ApprovalPath::CachedContributor) { @@ -3038,9 +3080,23 @@ printf '%s\n' "${@: -1}" >> "${payload_path}""#, let mut builder = test_codex().with_config(move |config| { config.notify = Some(vec![notify_script_str]); config.permissions.approval_policy = Constrained::allow_any(approval_policy); + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &sandbox_policy_for_config, + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(sandbox_policy_for_config) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); }); let test = builder.build(&server).await?; diff --git a/codex-rs/core/tests/suite/guardian_review_cancellation.rs b/codex-rs/core/tests/suite/guardian_review_cancellation.rs index e11c6fb70c..2f9ad19ec8 100644 --- a/codex-rs/core/tests/suite/guardian_review_cancellation.rs +++ b/codex-rs/core/tests/suite/guardian_review_cancellation.rs @@ -4,6 +4,7 @@ use codex_core::TurnInputRequest; use codex_core::config::Constrained; use codex_features::Feature; use codex_protocol::config_types::ApprovalsReviewer; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::GuardianAssessmentStatus; @@ -64,9 +65,23 @@ async fn cancelling_tool_aborts_its_guardian_review( .enable(Feature::GuardianDenialReconsideration) .expect("enable Guardian denial reconsideration"); } + config.workspace_roots_explicit = false; + let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( + &SandboxPolicy::new_workspace_write_policy(), + config.cwd.as_path(), + ); config - .set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy()) - .expect("set sandbox policy"); + .permissions + .can_set_permission_profile(&permission_profile) + .expect("set permission profile"); + config + .permissions + .set_workspace_roots(vec![config.cwd.clone()]); + config + .permissions + .set_permission_profile(permission_profile) + .expect("set permission profile"); + config.workspace_roots = config.permissions.workspace_roots().to_vec(); if !matches!(cancellation, Cancellation::DirectTool) { let _ = config.features.enable(Feature::CodeMode); let _ = config.features.enable(Feature::CodeModeInterrupt);