@@ -91,6 +91,7 @@ use codex_app_server_protocol::TurnStatus;
9191use codex_app_server_protocol:: UserInfoResponse ;
9292use codex_app_server_protocol:: UserInput as V2UserInput ;
9393use codex_app_server_protocol:: UserSavedConfig ;
94+ use codex_app_server_protocol:: WindowsWorldWritableWarningNotification ;
9495use codex_app_server_protocol:: build_turns_from_event_msgs;
9596use codex_backend_client:: Client as BackendClient ;
9697use codex_core:: AuthManager ;
@@ -1239,7 +1240,7 @@ impl CodexMessageProcessor {
12391240 let overrides = ConfigOverrides {
12401241 model,
12411242 config_profile : profile,
1242- cwd : cwd. map ( PathBuf :: from) ,
1243+ cwd : cwd. clone ( ) . map ( PathBuf :: from) ,
12431244 approval_policy,
12441245 sandbox_mode,
12451246 model_provider,
@@ -1254,7 +1255,7 @@ impl CodexMessageProcessor {
12541255 // Persist windows sandbox feature.
12551256 // TODO: persist default config in general.
12561257 let mut cli_overrides = cli_overrides. unwrap_or_default ( ) ;
1257- if cfg ! ( target_os = " windows" ) && self . config . features . enabled ( Feature :: WindowsSandbox ) {
1258+ if cfg ! ( windows) && self . config . features . enabled ( Feature :: WindowsSandbox ) {
12581259 cli_overrides. insert (
12591260 "features.enable_experimental_windows_sandbox" . to_string ( ) ,
12601261 serde_json:: json!( true ) ,
@@ -1273,6 +1274,10 @@ impl CodexMessageProcessor {
12731274 return ;
12741275 }
12751276 } ;
1277+ if cfg ! ( windows) && config. features . enabled ( Feature :: WindowsSandbox ) {
1278+ self . handle_windows_world_writable_warning ( config. cwd . clone ( ) )
1279+ . await ;
1280+ }
12761281
12771282 match self . conversation_manager . new_conversation ( config) . await {
12781283 Ok ( conversation_id) => {
@@ -1953,6 +1958,15 @@ impl CodexMessageProcessor {
19531958 include_apply_patch_tool,
19541959 } = overrides;
19551960
1961+ // Persist windows sandbox feature.
1962+ let mut cli_overrides = cli_overrides. unwrap_or_default ( ) ;
1963+ if cfg ! ( windows) && self . config . features . enabled ( Feature :: WindowsSandbox ) {
1964+ cli_overrides. insert (
1965+ "features.enable_experimental_windows_sandbox" . to_string ( ) ,
1966+ serde_json:: json!( true ) ,
1967+ ) ;
1968+ }
1969+
19561970 let overrides = ConfigOverrides {
19571971 model,
19581972 config_profile : profile,
@@ -1968,7 +1982,7 @@ impl CodexMessageProcessor {
19681982 ..Default :: default ( )
19691983 } ;
19701984
1971- derive_config_from_params ( overrides, cli_overrides) . await
1985+ derive_config_from_params ( overrides, Some ( cli_overrides) ) . await
19721986 }
19731987 None => Ok ( self . config . as_ref ( ) . clone ( ) ) ,
19741988 } ;
@@ -1983,6 +1997,10 @@ impl CodexMessageProcessor {
19831997 return ;
19841998 }
19851999 } ;
2000+ if cfg ! ( windows) && config. features . enabled ( Feature :: WindowsSandbox ) {
2001+ self . handle_windows_world_writable_warning ( config. cwd . clone ( ) )
2002+ . await ;
2003+ }
19862004
19872005 let conversation_history = if let Some ( path) = path {
19882006 match RolloutRecorder :: get_rollout_history ( & path) . await {
@@ -2841,6 +2859,53 @@ impl CodexMessageProcessor {
28412859 Err ( _) => None ,
28422860 }
28432861 }
2862+
2863+ /// On Windows, when using the experimental sandbox, we need to warn the user about world-writable directories.
2864+ async fn handle_windows_world_writable_warning ( & self , cwd : PathBuf ) {
2865+ if !cfg ! ( windows) {
2866+ return ;
2867+ }
2868+
2869+ if !self . config . features . enabled ( Feature :: WindowsSandbox ) {
2870+ return ;
2871+ }
2872+
2873+ if !matches ! (
2874+ self . config. sandbox_policy,
2875+ codex_protocol:: protocol:: SandboxPolicy :: WorkspaceWrite { .. }
2876+ | codex_protocol:: protocol:: SandboxPolicy :: ReadOnly
2877+ ) {
2878+ return ;
2879+ }
2880+
2881+ if self
2882+ . config
2883+ . notices
2884+ . hide_world_writable_warning
2885+ . unwrap_or ( false )
2886+ {
2887+ return ;
2888+ }
2889+
2890+ // This function is stubbed out to return None on non-Windows platforms
2891+ if let Some ( ( sample_paths, extra_count, failed_scan) ) =
2892+ codex_windows_sandbox:: world_writable_warning_details (
2893+ self . config . codex_home . as_path ( ) ,
2894+ cwd,
2895+ )
2896+ {
2897+ tracing:: warn!( "world writable warning: {sample_paths:?} {extra_count} {failed_scan}" ) ;
2898+ self . outgoing
2899+ . send_server_notification ( ServerNotification :: WindowsWorldWritableWarning (
2900+ WindowsWorldWritableWarningNotification {
2901+ sample_paths,
2902+ extra_count,
2903+ failed_scan,
2904+ } ,
2905+ ) )
2906+ . await ;
2907+ }
2908+ }
28442909}
28452910
28462911async fn derive_config_from_params (
0 commit comments