Skip to content

WindowsSandbox架构

从统一 spawn 请求到 legacy token 与 elevated runner,解释 Windows 沙箱的权限快照、ACL、网络身份、IPC 和进程生命周期。

基于rust-v0.150.0
CodexRustSecurityWindows

WindowsSandbox架构 ​

Windows 沙箱的核心不是“创建一个 restricted token”。一次命令执行先携带完整的 PermissionProfile、workspace roots、网络代理状态、TTY/stdio 和取消参数,进入 executor-native 的统一 spawn 接口;随后由 Windows backend 根据 WindowsSandboxLevel 选择 unelevated restricted-token 或 elevated command-runner。两条路径共享同一份权限快照,却在“谁建立 ACL、谁创建进程、谁持有生命周期句柄”上有明确分工。

本文不把 Windows-only 行为伪装成当前主机实测。源码和测试能够证明请求字段、backend 选择、权限可表达性检查、ACL/SID 组装、elevated IPC 帧和 Job Object 的控制流;UAC、ACL、firewall、ConPTY 和 Windows namespace 的系统效果仍需 Windows target 执行。

阅读前可先查看跨平台Sandbox抽象了解 SandboxType 与 executor owner,再查看权限审批沙箱三层模型理解 permission profile 如何进入单次执行请求。

1. 配置解析到等级 ​

Core 同时支持显式配置和历史 feature key。显式 windows.sandbox 优先;没有显式值时,WindowsSandboxElevated 优先于 WindowsSandbox,最终映射为 Elevated、RestrictedToken 或 Disabled。private desktop 则是独立配置,默认开启。

源码位置:codex-rs/core/src/windows_sandbox.rs :: WindowsSandboxLevelExt::from_config、WindowsSandboxLevelExt::from_features

rust
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
        }
    }
}

源码位置:codex-rs/core/src/windows_sandbox.rs :: resolve_windows_sandbox_mode、resolve_windows_sandbox_private_desktop

rust
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)
}

这一步只决定“请求使用什么等级”,并不创建 token 或 ACL。真正的执行约束在后续 PermissionProfile 解析和 executor spawn 阶段建立。

2. 权限快照与边界 ​

Windows backend 先把用户层 PermissionProfile 解析成 ResolvedWindowsSandboxPermissions。只有 managed、restricted filesystem profile 能进入 Windows sandbox;symbolic :workspace_roots 会在解析时绑定调用方传入的 roots。token mode 进一步区分“只读 capability”与“按 writable roots 分配 capability SID”。

源码位置:codex-rs/windows-sandbox-rs/src/resolved_permissions.rs :: ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_workspace_roots、token_mode_for_permission_profile

rust
pub fn token_mode_for_permission_profile(
    permission_profile: &PermissionProfile,
    workspace_roots: &[AbsolutePathBuf],
    cwd: &Path,
    env_map: &HashMap<String, String>,
) -> Result<WindowsSandboxTokenMode> {
    let permissions =
        ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_workspace_roots(
            permission_profile,
            workspace_roots,
        )?;
    if permissions.file_system.has_full_disk_write_access() {
        anyhow::bail!(
            "permission profile requests full-disk filesystem writes, which cannot be enforced by the Windows sandbox"
        );
    }
    if permissions.writable_roots_for_cwd(cwd, env_map).is_empty() {
        Ok(WindowsSandboxTokenMode::ReadOnlyCapability)
    } else {
        Ok(WindowsSandboxTokenMode::WritableRootsCapability)
    }
}

impl ResolvedWindowsSandboxPermissions {
    pub fn try_from_permission_profile_for_workspace_roots(
        permission_profile: &PermissionProfile,
        workspace_roots: &[AbsolutePathBuf],
    ) -> Result<Self> {
        let mut permissions = Self::try_from_permission_profile(permission_profile)?;
        permissions.file_system = permissions
            .file_system
            .materialize_project_roots_with_workspace_roots(workspace_roots);
        Ok(permissions)
    }
}

