diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 036224cab..8b6539eb6 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -91,6 +91,7 @@ use codex_app_server_protocol::TurnStatus; use codex_app_server_protocol::UserInfoResponse; use codex_app_server_protocol::UserInput as V2UserInput; use codex_app_server_protocol::UserSavedConfig; +use codex_app_server_protocol::WindowsWorldWritableWarningNotification; use codex_app_server_protocol::build_turns_from_event_msgs; use codex_backend_client::Client as BackendClient; use codex_core::AuthManager; @@ -1239,7 +1240,7 @@ impl CodexMessageProcessor { let overrides = ConfigOverrides { model, config_profile: profile, - cwd: cwd.map(PathBuf::from), + cwd: cwd.clone().map(PathBuf::from), approval_policy, sandbox_mode, model_provider, @@ -1254,7 +1255,7 @@ impl CodexMessageProcessor { // Persist windows sandbox feature. // TODO: persist default config in general. let mut cli_overrides = cli_overrides.unwrap_or_default(); - if cfg!(target_os = "windows") && self.config.features.enabled(Feature::WindowsSandbox) { + if cfg!(windows) && self.config.features.enabled(Feature::WindowsSandbox) { cli_overrides.insert( "features.enable_experimental_windows_sandbox".to_string(), serde_json::json!(true), @@ -1273,6 +1274,10 @@ impl CodexMessageProcessor { return; } }; + if cfg!(windows) && config.features.enabled(Feature::WindowsSandbox) { + self.handle_windows_world_writable_warning(config.cwd.clone()) + .await; + } match self.conversation_manager.new_conversation(config).await { Ok(conversation_id) => { @@ -1953,6 +1958,15 @@ impl CodexMessageProcessor { include_apply_patch_tool, } = overrides; + // Persist windows sandbox feature. + let mut cli_overrides = cli_overrides.unwrap_or_default(); + if cfg!(windows) && self.config.features.enabled(Feature::WindowsSandbox) { + cli_overrides.insert( + "features.enable_experimental_windows_sandbox".to_string(), + serde_json::json!(true), + ); + } + let overrides = ConfigOverrides { model, config_profile: profile, @@ -1968,7 +1982,7 @@ impl CodexMessageProcessor { ..Default::default() }; - derive_config_from_params(overrides, cli_overrides).await + derive_config_from_params(overrides, Some(cli_overrides)).await } None => Ok(self.config.as_ref().clone()), }; @@ -1983,6 +1997,10 @@ impl CodexMessageProcessor { return; } }; + if cfg!(windows) && config.features.enabled(Feature::WindowsSandbox) { + self.handle_windows_world_writable_warning(config.cwd.clone()) + .await; + } let conversation_history = if let Some(path) = path { match RolloutRecorder::get_rollout_history(&path).await { @@ -2841,6 +2859,53 @@ impl CodexMessageProcessor { Err(_) => None, } } + + /// On Windows, when using the experimental sandbox, we need to warn the user about world-writable directories. + async fn handle_windows_world_writable_warning(&self, cwd: PathBuf) { + if !cfg!(windows) { + return; + } + + if !self.config.features.enabled(Feature::WindowsSandbox) { + return; + } + + if !matches!( + self.config.sandbox_policy, + codex_protocol::protocol::SandboxPolicy::WorkspaceWrite { .. } + | codex_protocol::protocol::SandboxPolicy::ReadOnly + ) { + return; + } + + if self + .config + .notices + .hide_world_writable_warning + .unwrap_or(false) + { + return; + } + + // This function is stubbed out to return None on non-Windows platforms + if let Some((sample_paths, extra_count, failed_scan)) = + codex_windows_sandbox::world_writable_warning_details( + self.config.codex_home.as_path(), + cwd, + ) + { + tracing::warn!("world writable warning: {sample_paths:?} {extra_count} {failed_scan}"); + self.outgoing + .send_server_notification(ServerNotification::WindowsWorldWritableWarning( + WindowsWorldWritableWarningNotification { + sample_paths, + extra_count, + failed_scan, + }, + )) + .await; + } + } } async fn derive_config_from_params( diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index 93af87038..403263b89 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -11,14 +11,11 @@ use codex_app_server_protocol::JSONRPCErrorError; use codex_app_server_protocol::JSONRPCNotification; use codex_app_server_protocol::JSONRPCRequest; use codex_app_server_protocol::JSONRPCResponse; -use codex_app_server_protocol::ServerNotification; -use codex_app_server_protocol::WindowsWorldWritableWarningNotification; use codex_core::AuthManager; use codex_core::ConversationManager; use codex_core::config::Config; use codex_core::default_client::USER_AGENT_SUFFIX; use codex_core::default_client::get_codex_user_agent; -use codex_core::features::Feature; use codex_feedback::CodexFeedback; use codex_protocol::protocol::SessionSource; use std::sync::Arc; @@ -26,7 +23,6 @@ use std::sync::Arc; pub(crate) struct MessageProcessor { outgoing: Arc, codex_message_processor: CodexMessageProcessor, - config: Arc, initialized: bool, } @@ -54,14 +50,13 @@ impl MessageProcessor { conversation_manager, outgoing.clone(), codex_linux_sandbox_exe, - config.clone(), + config, feedback, ); Self { outgoing, codex_message_processor, - config, initialized: false, } } @@ -122,7 +117,6 @@ impl MessageProcessor { self.outgoing.send_response(request_id, response).await; self.initialized = true; - self.handle_windows_world_writable_warning().await; return; } @@ -162,54 +156,4 @@ impl MessageProcessor { pub(crate) fn process_error(&mut self, err: JSONRPCError) { tracing::error!("<- error: {:?}", err); } - - /// On Windows, when using the experimental sandbox, we need to warn the user about world-writable directories. - async fn handle_windows_world_writable_warning(&self) { - if !cfg!(windows) { - return; - } - - if !self.config.features.enabled(Feature::WindowsSandbox) { - return; - } - - if !matches!( - self.config.sandbox_policy, - codex_protocol::protocol::SandboxPolicy::WorkspaceWrite { .. } - | codex_protocol::protocol::SandboxPolicy::ReadOnly - ) { - return; - } - - if self - .config - .notices - .hide_world_writable_warning - .unwrap_or(false) - { - return; - } - - // This function is stubbed out to return None on non-Windows platforms - let cwd = match std::env::current_dir() { - Ok(cwd) => cwd, - Err(_) => return, - }; - if let Some((sample_paths, extra_count, failed_scan)) = - codex_windows_sandbox::world_writable_warning_details( - self.config.codex_home.as_path(), - cwd, - ) - { - self.outgoing - .send_server_notification(ServerNotification::WindowsWorldWritableWarning( - WindowsWorldWritableWarningNotification { - sample_paths, - extra_count, - failed_scan, - }, - )) - .await; - } - } }