mirror of
https://github.com/openai/codex.git
synced 2026-09-16 12:13:30 +00:00
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
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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<Instant>,
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 { .. }
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<AppEvent>) {
|
||||
let (app_event_tx, app_event_rx) = unbounded_channel();
|
||||
(
|
||||
|
||||
@@ -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<String>,
|
||||
session_telemetry: SessionTelemetry,
|
||||
session_header: SessionHeader,
|
||||
initial_user_message: Option<UserMessage>,
|
||||
pub(crate) initial_user_message: Option<UserMessage>,
|
||||
status_account_display: Option<StatusAccountDisplay>,
|
||||
pub(crate) remote_connection: Option<RemoteConnectionStatus>,
|
||||
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<TokenUsageInfo>,
|
||||
token_usage_pending: bool,
|
||||
// Status and polling use account usage reads; response streams may identify meters differently.
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user