Windows 的限制不是抽象上的“全部或无”:unelevated token 能处理某些 writable-root 投影,却不能让 capability SID 的 deny-read ACE 参与读检查;split read restriction、deny-read 和某些重开的 writable descendant 必须交给 elevated override。sandboxing/src/windows.rs 因此在启动前比较 legacy projection 与 split policy,无法表达时返回错误并拒绝无沙箱运行。

源码位置:codex-rs/sandboxing/src/windows.rs :: resolve_windows_restricted_token_filesystem_overrides

rust
if !windows_policy_has_root_read_access(&file_system_sandbox_policy, sandbox_policy_cwd) {
    return Err(
        "windows unelevated restricted-token sandbox cannot enforce split filesystem read restrictions directly; refusing to run unsandboxed"
            .to_string(),
    );
}

let additional_deny_read_paths = codex_windows_sandbox::resolve_windows_deny_read_paths(
    &file_system_sandbox_policy,
    sandbox_policy_cwd,
)?;
if !additional_deny_read_paths.is_empty() {
    return Err(
        "windows unelevated restricted-token sandbox cannot enforce deny-read restrictions directly; refusing to run unsandboxed"
            .to_string(),
    );
}

3. 统一spawn入口 ​

SandboxType::WindowsRestrictedToken 不再由不同调用方各自拼装参数。sandboxing::spawn_process 把权限快照、workspace roots、proxy enforcing、restricting SID、filesystem overrides、TTY 和 stdin 组装为 WindowsSandboxSessionRequest,再调用 codex-windows-sandbox。非 Windows 编译目标保留明确错误 stub,而不是模拟成功。

源码位置:codex-rs/sandboxing/src/spawn.rs :: WindowsSandboxSpawnRequest、spawn_process

rust
pub struct WindowsSandboxSpawnRequest<'a> {
    pub permission_profile: &'a PermissionProfile,
    pub workspace_roots: &'a [AbsolutePathBuf],
    pub windows_sandbox_level: WindowsSandboxLevel,
    pub proxy_enforced: bool,
    pub network_proxy_restricting_sid: Option<&'a str>,
    pub proxy_settings_mode: WindowsSandboxProxySettingsMode,
    pub filesystem_overrides: Option<&'a WindowsSandboxFilesystemOverrides>,
    pub use_private_desktop: bool,
}

源码位置:codex-rs/sandboxing/src/spawn.rs :: spawn_process

rust
pub async fn spawn_process(request: SpawnRequest<'_>) -> Result<SpawnedProcess> {
    if request.sandbox == SandboxType::WindowsRestrictedToken {
        #[cfg(target_os = "windows")]
        {
            let windows = request
                .windows_sandbox
                .context("missing Windows sandbox spawn request")?;
            let codex_home = codex_utils_home_dir::find_codex_home()
                .context("windows sandbox: failed to resolve codex_home")?;
            let empty_paths = &[];
            let overrides = windows.filesystem_overrides;

            return codex_windows_sandbox::spawn_windows_sandbox_session_for_level(
                codex_windows_sandbox::WindowsSandboxSessionRequest {
                    permission_profile: windows.permission_profile,
                    workspace_roots: windows.workspace_roots,
                    codex_home: codex_home.as_path(),
                    command: request.command.to_vec(),
                    cwd: request.cwd,
                    env_map: request.env.clone(),
                    windows_sandbox_level: windows.windows_sandbox_level,
                    proxy_enforced: windows.proxy_enforced,
                    network_proxy_restricting_sid: windows
                        .network_proxy_restricting_sid
                        .map(str::to_owned),
                    proxy_settings_mode: windows.proxy_settings_mode,
                    timeout_ms: None,
                    read_roots_override: overrides
                        .and_then(|value| value.read_roots_override.as_deref()),
                    read_roots_include_platform_defaults: overrides
                        .is_some_and(|value| value.read_roots_include_platform_defaults),
                    write_roots_override: overrides
                        .and_then(|value| value.write_roots_override.as_deref()),
                    deny_read_paths_override: overrides.map_or(empty_paths, |value| {
                        value.additional_deny_read_paths.as_slice()
                    }),
                    deny_write_paths_override: overrides.map_or(empty_paths, |value| {
                        value.additional_deny_write_paths.as_slice()
                    }),
                    tty: request.tty,
                    stdin_open: request.stdin_open,
                    use_private_desktop: windows.use_private_desktop,
                },
            )
            .await;
        }

        #[cfg(not(target_os = "windows"))]
        anyhow::bail!("Windows sandbox process spawn is unavailable on this platform");
    }
}

