Promote Windows Sandbox (#11341)

1. Move Windows Sandbox NUX to right after trust directory screen
2. Don't offer read-only as an option in Sandbox NUX.
Elevated/Legacy/Quit
3. Don't allow new untrusted directories. It's trust or quit
4. move experimental sandbox features to `[windows]
sandbox="elevated|unelevatd"`
5. Copy tweaks = elevated -> default, non-elevated -> non-admin
This commit is contained in:
iceweasel-oai
2026-02-11 11:48:33 -08:00
committed by GitHub
parent 24e6adbda5
commit 87279de434
21 changed files with 727 additions and 395 deletions

View File

@@ -944,6 +944,7 @@ impl App {
session_selection: SessionSelection,
feedback: codex_feedback::CodexFeedback,
is_first_run: bool,
should_prompt_windows_sandbox_nux_at_startup: bool,
) -> Result<AppExitInfo> {
use tokio_stream::StreamExt;
let (app_event_tx, mut app_event_rx) = unbounded_channel();
@@ -1107,7 +1108,8 @@ impl App {
}
};
chat_widget.maybe_prompt_windows_sandbox_enable();
chat_widget
.maybe_prompt_windows_sandbox_enable(should_prompt_windows_sandbox_nux_at_startup);
let file_search = FileSearchManager::new(config.cwd.clone(), app_event_tx.clone());
#[cfg(not(debug_assertions))]
@@ -1788,6 +1790,42 @@ impl App {
let _ = preset;
}
}
AppEvent::BeginWindowsSandboxLegacySetup { preset } => {
#[cfg(target_os = "windows")]
{
let policy = preset.sandbox.clone();
let policy_cwd = self.config.cwd.clone();
let command_cwd = policy_cwd.clone();
let env_map: std::collections::HashMap<String, String> =
std::env::vars().collect();
let codex_home = self.config.codex_home.clone();
let tx = self.app_event_tx.clone();
self.chat_widget.show_windows_sandbox_setup_status();
tokio::task::spawn_blocking(move || {
if let Err(err) = codex_core::windows_sandbox::run_legacy_setup_preflight(
&policy,
policy_cwd.as_path(),
command_cwd.as_path(),
&env_map,
codex_home.as_path(),
) {
tracing::warn!(
error = %err,
"failed to preflight non-admin Windows sandbox setup"
);
}
tx.send(AppEvent::EnableWindowsSandboxForAgentMode {
preset,
mode: WindowsSandboxEnableMode::Legacy,
});
});
}
#[cfg(not(target_os = "windows"))]
{
let _ = preset;
}
}
AppEvent::EnableWindowsSandboxForAgentMode { preset, mode } => {
#[cfg(target_os = "windows")]
{
@@ -1800,33 +1838,26 @@ impl App {
);
}
let profile = self.active_profile.as_deref();
let feature_key = Feature::WindowsSandbox.key();
let elevated_key = Feature::WindowsSandboxElevated.key();
let elevated_enabled = matches!(mode, WindowsSandboxEnableMode::Elevated);
let mut builder =
ConfigEditsBuilder::new(&self.config.codex_home).with_profile(profile);
if elevated_enabled {
builder = builder.set_feature_enabled(elevated_key, true);
} else {
builder = builder
.set_feature_enabled(feature_key, true)
.set_feature_enabled(elevated_key, false);
}
let builder = ConfigEditsBuilder::new(&self.config.codex_home)
.with_profile(profile)
.set_windows_sandbox_mode(if elevated_enabled {
"elevated"
} else {
"unelevated"
})
.clear_legacy_windows_sandbox_keys();
match builder.apply().await {
Ok(()) => {
if elevated_enabled {
self.config.set_windows_sandbox_enabled(false);
self.config.set_windows_elevated_sandbox_enabled(true);
self.chat_widget
.set_feature_enabled(Feature::WindowsSandboxElevated, true);
} else {
self.config.set_windows_sandbox_enabled(true);
self.config.set_windows_elevated_sandbox_enabled(false);
self.chat_widget
.set_feature_enabled(Feature::WindowsSandbox, true);
self.chat_widget
.set_feature_enabled(Feature::WindowsSandboxElevated, false);
}
self.chat_widget.clear_forced_auto_mode_downgrade();
self.chat_widget
.set_windows_sandbox_mode(self.config.windows_sandbox_mode);
let windows_sandbox_level =
WindowsSandboxLevel::from_config(&self.config);
if let Some((sample_paths, extra_count, failed_scan)) =
@@ -1871,17 +1902,15 @@ impl App {
.send(AppEvent::UpdateAskForApprovalPolicy(preset.approval));
self.app_event_tx
.send(AppEvent::UpdateSandboxPolicy(preset.sandbox.clone()));
self.chat_widget.add_info_message(
match mode {
WindowsSandboxEnableMode::Elevated => {
"Enabled elevated agent sandbox.".to_string()
}
WindowsSandboxEnableMode::Legacy => {
"Enabled non-elevated agent sandbox.".to_string()
}
},
None,
);
let _ = mode;
self.chat_widget.add_plain_history_lines(vec![
Line::from(vec!["".dim(), "Sandbox ready".into()]),
Line::from(vec![
" ".into(),
"Codex can now safely edit files and execute commands in your computer"
.dark_gray(),
]),
]);
}
}
Err(err) => {
@@ -1989,21 +2018,17 @@ impl App {
codex_core::protocol::SandboxPolicy::WorkspaceWrite { .. }
| codex_core::protocol::SandboxPolicy::ReadOnly
);
#[cfg(target_os = "windows")]
let policy_for_chat = policy.clone();
if let Err(err) = self.config.sandbox_policy.set(policy.clone()) {
if let Err(err) = self.config.sandbox_policy.set(policy) {
tracing::warn!(%err, "failed to set sandbox policy on app config");
self.chat_widget
.add_error_message(format!("Failed to set sandbox policy: {err}"));
return Ok(AppRunControl::Continue);
}
#[cfg(target_os = "windows")]
if !matches!(&policy, codex_core::protocol::SandboxPolicy::ReadOnly)
|| WindowsSandboxLevel::from_config(&self.config)
!= WindowsSandboxLevel::Disabled
{
self.config.forced_auto_mode_downgraded_on_windows = false;
}
if let Err(err) = self.chat_widget.set_sandbox_policy(policy) {
if let Err(err) = self.chat_widget.set_sandbox_policy(policy_for_chat) {
tracing::warn!(%err, "failed to set sandbox policy on chat config");
self.chat_widget
.add_error_message(format!("Failed to set sandbox policy: {err}"));