From 9d826a20c69e5f3dc6c2196e8e7fbce7912ec5f3 Mon Sep 17 00:00:00 2001 From: jif-oai Date: Mon, 23 Feb 2026 12:49:54 +0000 Subject: [PATCH] fix: TUI constraint (#12571) --- codex-rs/tui/src/chatwidget.rs | 22 ++++++++++++ codex-rs/tui/src/chatwidget/tests.rs | 51 ++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 309ce80ce..64757eaa2 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -49,6 +49,7 @@ use codex_app_server_protocol::ConfigLayerSource; use codex_backend_client::Client as BackendClient; use codex_chatgpt::connectors; use codex_core::config::Config; +use codex_core::config::Constrained; use codex_core::config::ConstraintResult; use codex_core::config::types::Notifications; use codex_core::config::types::WindowsSandboxModeToml; @@ -1076,6 +1077,27 @@ impl ChatWidget { self.forked_from = event.forked_from_id; self.current_rollout_path = event.rollout_path.clone(); self.current_cwd = Some(event.cwd.clone()); + self.config.cwd = event.cwd.clone(); + if let Err(err) = self + .config + .permissions + .approval_policy + .set(event.approval_policy) + { + tracing::warn!(%err, "failed to sync approval_policy from SessionConfigured"); + self.config.permissions.approval_policy = + Constrained::allow_only(event.approval_policy); + } + if let Err(err) = self + .config + .permissions + .sandbox_policy + .set(event.sandbox_policy.clone()) + { + tracing::warn!(%err, "failed to sync sandbox_policy from SessionConfigured"); + self.config.permissions.sandbox_policy = + Constrained::allow_only(event.sandbox_policy.clone()); + } let initial_messages = event.initial_messages.clone(); let forked_from_id = event.forked_from_id; let model_for_header = event.model.clone(); diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index d7424f720..0f537581e 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -325,6 +325,57 @@ async fn replayed_user_message_preserves_remote_image_urls() { assert_eq!(stored_remote_image_urls, remote_image_urls); } +#[tokio::test] +async fn session_configured_syncs_widget_config_permissions_and_cwd() { + let (mut chat, _rx, _ops) = make_chatwidget_manual(None).await; + + chat.config + .permissions + .approval_policy + .set(AskForApproval::OnRequest) + .expect("set approval policy"); + chat.config + .permissions + .sandbox_policy + .set(SandboxPolicy::new_workspace_write_policy()) + .expect("set sandbox policy"); + chat.config.cwd = PathBuf::from("/home/user/main"); + + let expected_sandbox = SandboxPolicy::new_read_only_policy(); + let expected_cwd = PathBuf::from("/home/user/sub-agent"); + let configured = codex_protocol::protocol::SessionConfiguredEvent { + session_id: ThreadId::new(), + forked_from_id: None, + thread_name: None, + model: "test-model".to_string(), + model_provider_id: "test-provider".to_string(), + approval_policy: AskForApproval::Never, + sandbox_policy: expected_sandbox.clone(), + cwd: expected_cwd.clone(), + reasoning_effort: Some(ReasoningEffortConfig::default()), + history_log_id: 0, + history_entry_count: 0, + initial_messages: None, + network_proxy: None, + rollout_path: None, + }; + + chat.handle_codex_event(Event { + id: "session-configured".into(), + msg: EventMsg::SessionConfigured(configured), + }); + + assert_eq!( + chat.config_ref().permissions.approval_policy.value(), + AskForApproval::Never + ); + assert_eq!( + chat.config_ref().permissions.sandbox_policy.get(), + &expected_sandbox + ); + assert_eq!(&chat.config_ref().cwd, &expected_cwd); +} + #[tokio::test] async fn replayed_user_message_with_only_remote_images_renders_history_cell() { let (mut chat, mut rx, _ops) = make_chatwidget_manual(None).await;