这里展示的是 Windows 分支的完整连续实现;函数随后在源码中继续处理其他 sandbox 类型的普通 PTY/pipe spawn。非 Windows 编译目标的 Windows sandbox 分支则明确返回平台不可用错误。

4. Legacy token路径 ​

legacy backend 的前置顺序是:解析权限 → 规范化环境 → 生成 capability roots → 创建 restricted token → 把 allow/deny 规则写入 ACL → 创建进程。只读 profile 使用 readonly SID;workspace-write 使用每个 writable root 的 capability SID。deny-read override 在这条路径上被拒绝,因为 WRITE_RESTRICTED token 不能让 capability SID deny-read ACE 成为读检查的权威来源。

源码位置:codex-rs/windows-sandbox-rs/src/spawn_prep.rs :: prepare_legacy_session_security

rust
pub(crate) fn prepare_legacy_session_security(
    uses_write_capabilities: bool,
    codex_home: &Path,
    cwd: &Path,
    capability_roots: impl IntoIterator<Item = PathBuf>,
) -> Result<LegacySessionSecurity> {
    let caps = load_or_create_cap_sids(codex_home)?;
    let (h_token, readonly_sid, readonly_sid_str, write_root_sids) = unsafe {
        if uses_write_capabilities {
            let write_root_sids = root_capability_sids(codex_home, cwd, capability_roots)?;
            if write_root_sids.is_empty() {
                anyhow::bail!("workspace-write sandbox has no writable root capability SIDs");
            }
            let base = get_current_token_for_restriction()?;
            let cap_ptrs: Vec<*mut c_void> = write_root_sids
                .iter()
                .map(|root| root.sid.as_ptr())
                .collect();
            let h_token = create_workspace_write_token_with_caps_from(base, cap_ptrs.as_slice());
            CloseHandle(base);
            let h_token = h_token?;
            (h_token, None, None, write_root_sids)
        } else {
            let psid = LocalSid::from_string(&caps.readonly)?;
            let (h_token, _psid) = create_readonly_token_with_cap(psid.as_ptr())?;
            (h_token, Some(psid), Some(caps.readonly), Vec::new())
        }
    };

    Ok(LegacySessionSecurity {
        h_token,
        readonly_sid,
        readonly_sid_str,
        write_root_sids,
    })
}

源码位置:codex-rs/windows-sandbox-rs/src/unified_exec/backends/legacy.rs :: spawn_windows_sandbox_session_legacy

rust
let common = prepare_legacy_spawn_context(
    permission_profile,
    workspace_roots,
    codex_home,
    cwd,
    &mut env_map,
    &command,
    SpawnPrepOptions {
        inherit_path: false,
        add_git_safe_directory: false,
    },
)?;
if !common.permissions.has_full_disk_read_access() {
    anyhow::bail!("Restricted read-only access requires the elevated Windows sandbox backend");
}
if !additional_deny_read_paths.is_empty() {
    anyhow::bail!("deny-read overrides require the elevated Windows sandbox backend");
}
let capability_roots = legacy_session_capability_roots(
    &common.permissions,
    &common.current_dir,
    &env_map,
    codex_home,
);
let security = prepare_legacy_session_security(
    common.uses_write_capabilities,
    codex_home,
    cwd,
    capability_roots,
)?;

