From c210f4c222f8f7a447d0b3a013f3cb9cc3cd43b0 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Fri, 11 Sep 2026 23:27:14 +0000 Subject: [PATCH] Respect execution hosts in Windows sandbox setup (#44939) ## Why The Windows TUI cannot configure a remote executor's sandbox. Required elevated sandbox setup also needs to reflect the local app server's readiness rather than the TUI's local setup files. ## What changed - Restrict setup prompts and actions to local connections with local executors, including local daemon connections. Let remote servers own Agent permission selection, and warn when local and remote executors are configured together. - Query `WindowsSandboxReadiness` at startup when elevated sandboxing is required locally, and track successful setup across chat widget replacement and reconnects. - Restore pending initial input to the composer when mixed executors prevent required setup or a local connection goes offline. ## Testing Add regression coverage for local, remote, and mixed host selection, remote Agent permission selection, pending input restoration with mixed executors, and setup state preservation during daemon reconnects. GitOrigin-RevId: bd45b308ac3ae4c2489b0bd2ac5d7e12a7fc35d6 --- codex-rs/tui/src/app.rs | 1 + codex-rs/tui/src/app/event_dispatch.rs | 23 +++++++ codex-rs/tui/src/app/platform_actions.rs | 62 +++++++++++++++++++ codex-rs/tui/src/app/reconnect.rs | 7 +++ codex-rs/tui/src/app/session_lifecycle.rs | 6 ++ codex-rs/tui/src/app/startup.rs | 36 ++++++++++- .../app/tests/navigation_reconnect_tests.rs | 6 ++ codex-rs/tui/src/app/tests/startup.rs | 48 ++++++++++++++ codex-rs/tui/src/chatwidget.rs | 7 ++- codex-rs/tui/src/chatwidget/constructor.rs | 3 + codex-rs/tui/src/chatwidget/input_restore.rs | 17 ++++- .../tui/src/chatwidget/permission_popups.rs | 27 ++++---- .../src/chatwidget/permission_shortcuts.rs | 9 +-- .../tui/src/chatwidget/tests/permissions.rs | 41 ++++++++++++ .../src/chatwidget/windows_sandbox_prompts.rs | 8 ++- codex-rs/tui/src/lib.rs | 3 +- codex-rs/tui/src/windows_sandbox.rs | 6 +- 17 files changed, 278 insertions(+), 32 deletions(-) diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 75bb355cf8..edc16444a7 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -266,6 +266,7 @@ use self::agent_navigation::AgentNavigationState; use self::app_server_requests::PendingAppServerRequests; use self::loaded_threads::find_loaded_subagent_threads_for_primary; use self::pending_interactive_replay::PendingInteractiveReplayState; +pub(crate) use self::platform_actions::WindowsSandboxHost; use self::platform_actions::*; use self::side::SideParentStatus; use self::side::SideParentStatusChange; diff --git a/codex-rs/tui/src/app/event_dispatch.rs b/codex-rs/tui/src/app/event_dispatch.rs index 9b49e67fb6..5fd3cd2c28 100644 --- a/codex-rs/tui/src/app/event_dispatch.rs +++ b/codex-rs/tui/src/app/event_dispatch.rs @@ -48,6 +48,28 @@ impl App { { return Ok(AppRunControl::Continue); } + if matches!( + &event, + AppEvent::OpenWindowsSandboxEnablePrompt { .. } + | AppEvent::OpenWindowsSandboxFallbackPrompt { .. } + | AppEvent::BeginWindowsSandboxElevatedSetup { .. } + | AppEvent::BeginWindowsSandboxLegacySetup { .. } + | AppEvent::EnableWindowsSandboxForAgentMode { .. } + ) && !self.windows_sandbox_setup_is_local() + { + if matches!( + &event, + AppEvent::OpenWindowsSandboxFallbackPrompt { .. } + | AppEvent::EnableWindowsSandboxForAgentMode { .. } + ) { + self.chat_widget.clear_windows_sandbox_setup_status(); + } + self.chat_widget.add_info_message( + "Windows sandbox setup requires local connections and executors.".to_string(), + /*hint*/ None, + ); + return Ok(AppRunControl::Continue); + } if self.chat_widget.has_misalignment_policy_violation() && matches!( event, @@ -2179,6 +2201,7 @@ impl App { ); return Ok(AppRunControl::Continue); } + self.chat_widget.windows_sandbox_elevated_setup_complete = elevated_enabled; let edits = crate::config_update::build_windows_sandbox_mode_edits(elevated_enabled); match crate::config_update::write_config_batch( diff --git a/codex-rs/tui/src/app/platform_actions.rs b/codex-rs/tui/src/app/platform_actions.rs index 32931b4d8f..6ca93bc2d7 100644 --- a/codex-rs/tui/src/app/platform_actions.rs +++ b/codex-rs/tui/src/app/platform_actions.rs @@ -5,11 +5,73 @@ use super::*; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum WindowsSandboxHost { + Local, + Mixed, + Remote, +} + #[derive(Default)] pub(super) struct WindowsSandboxState { pub(super) setup_started_at: Option, } +pub(super) fn windows_sandbox_host( + target: &AppServerTarget, + environment_manager: &EnvironmentManager, +) -> WindowsSandboxHost { + if target.uses_remote_workspace() { + WindowsSandboxHost::Remote + } else if environment_manager + .default_environment_ids() + .into_iter() + .filter_map(|id| environment_manager.get_environment(&id)) + .any(|environment| environment.is_remote()) + { + if environment_manager.try_local_environment().is_some() { + WindowsSandboxHost::Mixed + } else { + WindowsSandboxHost::Remote + } + } else { + WindowsSandboxHost::Local + } +} + +#[cfg(target_os = "windows")] +pub(super) async fn windows_sandbox_ready(app_server: &mut AppServerSession) -> bool { + let request_id = app_server.next_request_id(); + matches!( + tokio::time::timeout( + Duration::from_secs(5), + app_server + .request_handle() + .request_typed(ClientRequest::WindowsSandboxReadiness { + request_id, + params: None, + }), + ) + .await, + Ok(Ok( + codex_app_server_protocol::WindowsSandboxReadinessResponse { + status: codex_app_server_protocol::WindowsSandboxReadiness::Ready, + } + )) + ) +} + +impl App { + pub(super) fn windows_sandbox_host(&self) -> WindowsSandboxHost { + windows_sandbox_host(&self.app_server_target, self.environment_manager.as_ref()) + } + + /// A local app server owns setup for both embedded and daemon connections. + pub(super) fn windows_sandbox_setup_is_local(&self) -> bool { + self.windows_sandbox_host() == WindowsSandboxHost::Local + } +} + pub(super) fn side_return_shortcut_matches(key_event: KeyEvent) -> bool { matches!( key_event, diff --git a/codex-rs/tui/src/app/reconnect.rs b/codex-rs/tui/src/app/reconnect.rs index 2951be249e..e816683d58 100644 --- a/codex-rs/tui/src/app/reconnect.rs +++ b/codex-rs/tui/src/app/reconnect.rs @@ -175,6 +175,12 @@ impl App { return false; } if !self.reconnect.offline { + #[cfg(target_os = "windows")] + if self.windows_sandbox_setup_is_local() + && let Some(message) = self.chat_widget.initial_user_message.take() + { + self.chat_widget.restore_user_message_to_composer(message); + } self.reconnect.offline = true; self.reconnect.failed = false; if self.pending_server_version_notice.take().is_some() { @@ -259,6 +265,7 @@ impl App { self.environment_manager.as_ref(), ), ); + self.chat_widget.windows_sandbox_host = self.windows_sandbox_host(); self.chat_widget.cyber_policy_notice = Default::default(); self.chat_widget.requires_openai_auth = bootstrap.requires_openai_auth; self.chat_widget.remote_connection = diff --git a/codex-rs/tui/src/app/session_lifecycle.rs b/codex-rs/tui/src/app/session_lifecycle.rs index 6165351cef..f1451569c0 100644 --- a/codex-rs/tui/src/app/session_lifecycle.rs +++ b/codex-rs/tui/src/app/session_lifecycle.rs @@ -497,6 +497,12 @@ impl App { } chat_widget.remote_connection = self.chat_widget.remote_connection.clone(); chat_widget.set_local_worktree_operations(self.chat_widget.local_worktree_operations); + chat_widget.windows_sandbox_host = self.chat_widget.windows_sandbox_host; + #[cfg(any(target_os = "windows", test))] + { + chat_widget.windows_sandbox_elevated_setup_complete = + self.chat_widget.windows_sandbox_elevated_setup_complete; + } chat_widget.set_agents_navigation_enabled(matches!( self.app_server_target, AppServerTarget::LocalDaemon { .. } diff --git a/codex-rs/tui/src/app/startup.rs b/codex-rs/tui/src/app/startup.rs index c5ec00043a..038925294c 100644 --- a/codex-rs/tui/src/app/startup.rs +++ b/codex-rs/tui/src/app/startup.rs @@ -682,9 +682,39 @@ impl App { AppServerTarget::LocalDaemon { .. } )); let thread_and_widget_ms = thread_and_widget_started_at.elapsed().as_millis(); - chat_widget - .maybe_prompt_windows_sandbox_enable(should_prompt_windows_sandbox_nux_at_startup); - + let windows_sandbox_host = + windows_sandbox_host(&app_server_target, environment_manager.as_ref()); + chat_widget.windows_sandbox_host = windows_sandbox_host; + let windows_sandbox_host_is_local = windows_sandbox_host == WindowsSandboxHost::Local; + #[cfg(target_os = "windows")] + let sandbox_ready = + if windows_sandbox_host_is_local && chat_widget.required_elevated_windows_sandbox() { + windows_sandbox_ready(&mut app_server).await + } else { + false + }; + #[cfg(not(target_os = "windows"))] + let sandbox_ready = false; + #[cfg(target_os = "windows")] + if sandbox_ready { + chat_widget.windows_sandbox_elevated_setup_complete = true; + } + chat_widget.maybe_prompt_windows_sandbox_enable( + should_prompt_windows_sandbox_nux_at_startup + && windows_sandbox_host_is_local + && !sandbox_ready, + ); + #[cfg(target_os = "windows")] + if windows_sandbox_host == WindowsSandboxHost::Mixed + && should_prompt_windows_sandbox_nux_at_startup + { + app_event_tx.send(AppEvent::InsertHistoryCell(Box::new( + history_cell::StartupWarningsCell::new(vec![ + "Windows sandbox setup is unavailable when local and remote executors are configured together." + .to_string(), + ]), + ))); + } let file_search = FileSearchManager::new(config.cwd.to_path_buf(), app_event_tx.clone()); let runtime_keymap = RuntimeKeymap::from_config(&local_settings.tui.keymap).map_err(|err| { diff --git a/codex-rs/tui/src/app/tests/navigation_reconnect_tests.rs b/codex-rs/tui/src/app/tests/navigation_reconnect_tests.rs index 2d8ef54a58..b04091cb1b 100644 --- a/codex-rs/tui/src/app/tests/navigation_reconnect_tests.rs +++ b/codex-rs/tui/src/app/tests/navigation_reconnect_tests.rs @@ -170,6 +170,9 @@ async fn reconnect_daemon_command_center_after_socket_replacement_without_a_conv app.app_server_target = AppServerTarget::LocalDaemon { endpoint: endpoint.clone(), }; + if previous_thread.is_none() { + app.chat_widget.windows_sandbox_elevated_setup_complete = true; + } let available = Arc::new(std::sync::atomic::AtomicBool::new(false)); let server_available = Arc::clone(&available); let restored_previous = previous_thread @@ -314,6 +317,9 @@ async fn reconnect_daemon_command_center_after_socket_replacement_without_a_conv CODEX_CLI_VERSION, ) .await?; + if previous_thread.is_none() { + assert!(app.chat_widget.windows_sandbox_elevated_setup_complete); + } assert!(!app.reconnect.offline); assert_eq!(app.current_displayed_thread_id(), previous_thread); diff --git a/codex-rs/tui/src/app/tests/startup.rs b/codex-rs/tui/src/app/tests/startup.rs index 9ef3aca8df..455128cf43 100644 --- a/codex-rs/tui/src/app/tests/startup.rs +++ b/codex-rs/tui/src/app/tests/startup.rs @@ -15,6 +15,54 @@ use pretty_assertions::assert_eq; use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::unbounded_channel; +#[tokio::test] +async fn windows_sandbox_setup_uses_local_app_server_connection() { + let mut app = make_test_app().await; + assert!(app.windows_sandbox_setup_is_local()); + + let endpoint = crate::RemoteAppServerEndpoint::WebSocket { + websocket_url: "ws://127.0.0.1:4500".to_string(), + auth_token: None, + }; + app.app_server_target = crate::AppServerTarget::LocalDaemon { + endpoint: endpoint.clone(), + }; + assert!(app.windows_sandbox_setup_is_local()); + + app.app_server_target = crate::AppServerTarget::Remote { endpoint }; + assert!(!app.windows_sandbox_setup_is_local()); +} + +#[tokio::test] +async fn windows_sandbox_setup_skips_remote_default_executor() -> Result<()> { + let mut app = make_test_app().await; + app.environment_manager = Arc::new( + EnvironmentManager::create_for_tests( + Some("ws://127.0.0.1:8765".to_string()), + Some(codex_exec_server::ExecServerRuntimePaths::new( + std::env::current_exe()?, + /*codex_linux_sandbox_exe*/ None, + )?), + ) + .await, + ); + assert!(!app.windows_sandbox_setup_is_local()); + + app.environment_manager = Arc::new( + EnvironmentManager::create_for_tests_with_local( + Some("ws://127.0.0.1:8765".to_string()), + codex_exec_server::ExecServerRuntimePaths::new( + std::env::current_exe()?, + /*codex_linux_sandbox_exe*/ None, + )?, + ) + .await, + ); + assert_eq!(app.windows_sandbox_host(), WindowsSandboxHost::Mixed); + assert!(!app.windows_sandbox_setup_is_local()); + Ok(()) +} + fn startup_bottom_pane() -> (BottomPane, UnboundedReceiver) { let (app_event_tx, app_event_rx) = unbounded_channel(); ( diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 4e6a7dfbcd..4f91c11b20 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -255,8 +255,6 @@ use crate::app_event::AppEvent; use crate::app_event::ExitMode; use crate::app_event::PermissionProfileSelection; use crate::app_event::RateLimitRefreshOrigin; -#[cfg(target_os = "windows")] -use crate::app_event::WindowsSandboxEnableMode; use crate::app_event_sender::AppEventSender; use crate::auto_review_denials; use crate::auto_review_denials::RecentAutoReviewDenials; @@ -593,10 +591,13 @@ pub(crate) struct ChatWidget { model_popup_model_ids: Vec, session_telemetry: SessionTelemetry, session_header: SessionHeader, - initial_user_message: Option, + pub(crate) initial_user_message: Option, status_account_display: Option, pub(crate) remote_connection: Option, pub(crate) local_worktree_operations: bool, + pub(crate) windows_sandbox_host: crate::app::WindowsSandboxHost, + #[cfg(any(target_os = "windows", test))] + pub(crate) windows_sandbox_elevated_setup_complete: bool, token_info: Option, token_usage_pending: bool, // Status and polling use account usage reads; response streams may identify meters differently. diff --git a/codex-rs/tui/src/chatwidget/constructor.rs b/codex-rs/tui/src/chatwidget/constructor.rs index 5eaa8d7715..af8e867122 100644 --- a/codex-rs/tui/src/chatwidget/constructor.rs +++ b/codex-rs/tui/src/chatwidget/constructor.rs @@ -135,6 +135,9 @@ impl ChatWidget { status_account_display, remote_connection: None, local_worktree_operations: true, + windows_sandbox_host: crate::app::WindowsSandboxHost::Local, + #[cfg(any(target_os = "windows", test))] + windows_sandbox_elevated_setup_complete: false, token_info: None, token_usage_pending: false, rate_limit_snapshots_by_limit_id: BTreeMap::new(), diff --git a/codex-rs/tui/src/chatwidget/input_restore.rs b/codex-rs/tui/src/chatwidget/input_restore.rs index 74dd84314a..a15bb8e140 100644 --- a/codex-rs/tui/src/chatwidget/input_restore.rs +++ b/codex-rs/tui/src/chatwidget/input_restore.rs @@ -118,7 +118,9 @@ impl ChatWidget { return; } #[cfg(any(target_os = "windows", test))] - if self.elevated_windows_sandbox_setup_required() { + if self.windows_sandbox_host == crate::app::WindowsSandboxHost::Local + && self.elevated_windows_sandbox_setup_required() + { return; } if let Some(draft) = pending_draft.take() { @@ -136,7 +138,18 @@ impl ChatWidget { return; } #[cfg(any(target_os = "windows", test))] - if self.elevated_windows_sandbox_setup_required() { + if self.windows_sandbox_host == crate::app::WindowsSandboxHost::Local + && self.elevated_windows_sandbox_setup_required() + { + return; + } + #[cfg(any(target_os = "windows", test))] + if self.windows_sandbox_host == crate::app::WindowsSandboxHost::Mixed + && self.elevated_windows_sandbox_setup_required() + { + if let Some(user_message) = self.initial_user_message.take() { + self.restore_user_message_to_composer(user_message); + } return; } if self.blocks_direct_input { diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs index 77fe534ab8..9ccd41b427 100644 --- a/codex-rs/tui/src/chatwidget/permission_popups.rs +++ b/codex-rs/tui/src/chatwidget/permission_popups.rs @@ -323,6 +323,17 @@ impl ChatWidget { }; let requires_confirmation = approvals_reviewer == ApprovalsReviewer::User && preset.id == "full-access"; + #[cfg(target_os = "windows")] + if preset.id == "auto" && self.windows_sandbox_host == crate::app::WindowsSandboxHost::Mixed + { + let preset = preset.clone(); + return vec![Box::new(move |tx| { + tx.send(AppEvent::OpenWindowsSandboxEnablePrompt { + preset: preset.clone(), + profile_selection: profile_selection.clone(), + }); + })]; + } if requires_confirmation { let preset = preset.clone(); return vec![Box::new(move |tx| { @@ -336,21 +347,15 @@ impl ChatWidget { if approvals_reviewer == ApprovalsReviewer::User && preset.id == "auto" { #[cfg(target_os = "windows")] { + if self.windows_sandbox_host == crate::app::WindowsSandboxHost::Remote { + // The remote server owns the permission choice. Its executor + // cannot be set up from this TUI's Windows account. + return apply_actions(); + } if crate::windows_sandbox::level_from_config(&self.config) == WindowsSandboxLevel::Disabled { let preset = preset.clone(); - if crate::windows_sandbox::sandbox_setup_is_complete( - self.config.codex_home.as_path(), - ) { - return vec![Box::new(move |tx| { - tx.send(AppEvent::EnableWindowsSandboxForAgentMode { - preset: preset.clone(), - mode: WindowsSandboxEnableMode::Elevated, - profile_selection: profile_selection.clone(), - }); - })]; - } return vec![Box::new(move |tx| { tx.send(AppEvent::OpenWindowsSandboxEnablePrompt { preset: preset.clone(), diff --git a/codex-rs/tui/src/chatwidget/permission_shortcuts.rs b/codex-rs/tui/src/chatwidget/permission_shortcuts.rs index 879d89e1d4..8079f471c0 100644 --- a/codex-rs/tui/src/chatwidget/permission_shortcuts.rs +++ b/codex-rs/tui/src/chatwidget/permission_shortcuts.rs @@ -55,12 +55,13 @@ impl ChatWidget { { continue; } - // Agent mode still needs explicit Windows setup. + // These modes still need the explicit Windows setup/warning flow. #[cfg(target_os = "windows")] if preset.id == "auto" - && reviewer == ApprovalsReviewer::User - && crate::windows_sandbox::level_from_config(&self.config) - == WindowsSandboxLevel::Disabled + && (self.windows_sandbox_host == crate::app::WindowsSandboxHost::Mixed + || (reviewer == ApprovalsReviewer::User + && crate::windows_sandbox::level_from_config(&self.config) + == WindowsSandboxLevel::Disabled)) { continue; } diff --git a/codex-rs/tui/src/chatwidget/tests/permissions.rs b/codex-rs/tui/src/chatwidget/tests/permissions.rs index f0f087bb63..2ea2387d36 100644 --- a/codex-rs/tui/src/chatwidget/tests/permissions.rs +++ b/codex-rs/tui/src/chatwidget/tests/permissions.rs @@ -11,6 +11,31 @@ use codex_protocol::permissions::FileSystemSpecialPath; use codex_protocol::permissions::NetworkSandboxPolicy; use pretty_assertions::assert_eq; +#[cfg(target_os = "windows")] +#[tokio::test] +async fn remote_windows_agent_permission_uses_server_selection() { + let preset = builtin_approval_presets() + .into_iter() + .find(|preset| preset.id == "auto") + .expect("Agent preset"); + let (mut chat, mut events, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + chat.windows_sandbox_host = crate::app::WindowsSandboxHost::Remote; + chat.config.permissions.windows_sandbox_mode = Some(WindowsSandboxModeToml::Elevated); + let actions = chat.permission_mode_actions( + &preset, + "Agent".to_string(), + ApprovalsReviewer::User, + /*profile_selection*/ None, + /*return_to_permissions*/ false, + ); + actions[0](&chat.app_event_tx); + assert!(matches!(events.try_recv(), Ok(AppEvent::CodexOp(_)))); + assert!(matches!( + events.try_recv(), + Ok(AppEvent::UpdateAskForApprovalPolicy(_)) + )); +} + #[tokio::test] async fn permission_discovery_uses_server_catalog_for_remote_custom_selection() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; @@ -766,6 +791,22 @@ async fn required_windows_sandbox_setup_defers_configured_initial_prompt() { ); } +#[tokio::test] +async fn mixed_executors_restore_required_sandbox_prompt_without_submitting() { + let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + chat.windows_sandbox_host = crate::app::WindowsSandboxHost::Mixed; + chat.config.permissions.windows_sandbox_mode = Some(WindowsSandboxModeToml::Elevated); + chat.config.config_layer_stack = + windows_sandbox_requirements_stack(vec![WindowsSandboxModeToml::Elevated]); + chat.initial_user_message = + create_initial_user_message(Some("review this".to_string()), Vec::new(), Vec::new()); + + chat.submit_initial_user_message_if_pending(); + + assert_eq!(chat.composer_text_with_pending(), "review this"); + assert!(op_rx.try_recv().is_err()); +} + #[tokio::test] async fn windows_sandbox_required_fallback_prompt_snapshot() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; diff --git a/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs b/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs index a2c81ec667..fbe018fb48 100644 --- a/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs +++ b/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs @@ -14,7 +14,7 @@ impl ChatWidget { } #[cfg(any(target_os = "windows", test))] - pub(super) fn elevated_windows_sandbox_setup_required(&self) -> bool { + pub(crate) fn required_elevated_windows_sandbox(&self) -> bool { crate::windows_sandbox::level_from_config(&self.config) == WindowsSandboxLevel::Elevated && self .config @@ -23,7 +23,11 @@ impl ChatWidget { .windows_sandbox_mode .source .is_some() - && !crate::windows_sandbox::sandbox_setup_is_complete(self.config.codex_home.as_path()) + } + + #[cfg(any(target_os = "windows", test))] + pub(super) fn elevated_windows_sandbox_setup_required(&self) -> bool { + self.required_elevated_windows_sandbox() && !self.windows_sandbox_elevated_setup_complete } #[cfg(any(target_os = "windows", test))] diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index 5e922fb8ae..6a0c65565e 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -1818,8 +1818,7 @@ async fn run_ratatui_app( .requirements() .windows_sandbox_mode .source - .is_some() - && !crate::windows_sandbox::sandbox_setup_is_complete(config.codex_home.as_path()); + .is_some(); #[cfg(target_os = "windows")] let should_prompt_windows_sandbox_nux_at_startup = (trust_decision_was_made && windows_sandbox_level == WindowsSandboxLevel::Disabled) diff --git a/codex-rs/tui/src/windows_sandbox.rs b/codex-rs/tui/src/windows_sandbox.rs index ef70225e21..153023a450 100644 --- a/codex-rs/tui/src/windows_sandbox.rs +++ b/codex-rs/tui/src/windows_sandbox.rs @@ -15,6 +15,7 @@ use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; #[cfg(target_os = "windows")] use std::collections::HashMap; +#[cfg(target_os = "windows")] use std::path::Path; pub(crate) fn level_from_config(config: &Config) -> WindowsSandboxLevel { @@ -34,11 +35,6 @@ pub(crate) fn level_from_config(config: &Config) -> WindowsSandboxLevel { #[cfg(target_os = "windows")] pub(crate) use codex_windows_sandbox::sandbox_setup_is_complete; -#[cfg(not(target_os = "windows"))] -pub(crate) fn sandbox_setup_is_complete(_codex_home: &Path) -> bool { - false -} - #[cfg(target_os = "windows")] pub(crate) fn prepare_elevated_sandbox( permission_profile: &PermissionProfile,