diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index a983f2734a..331d379dc7 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -153,8 +153,6 @@ use codex_otel::SessionTelemetry; use codex_otel::TelemetryAuthMode; use codex_protocol::ThreadId; use codex_protocol::config_types::Personality; -#[cfg(target_os = "windows")] -use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::models::ActivePermissionProfile; use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE; use codex_protocol::models::PermissionProfile; @@ -162,8 +160,6 @@ use codex_protocol::openai_models::ModelAvailabilityNux; use codex_protocol::openai_models::ModelPreset; use codex_protocol::openai_models::ModelUpgrade; use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig; -#[cfg(target_os = "windows")] -use codex_protocol::permissions::FileSystemSandboxKind; use codex_rollout::StateDbHandle; use codex_terminal_detection::user_agent; use codex_utils_absolute_path::AbsolutePathBuf; @@ -428,14 +424,6 @@ impl AutoReviewMode { } } -#[cfg(target_os = "windows")] -fn managed_filesystem_sandbox_is_restricted(permission_profile: &PermissionProfile) -> bool { - matches!( - permission_profile.file_system_sandbox_policy().kind, - FileSystemSandboxKind::Restricted - ) -} - /// Baseline cadence for periodic stream commit animation ticks. /// /// Smooth-mode streaming drains one line per tick, so this interval controls diff --git a/codex-rs/tui/src/app/event_dispatch.rs b/codex-rs/tui/src/app/event_dispatch.rs index 8eae5d0b63..30ced383a0 100644 --- a/codex-rs/tui/src/app/event_dispatch.rs +++ b/codex-rs/tui/src/app/event_dispatch.rs @@ -1909,24 +1909,6 @@ impl App { AppEvent::ApplyPermissionShortcut { thread_id, selection } => { self.apply_permission_shortcut(app_server, tui, thread_id, selection).await; } - AppEvent::OpenWorldWritableWarningConfirmation { - preset, - profile_selection, - sample_paths, - extra_count, - failed_scan, - } => { - self.chat_widget.open_world_writable_warning_confirmation( - preset, - profile_selection, - sample_paths, - extra_count, - failed_scan, - ); - } - AppEvent::StartupWorldWritableScanCompleted => { - self.windows_sandbox.startup_world_writable_scan_pending = false; - } AppEvent::OpenFeedbackNote { category, include_logs, @@ -2229,36 +2211,7 @@ impl App { ); let windows_sandbox_level = crate::windows_sandbox::level_from_config(&self.config); - if let Some((sample_paths, extra_count, failed_scan)) = - self.chat_widget.world_writable_warning_details() - { - self.app_event_tx.send(AppEvent::CodexOp( - AppCommand::override_turn_context( - /*cwd*/ None, - /*approval_policy*/ None, - /*approvals_reviewer*/ None, - /*permission_profile*/ None, - /*active_permission_profile*/ None, - #[cfg(target_os = "windows")] - Some(windows_sandbox_level), - /*model*/ None, - /*effort*/ None, - /*summary*/ None, - /*service_tier*/ None, - /*collaboration_mode*/ None, - /*personality*/ None, - ), - )); - self.app_event_tx.send( - AppEvent::OpenWorldWritableWarningConfirmation { - preset: Some(preset.clone()), - profile_selection: profile_selection.clone(), - sample_paths, - extra_count, - failed_scan, - }, - ); - } else if let Some(selection) = profile_selection { + if let Some(selection) = profile_selection { self.app_event_tx.send(AppEvent::CodexOp( AppCommand::override_turn_context( /*cwd*/ None, @@ -2504,9 +2457,6 @@ impl App { else { return Ok(AppRunControl::Continue); }; - #[cfg(target_os = "windows")] - let permission_profile_is_managed_restricted = - managed_filesystem_sandbox_is_restricted(&permission_profile); let permission_profile_for_chat = permission_profile.clone(); self.config = config; @@ -2529,42 +2479,6 @@ impl App { self.sync_active_thread_permission_settings_to_cached_session() .await; self.chat_widget.submit_initial_user_message_if_pending(); - - // If a managed filesystem sandbox is active, run the Windows - // world-writable scan. - #[cfg(target_os = "windows")] - { - // One-shot suppression if the user just confirmed continue. - if self.windows_sandbox.skip_world_writable_scan_once { - self.windows_sandbox.skip_world_writable_scan_once = false; - return Ok(AppRunControl::Continue); - } - - let should_check = crate::windows_sandbox::level_from_config(&self.config) - != WindowsSandboxLevel::Disabled - && permission_profile_is_managed_restricted - && !self.chat_widget.world_writable_warning_hidden(); - if should_check { - let cwd = self.config.cwd.clone(); - let workspace_roots = self.config.effective_workspace_roots(); - let env_map: std::collections::HashMap = - std::env::vars().collect(); - let tx = self.app_event_tx.clone(); - let logs_base_dir = self.config.codex_home.clone(); - let permission_profile = - self.config.permissions.effective_permission_profile(); - Self::spawn_world_writable_scan( - cwd, - workspace_roots, - env_map, - logs_base_dir, - permission_profile, - self.session_telemetry.clone(), - tx, - /*startup_scan*/ false, - ); - } - } } AppEvent::SelectPermissionProfile(selection) => { self.select_permission_profile(app_server, selection).await; @@ -2621,13 +2535,6 @@ impl App { AppEvent::ResetMemories => { self.reset_memories_with_app_server(app_server).await; } - AppEvent::SkipNextWorldWritableScan => { - self.windows_sandbox.skip_world_writable_scan_once = true; - } - AppEvent::UpdateWorldWritableWarningAcknowledged(ack) => { - self.chat_widget - .set_world_writable_warning_acknowledged(ack); - } AppEvent::UpdateRateLimitSwitchPromptHidden(hidden) => { self.chat_widget.set_rate_limit_switch_prompt_hidden(hidden); } @@ -2636,22 +2543,6 @@ impl App { self.sync_active_thread_plan_mode_reasoning_setting(app_server) .await; } - AppEvent::PersistWorldWritableWarningAcknowledged => { - self.local_settings.notices.hide_world_writable_warning = Some(true); - if let Err(err) = ConfigEditsBuilder::for_config_path(self.local_settings.user_config_path.as_path()) - .set_hide_world_writable_warning(/*acknowledged*/ true) - .apply() - .await - { - tracing::error!( - error = %err, - "failed to persist world-writable warning acknowledgement" - ); - self.chat_widget.add_error_message(format!( - "Failed to save Agent mode warning preference: {err}" - )); - } - } AppEvent::PersistRateLimitSwitchPromptHidden => { self.local_settings.notices.hide_rate_limit_model_nudge = Some(true); if let Err(err) = ConfigEditsBuilder::for_config_path(self.local_settings.user_config_path.as_path()) diff --git a/codex-rs/tui/src/app/platform_actions.rs b/codex-rs/tui/src/app/platform_actions.rs index bf84728fa6..32931b4d8f 100644 --- a/codex-rs/tui/src/app/platform_actions.rs +++ b/codex-rs/tui/src/app/platform_actions.rs @@ -8,68 +8,6 @@ use super::*; #[derive(Default)] pub(super) struct WindowsSandboxState { pub(super) setup_started_at: Option, - // One-shot suppression of the next world-writable scan after user confirmation. - pub(super) skip_world_writable_scan_once: bool, - /// A startup filesystem scan can still enqueue a protected warning after the app queue drains. - pub(super) startup_world_writable_scan_pending: bool, -} - -impl App { - #[cfg(target_os = "windows")] - #[allow(clippy::too_many_arguments)] - pub(super) fn spawn_world_writable_scan( - cwd: AbsolutePathBuf, - workspace_roots: Vec, - env_map: std::collections::HashMap, - logs_base_dir: AbsolutePathBuf, - permission_profile: PermissionProfile, - session_telemetry: SessionTelemetry, - tx: AppEventSender, - startup_scan: bool, - ) { - let Ok(permissions) = - codex_windows_sandbox::ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_workspace_roots( - &permission_profile, - workspace_roots.as_slice(), - ) - else { - if startup_scan { - tx.send(AppEvent::StartupWorldWritableScanCompleted); - } - return; - }; - - tokio::task::spawn_blocking(move || { - let logs_base_dir_path = logs_base_dir.as_path(); - let result = - codex_windows_sandbox::apply_world_writable_scan_and_denies_for_permissions( - logs_base_dir_path, - cwd.as_path(), - &env_map, - &permissions, - Some(logs_base_dir_path), - ); - crate::windows_sandbox::record_world_writable_scan_result(&session_telemetry, &result); - if result.is_err() { - // Scan failed: warn without examples. - send_world_writable_scan_failed(&tx); - } - if startup_scan { - tx.send(AppEvent::StartupWorldWritableScanCompleted); - } - }); - } -} - -#[cfg(target_os = "windows")] -fn send_world_writable_scan_failed(tx: &AppEventSender) { - tx.send(AppEvent::OpenWorldWritableWarningConfirmation { - preset: None, - profile_selection: None, - sample_paths: Vec::new(), - extra_count: 0usize, - failed_scan: true, - }); } pub(super) fn side_return_shortcut_matches(key_event: KeyEvent) -> bool { diff --git a/codex-rs/tui/src/app/startup.rs b/codex-rs/tui/src/app/startup.rs index 1faea715d7..c5ec00043a 100644 --- a/codex-rs/tui/src/app/startup.rs +++ b/codex-rs/tui/src/app/startup.rs @@ -128,7 +128,6 @@ impl App { pub(super) fn ready_for_terminal_color_probe(&self, has_pending_app_events: bool) -> bool { !has_pending_app_events && !self.chat_widget.has_active_view() - && !self.windows_sandbox.startup_world_writable_scan_pending && !self.startup_pending_protected_request && !self.has_queued_startup_protected_request() && !self.chat_widget.has_pending_protected_request() @@ -864,39 +863,6 @@ See the Codex keymap documentation for supported actions and examples." } let initial_session_ms = initial_session_started_at.elapsed().as_millis(); - // On startup, if a managed filesystem sandbox is active, warn about - // world-writable dirs on Windows. - #[cfg(target_os = "windows")] - { - let startup_permission_profile = app.config.permissions.effective_permission_profile(); - let should_check = crate::windows_sandbox::level_from_config(&app.config) - != WindowsSandboxLevel::Disabled - && managed_filesystem_sandbox_is_restricted(&startup_permission_profile) - && !app - .local_settings - .notices - .hide_world_writable_warning - .unwrap_or(false); - if should_check { - app.windows_sandbox.startup_world_writable_scan_pending = true; - let cwd = app.config.cwd.clone(); - let workspace_roots = app.config.effective_workspace_roots(); - let env_map: std::collections::HashMap = std::env::vars().collect(); - let tx = app.app_event_tx.clone(); - let logs_base_dir = app.config.codex_home.clone(); - Self::spawn_world_writable_scan( - cwd, - workspace_roots, - env_map, - logs_base_dir, - startup_permission_profile, - app.session_telemetry.clone(), - tx, - /*startup_scan*/ true, - ); - } - } - if let Err(err) = startup_draft.flush_pending_events(tui).await { return shutdown_on_startup_error(app_server, err).await; } diff --git a/codex-rs/tui/src/app/tests/startup.rs b/codex-rs/tui/src/app/tests/startup.rs index d217135021..9ef3aca8df 100644 --- a/codex-rs/tui/src/app/tests/startup.rs +++ b/codex-rs/tui/src/app/tests/startup.rs @@ -63,74 +63,6 @@ async fn terminal_color_probe_waits_for_startup_sandbox_choice() { assert!(app.ready_for_terminal_color_probe(/*has_pending_app_events*/ false)); } -#[tokio::test] -async fn terminal_color_probe_waits_for_delayed_world_writable_scan_failure() { - let (mut app, mut app_event_rx, _op_rx) = make_test_app_with_channels().await; - app.startup_protected_input_boundary = true; - app.windows_sandbox.startup_world_writable_scan_pending = true; - while app_event_rx.try_recv().is_ok() {} - - assert!(!app.ready_for_terminal_color_probe(/*has_pending_app_events*/ false)); - - app.app_event_tx - .send(AppEvent::OpenWorldWritableWarningConfirmation { - preset: None, - profile_selection: None, - sample_paths: Vec::new(), - extra_count: 0, - failed_scan: true, - }); - app.app_event_tx - .send(AppEvent::StartupWorldWritableScanCompleted); - assert!(!app.ready_for_terminal_color_probe(/*has_pending_app_events*/ true)); - - let warning = app_event_rx - .try_recv() - .expect("the delayed scan should queue its warning before completion"); - let AppEvent::OpenWorldWritableWarningConfirmation { - preset, - profile_selection, - sample_paths, - extra_count, - failed_scan, - } = warning - else { - panic!("the delayed scan should open a protected warning before completion"); - }; - app.chat_widget.open_world_writable_warning_confirmation( - preset, - profile_selection, - sample_paths, - extra_count, - failed_scan, - ); - assert!(matches!( - app_event_rx.try_recv(), - Ok(AppEvent::StartupWorldWritableScanCompleted) - )); - app.windows_sandbox.startup_world_writable_scan_pending = false; - - assert!(!app.windows_sandbox.startup_world_writable_scan_pending); - assert!(!app.ready_for_terminal_color_probe(/*has_pending_app_events*/ false)); - for character in "20;rgb:2222/ffff/ffff".chars() { - app.chat_widget - .handle_key_event(KeyEvent::new(KeyCode::Char(character), KeyModifiers::NONE)); - assert!(app_event_rx.try_recv().is_err()); - } - - app.chat_widget - .handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); - assert!(matches!( - app_event_rx.try_recv(), - Ok(AppEvent::UpdateWorldWritableWarningAcknowledged(true)) - )); - assert!(matches!( - app_event_rx.try_recv(), - Ok(AppEvent::PersistWorldWritableWarningAcknowledged) - )); - assert!(app.ready_for_terminal_color_probe(/*has_pending_app_events*/ false)); -} - #[test] fn startup_waiting_gate_is_only_for_fresh_or_exit_session_selection() { assert_eq!( @@ -907,12 +839,7 @@ async fn queued_startup_app_event_owns_protected_view_before_draft_restore() -> while let Ok(event) = app_event_rx.try_recv() { assert!( - !matches!( - event, - AppEvent::StartFileSearch(_) - | AppEvent::UpdateWorldWritableWarningAcknowledged(_) - | AppEvent::PersistWorldWritableWarningAcknowledged - ), + !matches!(event, AppEvent::StartFileSearch(_)), "protected startup app event must own input before draft side effects: {event:?}" ); } diff --git a/codex-rs/tui/src/app_event.rs b/codex-rs/tui/src/app_event.rs index d585e004cd..575ff2d8eb 100644 --- a/codex-rs/tui/src/app_event.rs +++ b/codex-rs/tui/src/app_event.rs @@ -1216,26 +1216,6 @@ pub(crate) enum AppEvent { selection: PermissionProfileSelection, }, - /// Open the Windows world-writable directories warning. - /// If `preset` is `Some`, the confirmation will apply the provided - /// approval/sandbox configuration on Continue; if `None`, it performs no - /// policy change and only acknowledges/dismisses the warning. - #[cfg_attr(not(target_os = "windows"), allow(dead_code))] - OpenWorldWritableWarningConfirmation { - preset: Option, - profile_selection: Option, - /// Up to 3 sample world-writable directories to display in the warning. - sample_paths: Vec, - /// If there are more than `sample_paths`, this carries the remaining count. - extra_count: usize, - /// True when the scan failed (e.g. ACL query error) and protections could not be verified. - failed_scan: bool, - }, - - /// The startup world-writable scan finished and queued any protected warning it requires. - #[cfg_attr(not(target_os = "windows"), allow(dead_code))] - StartupWorldWritableScanCompleted, - /// Prompt to enable the Windows sandbox feature before using Agent mode. #[cfg_attr(not(target_os = "windows"), allow(dead_code))] OpenWindowsSandboxEnablePrompt { @@ -1319,20 +1299,12 @@ pub(crate) enum AppEvent { /// Clear all persisted local memory artifacts via the app-server. ResetMemories, - /// Update whether the world-writable directories warning has been acknowledged. - #[cfg_attr(not(target_os = "windows"), allow(dead_code))] - UpdateWorldWritableWarningAcknowledged(bool), - /// Update whether the rate limit switch prompt has been acknowledged for the session. UpdateRateLimitSwitchPromptHidden(bool), /// Update the Plan-mode-specific reasoning effort in memory. UpdatePlanModeReasoningEffort(Option), - /// Persist the acknowledgement flag for the world-writable directories warning. - #[cfg_attr(not(target_os = "windows"), allow(dead_code))] - PersistWorldWritableWarningAcknowledged, - /// Persist the acknowledgement flag for the rate limit switch prompt. PersistRateLimitSwitchPromptHidden, @@ -1345,10 +1317,6 @@ pub(crate) enum AppEvent { to_model: String, }, - /// Skip the next world-writable scan (one-shot) after a user-confirmed continue. - #[cfg_attr(not(target_os = "windows"), allow(dead_code))] - SkipNextWorldWritableScan, - /// Re-open the approval presets popup. OpenApprovalsPopup, diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs index 53525f7c6e..77fe534ab8 100644 --- a/codex-rs/tui/src/chatwidget/permission_popups.rs +++ b/codex-rs/tui/src/chatwidget/permission_popups.rs @@ -358,20 +358,6 @@ impl ChatWidget { }); })]; } - if let Some((sample_paths, extra_count, failed_scan)) = - self.world_writable_warning_details() - { - let preset = preset.clone(); - return vec![Box::new(move |tx| { - tx.send(AppEvent::OpenWorldWritableWarningConfirmation { - preset: Some(preset.clone()), - profile_selection: profile_selection.clone(), - sample_paths: sample_paths.clone(), - extra_count, - failed_scan, - }); - })]; - } } } apply_actions() diff --git a/codex-rs/tui/src/chatwidget/permission_shortcuts.rs b/codex-rs/tui/src/chatwidget/permission_shortcuts.rs index 499dbe4b90..879d89e1d4 100644 --- a/codex-rs/tui/src/chatwidget/permission_shortcuts.rs +++ b/codex-rs/tui/src/chatwidget/permission_shortcuts.rs @@ -55,13 +55,12 @@ impl ChatWidget { { continue; } - // These modes still need the explicit Windows setup/warning flow. + // Agent mode still needs explicit Windows setup. #[cfg(target_os = "windows")] if preset.id == "auto" && reviewer == ApprovalsReviewer::User - && (crate::windows_sandbox::level_from_config(&self.config) + && crate::windows_sandbox::level_from_config(&self.config) == WindowsSandboxLevel::Disabled - || self.world_writable_warning_details().is_some()) { continue; } diff --git a/codex-rs/tui/src/chatwidget/settings.rs b/codex-rs/tui/src/chatwidget/settings.rs index 7cef3753c5..edda2fdba3 100644 --- a/codex-rs/tui/src/chatwidget/settings.rs +++ b/codex-rs/tui/src/chatwidget/settings.rs @@ -140,18 +140,6 @@ impl ChatWidget { self.refresh_status_surfaces(); } - pub(crate) fn set_world_writable_warning_acknowledged(&mut self, acknowledged: bool) { - self.local_settings.notices.hide_world_writable_warning = Some(acknowledged); - } - - #[cfg_attr(not(target_os = "windows"), allow(dead_code))] - pub(crate) fn world_writable_warning_hidden(&self) -> bool { - self.local_settings - .notices - .hide_world_writable_warning - .unwrap_or(false) - } - /// Override the reasoning effort used when Plan mode is active. /// /// When the active mask is already Plan, the override is applied immediately diff --git a/codex-rs/tui/src/chatwidget/tests/permission_shortcuts_tests.rs b/codex-rs/tui/src/chatwidget/tests/permission_shortcuts_tests.rs index d4124662ac..f45405051d 100644 --- a/codex-rs/tui/src/chatwidget/tests/permission_shortcuts_tests.rs +++ b/codex-rs/tui/src/chatwidget/tests/permission_shortcuts_tests.rs @@ -14,7 +14,6 @@ async fn permission_shortcuts_cycle_builtin_modes() { chat.chat_keymap.previous_permission_mode = vec![crate::key_hint::plain(KeyCode::F(7))]; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } for (current, reviewer, key, expected, next_reviewer) in [ diff --git a/codex-rs/tui/src/chatwidget/tests/permissions.rs b/codex-rs/tui/src/chatwidget/tests/permissions.rs index 680a94ed14..f0f087bb63 100644 --- a/codex-rs/tui/src/chatwidget/tests/permissions.rs +++ b/codex-rs/tui/src/chatwidget/tests/permissions.rs @@ -684,45 +684,6 @@ async fn fragmented_terminal_response_cannot_select_non_admin_windows_sandbox() } } -#[tokio::test] -async fn fragmented_terminal_response_cannot_acknowledge_world_writable_warning() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; - chat.open_world_writable_warning_confirmation( - /*preset*/ None, - /*profile_selection*/ None, - Vec::new(), - /*extra_count*/ 0, - /*failed_scan*/ true, - ); - - chat.handle_key_event(KeyEvent::new(KeyCode::Char('1'), KeyModifiers::NONE)); - assert!(chat.has_active_view()); - assert!(rx.try_recv().is_err()); - - for character in "20;rgb:2222/ffff/ffff".chars() { - chat.handle_key_event(KeyEvent::new(KeyCode::Char(character), KeyModifiers::NONE)); - assert!( - !matches!( - rx.try_recv(), - Ok(AppEvent::UpdateWorldWritableWarningAcknowledged(_) - | AppEvent::PersistWorldWritableWarningAcknowledged) - ), - "a fragmented terminal response must not acknowledge the world-writable warning" - ); - } - - assert!(chat.has_active_view()); - chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); - assert!(matches!( - rx.try_recv(), - Ok(AppEvent::UpdateWorldWritableWarningAcknowledged(true)) - )); - assert!(matches!( - rx.try_recv(), - Ok(AppEvent::PersistWorldWritableWarningAcknowledged) - )); -} - #[tokio::test] async fn windows_sandbox_setup_starts_a_fresh_status_clock() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; @@ -977,7 +938,6 @@ async fn permissions_selection_emits_history_cell_when_selection_changes() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ true); @@ -1003,7 +963,6 @@ async fn permissions_selection_history_snapshot_after_mode_switch() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ false); @@ -1040,7 +999,6 @@ async fn permissions_selection_history_snapshot_full_access_to_default() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.config @@ -1082,7 +1040,6 @@ async fn permissions_selection_emits_history_cell_when_current_is_selected() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.config @@ -1116,7 +1073,6 @@ async fn permissions_selection_hides_auto_review_when_feature_disabled() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ false); @@ -1135,7 +1091,6 @@ async fn permissions_selection_hides_auto_review_when_feature_disabled_even_if_a let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ false); @@ -1164,7 +1119,6 @@ async fn permissions_selection_marks_auto_review_current_after_session_configure let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } let _ = chat @@ -1209,7 +1163,6 @@ async fn permissions_selection_marks_auto_review_current_with_custom_workspace_w let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } let _ = chat @@ -1258,7 +1211,6 @@ async fn permissions_selection_can_disable_auto_review() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ true); @@ -1298,7 +1250,6 @@ async fn permissions_selection_sends_approvals_reviewer_in_override_turn_context let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ true); @@ -1379,7 +1330,6 @@ async fn permissions_full_access_history_cell_emitted_only_after_confirmation() let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; #[cfg(target_os = "windows")] { - chat.local_settings.notices.hide_world_writable_warning = Some(true); chat.set_windows_sandbox_mode(Some(WindowsSandboxModeToml::Unelevated)); } chat.set_feature_enabled(Feature::GuardianApproval, /*enabled*/ false); diff --git a/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs b/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs index 724f7a4f3c..a2c81ec667 100644 --- a/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs +++ b/codex-rs/tui/src/chatwidget/windows_sandbox_prompts.rs @@ -26,199 +26,6 @@ impl ChatWidget { && !crate::windows_sandbox::sandbox_setup_is_complete(self.config.codex_home.as_path()) } - #[cfg(target_os = "windows")] - pub(crate) fn world_writable_warning_details(&self) -> Option<(Vec, usize, bool)> { - if self - .local_settings - .notices - .hide_world_writable_warning - .unwrap_or(false) - { - return None; - } - let cwd = self.config.cwd.clone(); - let workspace_roots = self.config.effective_workspace_roots(); - let env_map: std::collections::HashMap = std::env::vars().collect(); - let permission_profile = self.config.permissions.effective_permission_profile(); - let Ok(permissions) = - codex_windows_sandbox::ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_workspace_roots( - &permission_profile, - workspace_roots.as_slice(), - ) - else { - return None; - }; - let result = codex_windows_sandbox::apply_world_writable_scan_and_denies_for_permissions( - self.config.codex_home.as_path(), - cwd.as_path(), - &env_map, - &permissions, - Some(self.config.codex_home.as_path()), - ); - crate::windows_sandbox::record_world_writable_scan_result(&self.session_telemetry, &result); - match result { - Ok(_) => None, - Err(_) => Some((Vec::new(), 0, true)), - } - } - - #[cfg(not(target_os = "windows"))] - #[allow(dead_code)] - pub(crate) fn world_writable_warning_details(&self) -> Option<(Vec, usize, bool)> { - None - } - - #[cfg(any(target_os = "windows", test))] - pub(crate) fn open_world_writable_warning_confirmation( - &mut self, - preset: Option, - profile_selection: Option, - sample_paths: Vec, - extra_count: usize, - failed_scan: bool, - ) { - let (approval, permission_profile, active_permission_profile) = match &preset { - Some(p) => ( - Some(AskForApproval::from(p.approval)), - Some(p.permission_profile.clone()), - Some(p.active_permission_profile.clone()), - ), - None => (None, None, None), - }; - let mut header_children: Vec> = Vec::new(); - let describe_profile = |profile: &PermissionProfile| { - if matches!(profile, PermissionProfile::Disabled) { - "Full Access mode" - } else if profile - .file_system_sandbox_policy() - .can_write_local_path_with_cwd(self.config.cwd.as_path(), self.config.cwd.as_path()) - { - "Agent mode" - } else { - "Read-Only mode" - } - }; - let mode_label = preset - .as_ref() - .map(|p| describe_profile(&p.permission_profile)) - .unwrap_or_else(|| { - describe_profile(&self.config.permissions.effective_permission_profile()) - }); - let info_line = if failed_scan { - Line::from(vec![ - "We couldn't complete the world-writable scan, so protections cannot be verified. " - .into(), - format!("The Windows sandbox cannot guarantee protection in {mode_label}.").red(), - ]) - } else { - Line::from(vec![ - "The Windows sandbox cannot protect writes to folders that are writable by Everyone.".into(), - " Consider removing write access for Everyone from the following folders:".into(), - ]) - }; - header_children.push(Box::new( - Paragraph::new(vec![info_line]).wrap(Wrap { trim: false }), - )); - - if !sample_paths.is_empty() { - // Show up to three examples and optionally an "and X more" line. - let mut lines: Vec = Vec::new(); - lines.push(Line::from("")); - for p in &sample_paths { - lines.push(Line::from(format!(" - {p}"))); - } - if extra_count > 0 { - lines.push(Line::from(format!("and {extra_count} more"))); - } - header_children.push(Box::new(Paragraph::new(lines).wrap(Wrap { trim: false }))); - } - let header = ColumnRenderable::with(header_children); - - // Build actions ensuring acknowledgement happens before applying the - // new permission profile, so downstream policy-change hooks don't - // re-trigger the warning. - let mut accept_actions: Vec = Vec::new(); - // Suppress the immediate re-scan only when a preset will be applied via - // /permissions, to avoid duplicate warnings from the ensuing policy change. - if preset.is_some() { - accept_actions.push(Box::new(|tx| { - tx.send(AppEvent::SkipNextWorldWritableScan); - })); - } - if let Some(selection) = profile_selection.clone() { - accept_actions.extend(Self::permission_profile_selection_actions(selection)); - } else if let (Some(approval), Some(permission_profile), Some(active_permission_profile)) = ( - approval, - permission_profile.clone(), - active_permission_profile.clone(), - ) { - accept_actions.extend(Self::approval_preset_actions( - approval, - permission_profile, - active_permission_profile, - mode_label.to_string(), - ApprovalsReviewer::User, - )); - } - - let mut accept_and_remember_actions: Vec = Vec::new(); - accept_and_remember_actions.push(Box::new(|tx| { - tx.send(AppEvent::UpdateWorldWritableWarningAcknowledged(true)); - tx.send(AppEvent::PersistWorldWritableWarningAcknowledged); - })); - if let Some(selection) = profile_selection { - accept_and_remember_actions - .extend(Self::permission_profile_selection_actions(selection)); - } else if let (Some(approval), Some(permission_profile), Some(active_permission_profile)) = - (approval, permission_profile, active_permission_profile) - { - accept_and_remember_actions.extend(Self::approval_preset_actions( - approval, - permission_profile, - active_permission_profile, - mode_label.to_string(), - ApprovalsReviewer::User, - )); - } - - let items = vec![ - SelectionItem { - name: "Continue".to_string(), - description: Some(format!("Apply {mode_label} for this session")), - actions: accept_actions, - dismiss_on_select: true, - require_explicit_confirmation: true, - ..Default::default() - }, - SelectionItem { - name: "Continue and don't warn again".to_string(), - description: Some(format!("Enable {mode_label} and remember this choice")), - actions: accept_and_remember_actions, - dismiss_on_select: true, - require_explicit_confirmation: true, - ..Default::default() - }, - ]; - - self.bottom_pane.show_selection_view(SelectionViewParams { - footer_hint: Some(standard_popup_hint_line()), - items, - header: Box::new(header), - ..Default::default() - }); - } - - #[cfg(all(not(target_os = "windows"), not(test)))] - pub(crate) fn open_world_writable_warning_confirmation( - &mut self, - _preset: Option, - _profile_selection: Option, - _sample_paths: Vec, - _extra_count: usize, - _failed_scan: bool, - ) { - } - #[cfg(any(target_os = "windows", test))] pub(crate) fn open_windows_sandbox_enable_prompt( &mut self, diff --git a/codex-rs/tui/src/windows_sandbox.rs b/codex-rs/tui/src/windows_sandbox.rs index 0a4d9e8199..ef70225e21 100644 --- a/codex-rs/tui/src/windows_sandbox.rs +++ b/codex-rs/tui/src/windows_sandbox.rs @@ -8,8 +8,6 @@ use crate::legacy_core::config::Config; use codex_config::types::WindowsSandboxModeToml; use codex_features::Feature; -#[cfg(target_os = "windows")] -use codex_otel::SessionTelemetry; use codex_protocol::config_types::WindowsSandboxLevel; #[cfg(target_os = "windows")] use codex_protocol::models::PermissionProfile; @@ -19,22 +17,6 @@ use codex_utils_absolute_path::AbsolutePathBuf; use std::collections::HashMap; use std::path::Path; -#[cfg(target_os = "windows")] -pub(crate) fn record_world_writable_scan_result( - session_telemetry: &SessionTelemetry, - result: &anyhow::Result, -) { - let (flagged_count, result) = match result { - Ok(flagged_count) => (*flagged_count as i64, "success"), - Err(_) => (0, "error"), - }; - session_telemetry.histogram( - "codex.windows_sandbox.world_writable_scan_flagged_directories", - flagged_count, - &[("result", result)], - ); -} - pub(crate) fn level_from_config(config: &Config) -> WindowsSandboxLevel { match config.permissions.windows_sandbox_mode { Some(WindowsSandboxModeToml::Elevated) => WindowsSandboxLevel::Elevated,