后续 apply_legacy_session_acl_rules 会把 allow roots、deny-write carveouts、persistent deny-read(仅在可用 SID 语义下)和 .codex/.agents 保护写入 ACL,然后才调用 token spawn。失败发生在这条路径时会返回错误,不会调用普通未沙箱 spawn。

5. Job Object进程树 ​

legacy backend 的 TTY 分支通过 ConPTY 创建进程,非 TTY 分支通过 pipes 创建进程;两者都要求返回 Job Object。ProcessDriver 的 terminator 终止 job,等待线程在超时或取消时优先杀整个进程树,只有 Job API 失败才退回 TerminateProcess 杀根进程。

源码位置:codex-rs/windows-sandbox-rs/src/unified_exec/backends/legacy.rs :: spawn_legacy_process、terminate_job_or_process

rust
fn terminate_job_or_process(
    job: &JobObject,
    process_handle: &Arc<StdMutex<Option<HANDLE>>>,
    logs_base_dir: Option<&Path>,
) {
    if let Err(job_err) = job.terminate() {
        log_note(
            &format!("legacy spawn failed to terminate process tree: {job_err}"),
            logs_base_dir,
        );
        if let Ok(guard) = process_handle.lock()
            && let Some(handle) = guard.as_ref()
            && unsafe { TerminateProcess(*handle, 1) } == 0
        {
            log_note(
                &format!(
                    "legacy spawn failed to terminate root process: {}",
                    unsafe { GetLastError() }
                ),
                logs_base_dir,
            );
        }
    }
}

源码位置:codex-rs/utils/pty/src/win/job.rs :: JobObject::create、JobObject::terminate

rust
pub fn create() -> io::Result<Self> {
    let handle = unsafe { CreateJobObjectW(std::ptr::null_mut(), std::ptr::null()) };
    if handle.is_null() {
        return Err(io::Error::last_os_error());
    }
    let handle = unsafe { OwnedHandle::from_raw_handle(handle.cast()) };

    Self::set_limit_flags(
        &handle,
        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK,
    )?;

    Ok(Self {
        handle,
        preserve_descendants: Mutex::new(false),
    })
}

