Codex Handbook
core/src/windows_sandbox.rs 435 lines
use crate::config::Config;use crate::config::edit::ConfigEditsBuilder;use codex_config::config_toml::ConfigToml;use codex_config::types::WindowsSandboxModeToml;use codex_features::Feature;use codex_features::Features;use codex_features::FeaturesToml;use codex_login::default_client::originator;use codex_otel::sanitize_metric_tag_value;use codex_protocol::config_types::WindowsSandboxLevel;use codex_protocol::models::PermissionProfile;use codex_utils_absolute_path::AbsolutePathBuf;use std::collections::BTreeMap;use std::collections::HashMap;use std::path::Path;use std::path::PathBuf;use std::time::Instant;/// Kill switch for the elevated sandbox NUX on Windows.////// When false, revert to the previous sandbox NUX, which only/// prompts users to enable the legacy sandbox feature.pub const ELEVATED_SANDBOX_NUX_ENABLED: bool = true;pub trait WindowsSandboxLevelExt {    fn from_config(config: &Config) -> WindowsSandboxLevel;    fn from_features(features: &Features) -> WindowsSandboxLevel;}impl WindowsSandboxLevelExt for WindowsSandboxLevel {    fn from_config(config: &Config) -> WindowsSandboxLevel {        match config.permissions.windows_sandbox_mode {            Some(WindowsSandboxModeToml::Elevated) => WindowsSandboxLevel::Elevated,            Some(WindowsSandboxModeToml::Unelevated) => WindowsSandboxLevel::RestrictedToken,            None => Self::from_features(&config.features),        }    }    fn from_features(features: &Features) -> WindowsSandboxLevel {        if features.enabled(Feature::WindowsSandboxElevated) {            return WindowsSandboxLevel::Elevated;        }        if features.enabled(Feature::WindowsSandbox) {            WindowsSandboxLevel::RestrictedToken        } else {            WindowsSandboxLevel::Disabled        }    }}pub fn windows_sandbox_level_from_config(config: &Config) -> WindowsSandboxLevel {    WindowsSandboxLevel::from_config(config)}pub fn windows_sandbox_level_from_features(features: &Features) -> WindowsSandboxLevel {    WindowsSandboxLevel::from_features(features)}pub fn resolve_windows_sandbox_mode(cfg: &ConfigToml) -> Option<WindowsSandboxModeToml> {    cfg.windows        .as_ref()        .and_then(|windows| windows.sandbox)        .or_else(|| legacy_windows_sandbox_mode(cfg.features.as_ref()))}pub fn resolve_windows_sandbox_private_desktop(cfg: &ConfigToml) -> bool {    cfg.windows        .as_ref()        .and_then(|windows| windows.sandbox_private_desktop)        .unwrap_or(true)}pub fn legacy_windows_sandbox_mode(    features: Option<&FeaturesToml>,) -> Option<WindowsSandboxModeToml> {    let entries = features.map(FeaturesToml::entries)?;    legacy_windows_sandbox_mode_from_entries(&entries)}pub fn legacy_windows_sandbox_mode_from_entries(    entries: &BTreeMap<String, bool>,) -> Option<WindowsSandboxModeToml> {    if entries        .get(Feature::WindowsSandboxElevated.key())        .copied()        .unwrap_or(false)    {        return Some(WindowsSandboxModeToml::Elevated);    }    if entries        .get(Feature::WindowsSandbox.key())        .copied()        .unwrap_or(false)        || entries            .get("enable_experimental_windows_sandbox")            .copied()            .unwrap_or(false)    {        Some(WindowsSandboxModeToml::Unelevated)    } else {        None    }}#[cfg(target_os = "windows")]pub fn sandbox_setup_is_complete(codex_home: &Path) -> bool {    codex_windows_sandbox::sandbox_setup_is_complete(codex_home)}#[cfg(not(target_os = "windows"))]pub fn sandbox_setup_is_complete(_codex_home: &Path) -> bool {    false}#[cfg(target_os = "windows")]pub fn elevated_setup_failure_details(err: &anyhow::Error) -> Option<(String, String)> {    let failure = codex_windows_sandbox::extract_setup_failure(err)?;    let code = failure.code.as_str().to_string();    let message = codex_windows_sandbox::sanitize_setup_metric_tag_value(&failure.message);    Some((code, message))}#[cfg(not(target_os = "windows"))]pub fn elevated_setup_failure_details(_err: &anyhow::Error) -> Option<(String, String)> {    None}#[cfg(target_os = "windows")]pub fn elevated_setup_failure_metric_name(err: &anyhow::Error) -> &'static str {    if codex_windows_sandbox::extract_setup_failure(err).is_some_and(|failure| {        matches!(            failure.code,            codex_windows_sandbox::SetupErrorCode::OrchestratorHelperLaunchCanceled        )    }) {        "codex.windows_sandbox.elevated_setup_canceled"    } else {        "codex.windows_sandbox.elevated_setup_failure"    }}#[cfg(not(target_os = "windows"))]pub fn elevated_setup_failure_metric_name(_err: &anyhow::Error) -> &'static str {    panic!("elevated_setup_failure_metric_name is only supported on Windows")}#[cfg(target_os = "windows")]pub fn run_elevated_setup(    permission_profile: &PermissionProfile,    workspace_roots: &[AbsolutePathBuf],    command_cwd: &Path,    env_map: &HashMap<String, String>,    codex_home: &Path,) -> anyhow::Result<()> {    let permissions =        codex_windows_sandbox::ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_workspace_roots(            permission_profile,            workspace_roots,        )?;    codex_windows_sandbox::run_elevated_setup(        codex_windows_sandbox::SandboxSetupRequest {            permissions: &permissions,            command_cwd,            env_map,            codex_home,            proxy_enforced: false,        },        codex_windows_sandbox::SetupRootOverrides::default(),    )}#[cfg(target_os = "windows")]pub fn run_elevated_provisioning_setup(codex_home: &Path, real_user: &str) -> anyhow::Result<()> {    codex_windows_sandbox::run_elevated_provisioning_setup(codex_home, real_user)}#[cfg(not(target_os = "windows"))]pub fn run_elevated_setup(    _permission_profile: &PermissionProfile,    _workspace_roots: &[AbsolutePathBuf],    _command_cwd: &Path,    _env_map: &HashMap<String, String>,    _codex_home: &Path,) -> anyhow::Result<()> {    anyhow::bail!("elevated Windows sandbox setup is only supported on Windows")}#[cfg(not(target_os = "windows"))]pub fn run_elevated_provisioning_setup(_codex_home: &Path, _real_user: &str) -> anyhow::Result<()> {    anyhow::bail!("elevated Windows sandbox setup is only supported on Windows")}#[cfg(target_os = "windows")]pub fn run_legacy_setup_preflight(    permission_profile: &PermissionProfile,    workspace_roots: &[AbsolutePathBuf],    command_cwd: &Path,    env_map: &HashMap<String, String>,    codex_home: &Path,) -> anyhow::Result<()> {    codex_windows_sandbox::run_windows_sandbox_legacy_preflight(        permission_profile,        workspace_roots,        codex_home,        command_cwd,        env_map,    )}#[cfg(target_os = "windows")]pub fn run_setup_refresh_with_extra_read_roots(    permission_profile: &PermissionProfile,    workspace_roots: &[AbsolutePathBuf],    command_cwd: &Path,    env_map: &HashMap<String, String>,    codex_home: &Path,    extra_read_roots: Vec<PathBuf>,) -> anyhow::Result<()> {    codex_windows_sandbox::run_setup_refresh_with_extra_read_roots(        permission_profile,        workspace_roots,        command_cwd,        env_map,        codex_home,        extra_read_roots,        /*proxy_enforced*/ false,    )}#[cfg(not(target_os = "windows"))]pub fn run_legacy_setup_preflight(    _permission_profile: &PermissionProfile,    _workspace_roots: &[AbsolutePathBuf],    _command_cwd: &Path,    _env_map: &HashMap<String, String>,    _codex_home: &Path,) -> anyhow::Result<()> {    anyhow::bail!("legacy Windows sandbox setup is only supported on Windows")}#[cfg(not(target_os = "windows"))]pub fn run_setup_refresh_with_extra_read_roots(    _permission_profile: &PermissionProfile,    _workspace_roots: &[AbsolutePathBuf],    _command_cwd: &Path,    _env_map: &HashMap<String, String>,    _codex_home: &Path,    _extra_read_roots: Vec<PathBuf>,) -> anyhow::Result<()> {    anyhow::bail!("Windows sandbox read-root refresh is only supported on Windows")}#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum WindowsSandboxSetupMode {    Elevated,    Unelevated,}#[derive(Debug, Clone)]pub struct WindowsSandboxSetupRequest {    pub mode: WindowsSandboxSetupMode,    pub permission_profile: PermissionProfile,    pub workspace_roots: Vec<AbsolutePathBuf>,    pub command_cwd: PathBuf,    pub env_map: HashMap<String, String>,    pub codex_home: PathBuf,}pub async fn run_windows_sandbox_setup(request: WindowsSandboxSetupRequest) -> anyhow::Result<()> {    let start = Instant::now();    let mode = request.mode;    let originator_tag = sanitize_metric_tag_value(originator().value.as_str());    let result = run_windows_sandbox_setup_and_persist(request).await;    match result {        Ok(()) => {            emit_windows_sandbox_setup_success_metrics(                mode,                originator_tag.as_str(),                start.elapsed(),            );            Ok(())        }        Err(err) => {            emit_windows_sandbox_setup_failure_metrics(                mode,                originator_tag.as_str(),                start.elapsed(),                &err,            );            Err(err)        }    }}async fn run_windows_sandbox_setup_and_persist(    request: WindowsSandboxSetupRequest,) -> anyhow::Result<()> {    let mode = request.mode;    let permission_profile = request.permission_profile;    let workspace_roots = request.workspace_roots;    let command_cwd = request.command_cwd;    let env_map = request.env_map;    let codex_home = request.codex_home;    let setup_codex_home = codex_home.clone();    let setup_result = tokio::task::spawn_blocking(move || -> anyhow::Result<()> {        match mode {            WindowsSandboxSetupMode::Elevated => {                if !sandbox_setup_is_complete(setup_codex_home.as_path()) {                    run_elevated_setup(                        &permission_profile,                        workspace_roots.as_slice(),                        command_cwd.as_path(),                        &env_map,                        setup_codex_home.as_path(),                    )?;                }            }            WindowsSandboxSetupMode::Unelevated => {                run_legacy_setup_preflight(                    &permission_profile,                    workspace_roots.as_slice(),                    command_cwd.as_path(),                    &env_map,                    setup_codex_home.as_path(),                )?;            }        }        Ok(())    })    .await    .map_err(|join_err| anyhow::anyhow!("windows sandbox setup task failed: {join_err}"))?;    setup_result?;    ConfigEditsBuilder::new(codex_home.as_path())        .set_windows_sandbox_mode(windows_sandbox_setup_mode_tag(mode))        .clear_legacy_windows_sandbox_keys()        .apply()        .await        .map_err(|err| anyhow::anyhow!("failed to persist windows sandbox mode: {err}"))}fn emit_windows_sandbox_setup_success_metrics(    mode: WindowsSandboxSetupMode,    originator_tag: &str,    duration: std::time::Duration,) {    let Some(metrics) = codex_otel::global() else {        return;    };    let mode_tag = windows_sandbox_setup_mode_tag(mode);    let _ = metrics.record_duration(        "codex.windows_sandbox.setup_duration_ms",        duration,        &[            ("result", "success"),            ("originator", originator_tag),            ("mode", mode_tag),        ],    );    let _ = metrics.counter(        "codex.windows_sandbox.setup_success",        /*inc*/ 1,        &[("originator", originator_tag), ("mode", mode_tag)],    );}fn emit_windows_sandbox_setup_failure_metrics(    mode: WindowsSandboxSetupMode,    originator_tag: &str,    duration: std::time::Duration,    _err: &anyhow::Error,) {    let Some(metrics) = codex_otel::global() else {        return;    };    let mode_tag = windows_sandbox_setup_mode_tag(mode);    let _ = metrics.record_duration(        "codex.windows_sandbox.setup_duration_ms",        duration,        &[            ("result", "failure"),            ("originator", originator_tag),            ("mode", mode_tag),        ],    );    let _ = metrics.counter(        "codex.windows_sandbox.setup_failure",        /*inc*/ 1,        &[("originator", originator_tag), ("mode", mode_tag)],    );    if matches!(mode, WindowsSandboxSetupMode::Elevated) {        #[cfg(target_os = "windows")]        {            let mut failure_tags: Vec<(&str, &str)> = vec![("originator", originator_tag)];            let mut code_tag: Option<String> = None;            let mut message_tag: Option<String> = None;            if let Some((code, message)) = elevated_setup_failure_details(_err) {                code_tag = Some(code);                message_tag = Some(message);            }            if let Some(code) = code_tag.as_deref() {                failure_tags.push(("code", code));            }            if let Some(message) = message_tag.as_deref() {                failure_tags.push(("message", message));            }            let _ = metrics.counter(                elevated_setup_failure_metric_name(_err),                /*inc*/ 1,                &failure_tags,            );        }    } else {        let _ = metrics.counter(            "codex.windows_sandbox.legacy_setup_preflight_failed",            /*inc*/ 1,            &[("originator", originator_tag)],        );    }}fn windows_sandbox_setup_mode_tag(mode: WindowsSandboxSetupMode) -> &'static str {    match mode {        WindowsSandboxSetupMode::Elevated => "elevated",        WindowsSandboxSetupMode::Unelevated => "unelevated",    }}#[cfg(test)]#[path = "windows_sandbox_tests.rs"]mod tests;