mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
Add Windows sandbox diagnostics to codex doctor (#39290)
## What changed - Report the configured Windows sandbox backend and whether denied-read restrictions are active. - Diagnose incompatible backend policy, incomplete or failed elevated sandbox provisioning, unreadable setup failure reports, and missing, locked, disabled, or expired sandbox accounts. - Provide issue-specific remediation and promote the sandbox check status and summary to the highest detected severity. - Export the Windows sandbox setup data needed by the diagnostic check. ## Testing - Cover missing Linux helpers and malformed or oversized Windows setup failure reports. - Cover a recorded Windows sandbox refresh failure after setup completed. GitOrigin-RevId: e965b703578a5c0597dcce9f836d2e1f510ad0c8
This commit is contained in:
@@ -79,6 +79,7 @@ mod network;
|
||||
mod output;
|
||||
mod progress;
|
||||
mod runtime;
|
||||
mod sandbox;
|
||||
mod security;
|
||||
mod system;
|
||||
mod thread_inventory;
|
||||
@@ -100,6 +101,7 @@ use progress::DoctorProgress;
|
||||
use progress::doctor_progress;
|
||||
use runtime::runtime_check;
|
||||
use runtime::search_check;
|
||||
use sandbox::sandbox_check;
|
||||
use system::system_check;
|
||||
use thread_inventory::thread_inventory_check;
|
||||
use title::terminal_title_check;
|
||||
@@ -1698,41 +1700,6 @@ async fn mcp_check_from_servers(servers: &HashMap<String, McpServerConfig>) -> D
|
||||
check
|
||||
}
|
||||
|
||||
fn sandbox_check(config: &Config, arg0_paths: &Arg0DispatchPaths) -> DoctorCheck {
|
||||
let mut details = Vec::new();
|
||||
details.push(format!(
|
||||
"approval policy: {:?}",
|
||||
config.permissions.approval_policy.value()
|
||||
));
|
||||
let file_system_sandbox = config.permissions.file_system_sandbox_policy();
|
||||
details.push(format!("filesystem sandbox: {}", file_system_sandbox.kind));
|
||||
details.push(format!(
|
||||
"network sandbox: {}",
|
||||
config.permissions.network_sandbox_policy()
|
||||
));
|
||||
push_path_detail(
|
||||
&mut details,
|
||||
"codex-linux-sandbox helper",
|
||||
arg0_paths.codex_linux_sandbox_exe.as_deref(),
|
||||
);
|
||||
push_path_detail(
|
||||
&mut details,
|
||||
"execve wrapper helper",
|
||||
arg0_paths.main_execve_wrapper_exe.as_deref(),
|
||||
);
|
||||
|
||||
let mut status = CheckStatus::Ok;
|
||||
let mut summary = "sandbox configuration is readable".to_string();
|
||||
if let Some(helper) = arg0_paths.codex_linux_sandbox_exe.as_deref()
|
||||
&& !helper.exists()
|
||||
{
|
||||
status = CheckStatus::Warning;
|
||||
summary = "Linux sandbox helper path does not exist".to_string();
|
||||
}
|
||||
|
||||
DoctorCheck::new("sandbox.helpers", "sandbox", status, summary).details(details)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct TerminalCheckInputs {
|
||||
info: TerminalInfo,
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::fs;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::io;
|
||||
|
||||
use codex_arg0::Arg0DispatchPaths;
|
||||
use codex_core::config::Config;
|
||||
#[cfg(target_os = "windows")]
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
#[cfg(target_os = "windows")]
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
#[cfg(target_os = "windows")]
|
||||
use codex_sandboxing::windows_sandbox_uses_elevated_backend;
|
||||
#[cfg(target_os = "windows")]
|
||||
use codex_windows_sandbox::SetupErrorCode;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::Foundation::ERROR_ACCESS_DENIED;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::NERR_Success as NERR_SUCCESS;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::NERR_UserNotFound as NERR_USER_NOT_FOUND;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::NetApiBufferFree;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::NetUserGetInfo;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::UF_ACCOUNTDISABLE;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::UF_LOCKOUT;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::UF_PASSWORD_EXPIRED;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::USER_INFO_23;
|
||||
|
||||
use super::CheckStatus;
|
||||
use super::DoctorCheck;
|
||||
#[cfg(target_os = "windows")]
|
||||
use super::DoctorIssue;
|
||||
use super::push_path_detail;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const WINDOWS_SETUP_REMEDIATION: &str = "run codex sandbox setup --elevated --user <end-user> --codex-home <authoritative-home> from an elevated shell";
|
||||
|
||||
pub(super) fn sandbox_check(config: &Config, arg0_paths: &Arg0DispatchPaths) -> DoctorCheck {
|
||||
let mut details = Vec::new();
|
||||
details.push(format!(
|
||||
"approval policy: {:?}",
|
||||
config.permissions.approval_policy.value()
|
||||
));
|
||||
let file_system_sandbox = config.permissions.file_system_sandbox_policy();
|
||||
details.push(format!("filesystem sandbox: {}", file_system_sandbox.kind));
|
||||
details.push(format!(
|
||||
"network sandbox: {}",
|
||||
config.permissions.network_sandbox_policy()
|
||||
));
|
||||
push_path_detail(
|
||||
&mut details,
|
||||
"codex-linux-sandbox helper",
|
||||
arg0_paths.codex_linux_sandbox_exe.as_deref(),
|
||||
);
|
||||
push_path_detail(
|
||||
&mut details,
|
||||
"execve wrapper helper",
|
||||
arg0_paths.main_execve_wrapper_exe.as_deref(),
|
||||
);
|
||||
|
||||
let mut status = CheckStatus::Ok;
|
||||
let mut summary = "sandbox configuration is readable".to_string();
|
||||
if let Some(helper) = arg0_paths.codex_linux_sandbox_exe.as_deref()
|
||||
&& !helper.exists()
|
||||
{
|
||||
status = CheckStatus::Warning;
|
||||
summary = "Linux sandbox helper path does not exist".to_string();
|
||||
}
|
||||
|
||||
let check = DoctorCheck::new("sandbox.helpers", "sandbox", status, summary).details(details);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let mut check = check;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let configured_backend = WindowsSandboxLevel::from_config(config);
|
||||
let elevated = configured_backend != WindowsSandboxLevel::Disabled
|
||||
&& windows_sandbox_uses_elevated_backend(configured_backend);
|
||||
let backend = if elevated {
|
||||
WindowsSandboxLevel::Elevated
|
||||
} else {
|
||||
configured_backend
|
||||
};
|
||||
let denied = !config
|
||||
.permissions
|
||||
.file_system_sandbox_policy()
|
||||
.has_full_disk_read_access();
|
||||
|
||||
check.details.push(format!("sandbox backend: {backend}"));
|
||||
check
|
||||
.details
|
||||
.push(format!("denied-read restrictions: {denied}"));
|
||||
|
||||
if denied && !elevated {
|
||||
check.issues.push(
|
||||
DoctorIssue::new(
|
||||
CheckStatus::Fail,
|
||||
"managed denied-read requirements need the elevated Windows sandbox backend",
|
||||
)
|
||||
.measured(format!("{backend} backend"))
|
||||
.expected("elevated backend")
|
||||
.remedy("enable the elevated Windows sandbox backend permitted by managed policy")
|
||||
.field("sandbox backend")
|
||||
.field("denied-read restrictions"),
|
||||
);
|
||||
}
|
||||
|
||||
if elevated {
|
||||
let home = config.codex_home.as_path();
|
||||
let path = codex_windows_sandbox::setup_error_path(home);
|
||||
let report = match fs::metadata(&path) {
|
||||
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(None),
|
||||
Ok(metadata) if metadata.is_file() && metadata.len() <= 64 * 1024 => {
|
||||
codex_windows_sandbox::read_setup_error_report(home)
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
Ok(metadata) if !metadata.is_file() => Err("not a regular file".to_string()),
|
||||
Ok(_) => Err("larger than 64 KiB".to_string()),
|
||||
Err(error) => Err(error.to_string()),
|
||||
};
|
||||
let report = match report {
|
||||
Ok(report) => report,
|
||||
Err(error) => {
|
||||
check
|
||||
.details
|
||||
.push("setup failure report: unreadable".to_string());
|
||||
check.issues.push(
|
||||
DoctorIssue::new(
|
||||
CheckStatus::Warning,
|
||||
"Windows sandbox setup failure report could not be read",
|
||||
)
|
||||
.measured(error)
|
||||
.expected("readable setup failure report no larger than 64 KiB")
|
||||
.remedy(WINDOWS_SETUP_REMEDIATION)
|
||||
.field("setup failure report"),
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if report.is_none() && codex_windows_sandbox::sandbox_setup_is_complete(home) {
|
||||
check
|
||||
.details
|
||||
.push("sandbox provisioning: complete".to_string());
|
||||
|
||||
for username in [
|
||||
codex_windows_sandbox::OFFLINE_USERNAME,
|
||||
codex_windows_sandbox::ONLINE_USERNAME,
|
||||
] {
|
||||
let username_wide = username.encode_utf16().chain(Some(0)).collect::<Vec<_>>();
|
||||
let mut buffer = std::ptr::null_mut();
|
||||
let status = unsafe {
|
||||
NetUserGetInfo(
|
||||
std::ptr::null(),
|
||||
username_wide.as_ptr(),
|
||||
/*level*/ 23,
|
||||
&mut buffer,
|
||||
)
|
||||
};
|
||||
let flags = if status == NERR_SUCCESS && !buffer.is_null() {
|
||||
Some(unsafe { (*(buffer as *const USER_INFO_23)).usri23_flags })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if !buffer.is_null() {
|
||||
unsafe { NetApiBufferFree(buffer.cast()) };
|
||||
}
|
||||
|
||||
let (severity, cause, remediation) = match (status, flags) {
|
||||
(NERR_USER_NOT_FOUND, _) => (
|
||||
CheckStatus::Fail,
|
||||
"a Windows sandbox account is missing",
|
||||
WINDOWS_SETUP_REMEDIATION,
|
||||
),
|
||||
(NERR_SUCCESS, Some(flags)) if flags & UF_LOCKOUT != 0 => (
|
||||
CheckStatus::Fail,
|
||||
"a Windows sandbox account is locked",
|
||||
"stop sandbox retries and ask IT to unlock the account",
|
||||
),
|
||||
(NERR_SUCCESS, Some(flags)) if flags & UF_ACCOUNTDISABLE != 0 => (
|
||||
CheckStatus::Fail,
|
||||
"a Windows sandbox account is disabled",
|
||||
"ask IT to enable the sandbox account before rerunning setup",
|
||||
),
|
||||
(NERR_SUCCESS, Some(flags)) if flags & UF_PASSWORD_EXPIRED != 0 => (
|
||||
CheckStatus::Fail,
|
||||
"a Windows sandbox account password has expired",
|
||||
WINDOWS_SETUP_REMEDIATION,
|
||||
),
|
||||
(NERR_SUCCESS, Some(_)) => continue,
|
||||
(ERROR_ACCESS_DENIED, _) => (
|
||||
CheckStatus::Warning,
|
||||
"Windows sandbox account status could not be inspected",
|
||||
"ask IT to inspect access to the local sandbox accounts",
|
||||
),
|
||||
_ => (
|
||||
CheckStatus::Warning,
|
||||
"Windows sandbox account status could not be inspected",
|
||||
"ask IT to inspect the local sandbox accounts",
|
||||
),
|
||||
};
|
||||
check.details.push(format!("sandbox account: {username}"));
|
||||
if !matches!(
|
||||
status,
|
||||
NERR_SUCCESS | NERR_USER_NOT_FOUND | ERROR_ACCESS_DENIED
|
||||
) {
|
||||
check
|
||||
.details
|
||||
.push(format!("account query status: {status}"));
|
||||
}
|
||||
check.issues.push(
|
||||
DoctorIssue::new(severity, cause)
|
||||
.measured(username)
|
||||
.expected("enabled, unlocked local sandbox account")
|
||||
.remedy(remediation)
|
||||
.field("sandbox account"),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
check.details.push(if report.is_some() {
|
||||
"sandbox provisioning: failed".to_string()
|
||||
} else {
|
||||
"sandbox provisioning: incomplete".to_string()
|
||||
});
|
||||
if let Some(report) = report {
|
||||
let remediation = match report.code {
|
||||
SetupErrorCode::OrchestratorElevationCheckFailed
|
||||
| SetupErrorCode::OrchestratorElevationRequired
|
||||
| SetupErrorCode::OrchestratorHelperLaunchCanceled => {
|
||||
"use an elevated shell or your organization's approved elevation workflow"
|
||||
}
|
||||
SetupErrorCode::OrchestratorHelperLaunchFailed
|
||||
| SetupErrorCode::OrchestratorHelperExitNonzero
|
||||
| SetupErrorCode::OrchestratorHelperReportReadFailed
|
||||
| SetupErrorCode::OrchestratorHelperIncomplete
|
||||
| SetupErrorCode::HelperReadAclHelperSpawnFailed => {
|
||||
"repair the installed Codex helpers or ask IT to allow their execution"
|
||||
}
|
||||
SetupErrorCode::HelperUserProvisionFailed
|
||||
| SetupErrorCode::HelperUsersGroupCreateFailed
|
||||
| SetupErrorCode::HelperUserCreateOrUpdateFailed
|
||||
| SetupErrorCode::HelperSidResolveFailed
|
||||
| SetupErrorCode::HelperCapabilitySidFailed => {
|
||||
"ask IT to allow the managed local sandbox accounts and group"
|
||||
}
|
||||
SetupErrorCode::OrchestratorSandboxDirCreateFailed
|
||||
| SetupErrorCode::HelperSandboxDirCreateFailed
|
||||
| SetupErrorCode::HelperLogFailed
|
||||
| SetupErrorCode::HelperDpapiProtectFailed
|
||||
| SetupErrorCode::HelperUsersFileWriteFailed
|
||||
| SetupErrorCode::HelperSetupMarkerWriteFailed
|
||||
| SetupErrorCode::HelperSandboxLockFailed => {
|
||||
"rerun elevated setup for the authoritative Codex home or ask IT"
|
||||
}
|
||||
SetupErrorCode::HelperFirewallComInitFailed
|
||||
| SetupErrorCode::HelperFirewallPolicyAccessFailed
|
||||
| SetupErrorCode::HelperFirewallPolicyIneffective
|
||||
| SetupErrorCode::HelperFirewallRuleCreateOrAddFailed
|
||||
| SetupErrorCode::HelperFirewallRuleVerifyFailed => {
|
||||
"ask IT to allow Codex sandbox rules in managed Windows Firewall policy"
|
||||
}
|
||||
SetupErrorCode::OrchestratorPayloadSerializeFailed
|
||||
| SetupErrorCode::HelperRequestArgsFailed
|
||||
| SetupErrorCode::HelperUnknownError => {
|
||||
"repair or reinstall the Codex CLI from an approved distribution"
|
||||
}
|
||||
};
|
||||
check
|
||||
.details
|
||||
.push(format!("error code: {}", report.code.as_str()));
|
||||
check.issues.push(
|
||||
DoctorIssue::new(
|
||||
CheckStatus::Fail,
|
||||
"elevated Windows sandbox provisioning recorded a structured failure",
|
||||
)
|
||||
.measured(report.code.as_str())
|
||||
.remedy(remediation)
|
||||
.field("error code"),
|
||||
);
|
||||
} else {
|
||||
check.issues.push(
|
||||
DoctorIssue::new(
|
||||
CheckStatus::Warning,
|
||||
"elevated Windows sandbox provisioning is incomplete or outdated",
|
||||
)
|
||||
.remedy(WINDOWS_SETUP_REMEDIATION)
|
||||
.field("sandbox provisioning"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(severity) = check.issues.iter().map(|issue| issue.severity).max() {
|
||||
check.status = check.status.max(severity);
|
||||
check.summary = if check.issues.len() == 1 {
|
||||
check.issues[0].cause.clone()
|
||||
} else {
|
||||
"Windows sandbox has multiple configuration or provisioning issues".to_string()
|
||||
};
|
||||
if check.remediation.is_none() {
|
||||
check.remediation = check.issues.iter().find_map(|issue| issue.remedy.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "sandbox_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,160 @@
|
||||
use codex_arg0::Arg0DispatchPaths;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::CheckStatus;
|
||||
use super::sandbox_check;
|
||||
|
||||
#[tokio::test]
|
||||
async fn reports_missing_linux_sandbox_helper() {
|
||||
let home = tempfile::tempdir().expect("create Codex home");
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(home.path().to_path_buf())
|
||||
.build()
|
||||
.await
|
||||
.expect("load sandbox config");
|
||||
let arg0_paths = Arg0DispatchPaths {
|
||||
codex_linux_sandbox_exe: Some(home.path().join("missing-linux-helper")),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let check = sandbox_check(&config, &arg0_paths);
|
||||
|
||||
assert_eq!(check.status, CheckStatus::Warning);
|
||||
assert_eq!(check.summary, "Linux sandbox helper path does not exist");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tokio::test]
|
||||
async fn reports_refresh_failure_after_setup_completed() {
|
||||
let home = tempfile::tempdir().expect("create Codex home");
|
||||
let version = codex_windows_sandbox::SETUP_VERSION;
|
||||
for (path, contents) in [
|
||||
(
|
||||
".sandbox/setup_marker.json",
|
||||
serde_json::json!({
|
||||
"version": version,
|
||||
"offline_username": codex_windows_sandbox::OFFLINE_USERNAME,
|
||||
"online_username": codex_windows_sandbox::ONLINE_USERNAME,
|
||||
}),
|
||||
),
|
||||
(
|
||||
".sandbox-secrets/sandbox_users.json",
|
||||
serde_json::json!({
|
||||
"version": version,
|
||||
"offline": {
|
||||
"username": codex_windows_sandbox::OFFLINE_USERNAME,
|
||||
"password": "",
|
||||
},
|
||||
"online": {
|
||||
"username": codex_windows_sandbox::ONLINE_USERNAME,
|
||||
"password": "",
|
||||
},
|
||||
}),
|
||||
),
|
||||
] {
|
||||
let path = home.path().join(path);
|
||||
std::fs::create_dir_all(path.parent().expect("fixture parent"))
|
||||
.expect("create fixture directory");
|
||||
std::fs::write(path, contents.to_string()).expect("write sandbox fixture");
|
||||
}
|
||||
assert!(codex_windows_sandbox::sandbox_setup_is_complete(
|
||||
home.path()
|
||||
));
|
||||
codex_windows_sandbox::write_setup_error_report(
|
||||
home.path(),
|
||||
&codex_windows_sandbox::SetupErrorReport {
|
||||
code: codex_windows_sandbox::SetupErrorCode::HelperFirewallPolicyIneffective,
|
||||
message: "firewall policy rejected the refresh".to_string(),
|
||||
},
|
||||
)
|
||||
.expect("write refresh failure");
|
||||
std::fs::write(
|
||||
home.path().join("config.toml"),
|
||||
"[windows]\nsandbox = \"elevated\"\n",
|
||||
)
|
||||
.expect("write elevated sandbox config");
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(home.path().to_path_buf())
|
||||
.build()
|
||||
.await
|
||||
.expect("load sandbox config");
|
||||
|
||||
let check = sandbox_check(&config, &Arg0DispatchPaths::default());
|
||||
|
||||
assert_eq!(check.status, CheckStatus::Fail);
|
||||
assert_eq!(
|
||||
check.issues[0].measured.as_deref(),
|
||||
Some("helper_firewall_policy_ineffective")
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tokio::test]
|
||||
async fn rejects_oversized_setup_failure_reports() {
|
||||
let home = tempfile::tempdir().expect("create Codex home");
|
||||
codex_windows_sandbox::write_setup_error_report(
|
||||
home.path(),
|
||||
&codex_windows_sandbox::SetupErrorReport {
|
||||
code: codex_windows_sandbox::SetupErrorCode::HelperFirewallPolicyIneffective,
|
||||
message: "x".repeat(64 * 1024),
|
||||
},
|
||||
)
|
||||
.expect("write oversized setup failure");
|
||||
std::fs::write(
|
||||
home.path().join("config.toml"),
|
||||
"[windows]\nsandbox = \"elevated\"\n",
|
||||
)
|
||||
.expect("write elevated sandbox config");
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(home.path().to_path_buf())
|
||||
.build()
|
||||
.await
|
||||
.expect("load sandbox config");
|
||||
|
||||
let check = sandbox_check(&config, &Arg0DispatchPaths::default());
|
||||
|
||||
assert_eq!(check.status, CheckStatus::Warning);
|
||||
assert!(
|
||||
check
|
||||
.details
|
||||
.contains(&"setup failure report: unreadable".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
check.issues[0].cause,
|
||||
"Windows sandbox setup failure report could not be read"
|
||||
);
|
||||
assert_eq!(
|
||||
check.issues[0].measured.as_deref(),
|
||||
Some("larger than 64 KiB")
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tokio::test]
|
||||
async fn reports_malformed_setup_failure_reports() {
|
||||
let home = tempfile::tempdir().expect("create Codex home");
|
||||
let path = codex_windows_sandbox::setup_error_path(home.path());
|
||||
std::fs::create_dir_all(path.parent().expect("setup failure report parent"))
|
||||
.expect("create sandbox directory");
|
||||
std::fs::write(path, "{").expect("write malformed setup failure report");
|
||||
std::fs::write(
|
||||
home.path().join("config.toml"),
|
||||
"[windows]\nsandbox = \"elevated\"\n",
|
||||
)
|
||||
.expect("write elevated sandbox config");
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(home.path().to_path_buf())
|
||||
.build()
|
||||
.await
|
||||
.expect("load sandbox config");
|
||||
|
||||
let check = sandbox_check(&config, &Arg0DispatchPaths::default());
|
||||
|
||||
assert_eq!(check.status, CheckStatus::Warning);
|
||||
assert_eq!(
|
||||
check.issues[0].cause,
|
||||
"Windows sandbox setup failure report could not be read"
|
||||
);
|
||||
assert!(check.issues[0].measured.is_some());
|
||||
}
|
||||
@@ -259,6 +259,10 @@ pub use resolved_permissions::WindowsSandboxTokenMode;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use resolved_permissions::token_mode_for_permission_profile;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup::OFFLINE_USERNAME;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup::ONLINE_USERNAME;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup::SETUP_VERSION;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup::SandboxSetupRequest;
|
||||
@@ -287,6 +291,8 @@ pub use setup_error::SetupFailure;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup_error::extract_failure as extract_setup_failure;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup_error::read_setup_error_report;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup_error::sanitize_setup_metric_tag_value;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use setup_error::setup_error_path;
|
||||
|
||||
Reference in New Issue
Block a user