pub fn terminate(&self) -> io::Result<()> {
    let preserve_descendants = self
        .preserve_descendants
        .lock()
        .map_err(|_| io::Error::other("job state lock poisoned"))?;
    if *preserve_descendants {
        return Ok(());
    }

    let terminated = unsafe {
        TerminateJobObject(self.handle.as_raw_handle().cast(), /*uExitCode*/ 1)
    };
    if terminated == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

Job Object 的 KILL_ON_JOB_CLOSE 还提供句柄关闭后的兜底回收;preserve_descendants 则用于根进程先退出、但 session 仍需保留子孙的场景。这个细节解释了为什么 Windows sandbox 的生命周期不能只用一个 PID 表示。

6. Elevated setup ​

elevated backend 不把 ACL 操作塞进父进程的 token。它先生成或刷新 sandbox credentials,再把 resolved roots、deny paths、proxy ports、offline/online 用户、cwd 和 setup mode 编码成 ElevationPayload。setup refresh 使用 singleflight:相同 payload 的并发调用共享一次 helper 执行和结果。

源码位置:codex-rs/windows-sandbox-rs/src/setup.rs :: run_setup_singleflight

rust
fn run_setup_singleflight(key: String, run: impl FnOnce() -> Result<()>) -> Result<()> {
    let flights = SETUP_FLIGHTS.get_or_init(|| Mutex::new(HashMap::new()));
    let (flight, is_leader) = {
        let mut flights = flights
            .lock()
            .unwrap_or_else(std::sync::PoisonError::into_inner);
        match flights.get(&key) {
            Some(flight) => (Arc::clone(flight), false),
            None => {
                let flight = Arc::new(SetupFlight::pending());
                flights.insert(key.clone(), Arc::clone(&flight));
                (flight, true)
            }
        }
    };

    if !is_leader {
        return flight.wait();
    }

    let result = run();
    let shared_result = match &result {
        Ok(()) => Ok(()),
        Err(error) => Err(SharedSetupError::from_error(error)),
    };
    flight.complete(shared_result);
    let mut flights = flights
        .lock()
        .unwrap_or_else(std::sync::PoisonError::into_inner);
    if flights
        .get(&key)
        .is_some_and(|current| Arc::ptr_eq(current, &flight))
    {
        flights.remove(&key);
    }
    result
}

源码位置:codex-rs/windows-sandbox-rs/src/setup.rs :: run_setup_refresh_inner

rust
fn run_setup_refresh_inner(
    request: SandboxSetupRequest<'_>,
    overrides: SetupRootOverrides,
    offline_proxy_settings_override: Option<&OfflineProxySettings>,
) -> Result<()> {
    if !request.permissions.is_enforceable_by_windows_sandbox() {
        anyhow::bail!("unsupported filesystem permissions for Windows sandbox setup");
    }
    let (read_roots, write_roots) = build_payload_roots(&request, &overrides);
    let deny_read_paths = build_payload_deny_read_paths(overrides.deny_read_paths);
    let deny_write_paths = build_payload_deny_write_paths(&request, overrides.deny_write_paths);
    let offline_proxy_settings =
        offline_proxy_settings_for_request(&request, offline_proxy_settings_override);
    let payload = ElevationPayload {
        version: SETUP_VERSION,
        offline_username: OFFLINE_USERNAME.to_string(),
        online_username: ONLINE_USERNAME.to_string(),
        codex_home: request.codex_home.to_path_buf(),
        command_cwd: request.command_cwd.to_path_buf(),
        read_roots,
        write_roots,
        deny_read_paths,
        deny_write_paths,
        proxy_ports: offline_proxy_settings.proxy_ports,
        allow_local_binding: offline_proxy_settings.allow_local_binding,
        otel: None,
        real_user: std::env::var("USERNAME").unwrap_or_else(|_| "Administrators".to_string()),
        mode: SetupMode::Full,
        refresh_only: true,
    };
    let json = serde_json::to_vec(&payload)?;
    let b64 = BASE64_STANDARD.encode(json);
    run_setup_singleflight(b64.clone(), || {
        run_setup_refresh_payload(&b64, request.codex_home)
    })
}

refresh_only: true 的含义是刷新 ACL/配置,不请求 UAC elevation;真正需要 elevated command runner 时,后续 credentials 和 runner pipe 再承担进程创建。

7. Elevated runner ​

elevated backend 将 SpawnRequest 发给 command runner。请求包含命令、cwd、环境、原始 PermissionProfile、workspace roots、sandbox home、capability SIDs、可选的 network restricting SID、超时、TTY 和 private desktop。父进程只在收到 SpawnReady 后把 pipe 转换为统一 ProcessDriver。

源码位置:codex-rs/windows-sandbox-rs/src/elevated/ipc_framed.rs :: Message、SpawnRequest

rust
pub enum Message {
    SpawnRequest { payload: Box<SpawnRequest> },
    SpawnReady { payload: SpawnReady },
    Output { payload: OutputPayload },
    Stdin { payload: StdinPayload },
    CloseStdin { payload: EmptyPayload },
    Resize { payload: ResizePayload },
    Exit { payload: ExitPayload },
    Error { payload: ErrorPayload },
    Terminate { payload: EmptyPayload },
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SpawnRequest {
    pub command: Vec<String>,
    pub cwd: PathBuf,
    pub env: HashMap<String, String>,
    pub permission_profile: PermissionProfile,
    pub workspace_roots: Vec<AbsolutePathBuf>,
    pub codex_home: PathBuf,
    pub real_codex_home: PathBuf,
    pub cap_sids: Vec<String>,
    #[serde(default)]
    pub network_proxy_restricting_sid: Option<String>,
    pub timeout_ms: Option<u64>,
    pub tty: bool,
    #[serde(default)]
    pub stdin_open: bool,
    #[serde(default)]
    pub use_private_desktop: bool,
}

源码位置:codex-rs/windows-sandbox-rs/src/elevated/runner_client.rs :: RunnerTransport::send_spawn_request、RunnerTransport::read_spawn_ready

rust
pub(crate) fn send_spawn_request(&mut self, request: SpawnRequest) -> Result<()> {
    let spawn_request = FramedMessage {
        version: IPC_PROTOCOL_VERSION,
        message: Message::SpawnRequest {
            payload: Box::new(request),
        },
    };
    write_frame(&mut self.pipe_write, &spawn_request)
}

pub(crate) fn read_spawn_ready(&mut self) -> Result<()> {
    wait_for_complete_frame(&self.pipe_read, RUNNER_SPAWN_READY_TIMEOUT)?;
    let msg = read_frame(&mut self.pipe_read)?
        .ok_or_else(|| anyhow::anyhow!("runner pipe closed before spawn_ready"))?;
    match msg.message {
        Message::SpawnReady { .. } => Ok(()),
        Message::Error { payload } => Err(RunnerStartupError::new(payload).into()),
        other => Err(anyhow::anyhow!(
            "expected spawn_ready from runner, got {other:?}"
        )),
    }
}

帧协议把错误阶段区分为 ReadSpawnRequest、SpawnChild 和 WriteSpawnReady,因此父进程可以知道失败发生在 runner 读请求、创建子进程还是回写确认,而不是把所有错误归为“sandbox denied”。

8. 凭据刷新重试 ​

elevated runner 启动失败不等于任意失败都可重试。retry_runner_spawn_once 只在 logon failure、no-such-logon-session,或 runner 的 SpawnChild 阶段出现可刷新错误码时刷新 sandbox credentials;WindowsApps 命令的特定错误不会因轮换密码而改善。刷新后使用原始统一 spawn request 再尝试一次。

源码位置:codex-rs/windows-sandbox-rs/src/elevated/runner_client.rs :: is_refreshable_sandbox_creds_error、retry_runner_spawn_once

rust
pub(crate) fn retry_runner_spawn_once<T>(
    sandbox_creds: SandboxCreds,
    command: &[String],
    mut spawn: impl FnMut(SandboxCreds) -> Result<T>,
    refresh: impl FnOnce() -> Result<SandboxCreds>,
) -> Result<T> {
    match spawn(sandbox_creds) {
        Ok(result) => Ok(result),
        Err(err) if is_refreshable_sandbox_creds_error(&err, command) => spawn(refresh()?),
        Err(err) => Err(err),
    }
}

这条规则很窄:它只恢复可证明与 sandbox account 生命周期相关的错误,不会把 ACL、命令参数、权限不可表达或用户程序退出错误重新执行。

9. 网络与桌面 ​

managed network 的代理身份通过 network_proxy_restricting_sid 传到 runner,并与 proxy_ports、allow_local_binding 一起参与 setup。unelevated backend 在 session 入口直接拒绝 proxy_enforced 或 restricting SID;否则网络控制所需的 firewall/SID 可能无法建立。private desktop 是独立的 spawn 参数,同时传给 legacy token/ConPTY 和 elevated runner。

源码位置:codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs :: spawn_windows_sandbox_session_for_level

rust
pub async fn spawn_windows_sandbox_session_for_level(
    request: WindowsSandboxSessionRequest<'_>,
) -> Result<SpawnedProcess> {
    if matches!(request.windows_sandbox_level, WindowsSandboxLevel::Elevated) {
        backends::elevated::spawn_windows_sandbox_session_elevated_for_permission_profile(
            request.permission_profile,
            request.workspace_roots,
            request.codex_home,
            request.command,
            request.cwd,
            request.env_map,
            request.proxy_enforced,
            request.network_proxy_restricting_sid,
            request.proxy_settings_mode,
            request.timeout_ms,
            request.read_roots_override,
            request.read_roots_include_platform_defaults,
            request.write_roots_override,
            request.deny_read_paths_override,
            request.deny_write_paths_override,
            request.tty,
            request.stdin_open,
            request.use_private_desktop,
        )
        .await
    } else {
        if request.proxy_enforced {
            bail!("managed networking requires the elevated Windows sandbox backend");
        }
        if request.network_proxy_restricting_sid.is_some() {
            bail!("network proxy restricting SID requires the elevated Windows sandbox backend");
        }
        spawn_windows_sandbox_session_legacy(
            request.permission_profile,
            request.workspace_roots,
            request.codex_home,
            request.command,
            request.cwd,
            request.env_map,
            request.timeout_ms,
            request.deny_read_paths_override,
            request.deny_write_paths_override,
            request.tty,
            request.stdin_open,
            request.use_private_desktop,
        )
        .await
    }
}

10. 测试与证明边界 ​

源码测试把“可在任何 target 检查的决策”和“必须 Windows 执行的系统效果”分开。Core 测试覆盖显式/历史 feature 到等级的映射、private desktop 默认值和代理端口提取;Windows sandbox 测试覆盖 managed network 在 restricted token 下的前置拒绝、deny-read 需要 elevated、runner request 序列化以及 credential refresh 的一次重试;真正的 token、ACL、Job Object、ConPTY 和 helper IPC 运行测试带有 Windows 条件。

源码位置:codex-rs/core/src/windows_sandbox_tests.rs :: elevated_wins_when_both_flags_are_enabled、resolve_windows_sandbox_private_desktop_defaults_to_true

rust
#[test]
fn elevated_wins_when_both_flags_are_enabled() {
    let mut features = Features::with_defaults();
    features.enable(Feature::WindowsSandbox);
    features.enable(Feature::WindowsSandboxElevated);

    assert_eq!(
        WindowsSandboxLevel::from_features(&features),
        WindowsSandboxLevel::Elevated
    );
}

#[test]
fn resolve_windows_sandbox_private_desktop_defaults_to_true() {
    assert!(resolve_windows_sandbox_private_desktop(
        &ConfigToml::default()
    ));
}

源码位置:codex-rs/windows-sandbox-rs/src/unified_exec/tests.rs :: restricted_token_rejects_managed_network_before_spawn

rust
.await
.expect_err("managed networking must fail before spawning an unelevated sandbox");

assert_eq!(
    error.to_string(),
    "managed networking requires the elevated Windows sandbox backend"
);

输入、断言和边界分别是:给定两个启用 feature,等级断言必须是 elevated;给定缺失显式配置,private desktop 断言默认为 true;给定 restricted token + managed network,断言在创建进程前失败。它们能证明选择与拒绝时机,不能证明 Windows 内核实际应用了 token、ACL、firewall 或 Job Object。

在 Windows target 上可进一步运行:

text
cd codex-rs
cargo test -p codex-windows-sandbox --lib
cargo test -p codex-core windows_sandbox

当前非 Windows 主机只能执行不依赖 Windows API 的配置、解析和序列化测试;不能把未运行的系统测试记为通过。

11. 阅读闭环 ​

建议沿着 core/windows_sandbox.rs 的等级解析开始,进入 sandboxing/src/windows.rs 的可表达性检查,再看 sandboxing/src/spawn.rs 如何冻结请求字段。之后分别阅读 legacy 的 token/ACL/Job Object 和 elevated 的 setup/payload/runner IPC,最后回到 Core 的 timeout、cancel、output 收口。这样可以清楚区分三件容易混淆的事:权限快照如何形成、哪个进程真正执行命令、哪个句柄负责把进程树收干净。

下一篇深入 Windows 可读路径授权和 deny-read glob 的具体解析。