diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index e1ee055757..75a457acbd 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -10513,7 +10513,7 @@ mod tests { let err = std::io::Error::other(CloudRequirementsLoadError::new( CloudRequirementsLoadErrorCode::RequestFailed, /*status_code*/ None, - "failed to load your workspace-managed config", + "Failed to load cloud requirements (workspace-managed policies).", )); let error = config_load_error(&err); @@ -10523,7 +10523,7 @@ mod tests { Some(json!({ "reason": "cloudRequirements", "errorCode": "RequestFailed", - "detail": "failed to load your workspace-managed config", + "detail": "Failed to load cloud requirements (workspace-managed policies).", })) ); } diff --git a/codex-rs/cloud-requirements/src/lib.rs b/codex-rs/cloud-requirements/src/lib.rs index aeed90e8b0..ca9ec56fe9 100644 --- a/codex-rs/cloud-requirements/src/lib.rs +++ b/codex-rs/cloud-requirements/src/lib.rs @@ -50,9 +50,16 @@ const CLOUD_REQUIREMENTS_CACHE_TTL: Duration = Duration::from_secs(30 * 60); const CLOUD_REQUIREMENTS_FETCH_ATTEMPT_METRIC: &str = "codex.cloud_requirements.fetch_attempt"; const CLOUD_REQUIREMENTS_FETCH_FINAL_METRIC: &str = "codex.cloud_requirements.fetch_final"; const CLOUD_REQUIREMENTS_LOAD_METRIC: &str = "codex.cloud_requirements.load"; -const CLOUD_REQUIREMENTS_LOAD_FAILED_MESSAGE: &str = "failed to load your workspace-managed config"; -const CLOUD_REQUIREMENTS_PARSE_FAILED_MESSAGE: &str = "Your workspace-managed config is invalid and could not be parsed. Please contact your workspace admin."; -const CLOUD_REQUIREMENTS_AUTH_RECOVERY_FAILED_MESSAGE: &str = "Your authentication session could not be refreshed automatically. Please log out and sign in again."; +const CLOUD_REQUIREMENTS_LOAD_FAILED_MESSAGE: &str = + "Failed to load cloud requirements (workspace-managed policies)."; +const CLOUD_REQUIREMENTS_PARSE_FAILED_MESSAGE: &str = concat!( + "Cloud requirements (workspace-managed policies) are invalid and could not be parsed. ", + "Please contact your workspace admin." +); +const CLOUD_REQUIREMENTS_AUTH_RECOVERY_FAILED_MESSAGE: &str = concat!( + "Your authentication session could not be refreshed automatically. ", + "Please log out and sign in again." +); const CLOUD_REQUIREMENTS_CACHE_WRITE_HMAC_KEY: &[u8] = b"codex-cloud-requirements-cache-v3-064f8542-75b4-494c-a294-97d3ce597271"; const CLOUD_REQUIREMENTS_CACHE_READ_HMAC_KEYS: &[&[u8]] = @@ -2097,10 +2104,7 @@ enabled = false .await .expect("cloud requirements task") .expect_err("cloud requirements retry exhaustion should fail closed"); - assert_eq!( - err.to_string(), - "failed to load your workspace-managed config" - ); + assert_eq!(err.to_string(), CLOUD_REQUIREMENTS_LOAD_FAILED_MESSAGE); assert_eq!(err.code(), CloudRequirementsLoadErrorCode::RequestFailed); assert_eq!( fetcher.request_count.load(Ordering::SeqCst), diff --git a/codex-rs/tui/src/app/thread_session_state.rs b/codex-rs/tui/src/app/thread_session_state.rs index cbf40d0d75..50fcba0d63 100644 --- a/codex-rs/tui/src/app/thread_session_state.rs +++ b/codex-rs/tui/src/app/thread_session_state.rs @@ -3,6 +3,8 @@ use crate::app_server_session::ThreadSessionState; use crate::read_session_model; use codex_app_server_protocol::Thread; use codex_protocol::ThreadId; +use codex_protocol::models::PermissionProfile; +use codex_protocol::protocol::SandboxPolicy; impl App { pub(super) async fn sync_active_thread_permission_settings_to_cached_session(&mut self) { @@ -17,6 +19,15 @@ impl App { session.approval_policy = approval_policy; session.approvals_reviewer = approvals_reviewer; session.sandbox_policy = sandbox_policy.clone(); + session.permission_profile = + if matches!(sandbox_policy, SandboxPolicy::ExternalSandbox { .. }) { + None + } else { + Some(PermissionProfile::from_legacy_sandbox_policy( + &sandbox_policy, + &session.cwd, + )) + }; }; if self.primary_thread_id == Some(active_thread_id) @@ -108,6 +119,7 @@ mod tests { approval_policy: AskForApproval::Never, approvals_reviewer: ApprovalsReviewer::User, sandbox_policy: SandboxPolicy::new_read_only_policy(), + permission_profile: None, cwd: cwd.abs(), instruction_source_paths: Vec::new(), reasoning_effort: None, @@ -155,17 +167,23 @@ mod tests { .insert(side_thread_id, SideThreadState::new(main_thread_id)); app.config.permissions.approval_policy = codex_config::Constrained::allow_any(AskForApproval::OnRequest); - app.config.approvals_reviewer = ApprovalsReviewer::GuardianSubagent; + app.config.approvals_reviewer = ApprovalsReviewer::AutoReview; + let expected_sandbox_policy = SandboxPolicy::new_workspace_write_policy(); + let expected_permission_profile = PermissionProfile::from_legacy_sandbox_policy( + &expected_sandbox_policy, + &main_session.cwd, + ); app.config.permissions.sandbox_policy = - codex_config::Constrained::allow_any(SandboxPolicy::new_workspace_write_policy()); + codex_config::Constrained::allow_any(expected_sandbox_policy.clone()); app.sync_active_thread_permission_settings_to_cached_session() .await; let expected_main_session = ThreadSessionState { approval_policy: AskForApproval::OnRequest, - approvals_reviewer: ApprovalsReviewer::GuardianSubagent, - sandbox_policy: SandboxPolicy::new_workspace_write_policy(), + approvals_reviewer: ApprovalsReviewer::AutoReview, + sandbox_policy: expected_sandbox_policy, + permission_profile: Some(expected_permission_profile), ..main_session }; assert_eq!(