mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
Retry Windows sandbox runner logon failures
This commit is contained in:
@@ -40,6 +40,9 @@ mod windows_impl {
|
||||
use crate::logging::log_success;
|
||||
use crate::policy::SandboxPolicy;
|
||||
use crate::policy::parse_policy;
|
||||
use crate::setup::SandboxSetupRequest;
|
||||
use crate::setup::SetupRootOverrides;
|
||||
use crate::setup::run_elevated_setup;
|
||||
use crate::token::convert_string_sid_to_sid;
|
||||
use crate::winutil::quote_windows_arg;
|
||||
use crate::winutil::resolve_sid;
|
||||
@@ -222,6 +225,13 @@ mod windows_impl {
|
||||
}
|
||||
}
|
||||
|
||||
const ERROR_LOGON_FAILURE: i32 = 1326;
|
||||
const ERROR_ACCOUNT_LOCKED_OUT: i32 = 1909;
|
||||
|
||||
fn should_retry_after_logon_failure(err: i32) -> bool {
|
||||
matches!(err, ERROR_LOGON_FAILURE | ERROR_ACCOUNT_LOCKED_OUT)
|
||||
}
|
||||
|
||||
/// Launches the command runner under the sandbox user and captures its output.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn run_windows_sandbox_capture(
|
||||
@@ -252,7 +262,7 @@ mod windows_impl {
|
||||
|
||||
let logs_base_dir: Option<&Path> = Some(sandbox_base.as_path());
|
||||
log_start(&command, logs_base_dir);
|
||||
let sandbox_creds = require_logon_sandbox_creds(
|
||||
let mut sandbox_creds = require_logon_sandbox_creds(
|
||||
&policy,
|
||||
sandbox_policy_cwd,
|
||||
cwd,
|
||||
@@ -328,9 +338,9 @@ mod windows_impl {
|
||||
let mut si: STARTUPINFOW = unsafe { std::mem::zeroed() };
|
||||
si.cb = std::mem::size_of::<STARTUPINFOW>() as u32;
|
||||
let mut pi: PROCESS_INFORMATION = unsafe { std::mem::zeroed() };
|
||||
let user_w = to_wide(&sandbox_creds.username);
|
||||
let mut user_w = to_wide(&sandbox_creds.username);
|
||||
let domain_w = to_wide(".");
|
||||
let password_w = to_wide(&sandbox_creds.password);
|
||||
let mut password_w = to_wide(&sandbox_creds.password);
|
||||
// Suppress WER/UI popups from the runner process so we can collect exit codes.
|
||||
let _ = unsafe { SetErrorMode(0x0001 | 0x0002) }; // SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX
|
||||
|
||||
@@ -345,36 +355,80 @@ mod windows_impl {
|
||||
);
|
||||
|
||||
// Ensure command line buffer is mutable and includes the exe as argv[0].
|
||||
let spawn_res = unsafe {
|
||||
CreateProcessWithLogonW(
|
||||
user_w.as_ptr(),
|
||||
domain_w.as_ptr(),
|
||||
password_w.as_ptr(),
|
||||
LOGON_WITH_PROFILE,
|
||||
exe_w.as_ptr(),
|
||||
cmdline_vec.as_mut_ptr(),
|
||||
windows_sys::Win32::System::Threading::CREATE_NO_WINDOW
|
||||
| windows_sys::Win32::System::Threading::CREATE_UNICODE_ENVIRONMENT,
|
||||
env_block
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr() as *const c_void)
|
||||
.unwrap_or(ptr::null()),
|
||||
cwd_w.as_ptr(),
|
||||
&si,
|
||||
&mut pi,
|
||||
)
|
||||
};
|
||||
if spawn_res == 0 {
|
||||
let mut launch_attempt = 1;
|
||||
loop {
|
||||
let spawn_res = unsafe {
|
||||
CreateProcessWithLogonW(
|
||||
user_w.as_ptr(),
|
||||
domain_w.as_ptr(),
|
||||
password_w.as_ptr(),
|
||||
LOGON_WITH_PROFILE,
|
||||
exe_w.as_ptr(),
|
||||
cmdline_vec.as_mut_ptr(),
|
||||
windows_sys::Win32::System::Threading::CREATE_NO_WINDOW
|
||||
| windows_sys::Win32::System::Threading::CREATE_UNICODE_ENVIRONMENT,
|
||||
env_block
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr() as *const c_void)
|
||||
.unwrap_or(ptr::null()),
|
||||
cwd_w.as_ptr(),
|
||||
&si,
|
||||
&mut pi,
|
||||
)
|
||||
};
|
||||
if spawn_res != 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let err = unsafe { GetLastError() } as i32;
|
||||
log_note(
|
||||
&format!(
|
||||
"runner launch failed before process start: exe={} cmdline={} error={err}",
|
||||
"runner launch failed before process start: exe={} cmdline={} error={err} attempt={launch_attempt}",
|
||||
runner_exe.display(),
|
||||
runner_full_cmd
|
||||
),
|
||||
logs_base_dir,
|
||||
);
|
||||
return Err(anyhow::anyhow!("CreateProcessWithLogonW failed: {err}"));
|
||||
if launch_attempt > 1 || !should_retry_after_logon_failure(err) {
|
||||
return Err(anyhow::anyhow!("CreateProcessWithLogonW failed: {err}"));
|
||||
}
|
||||
|
||||
log_note(
|
||||
&format!(
|
||||
"runner launch hit recoverable logon error {err}; reprovisioning sandbox users and retrying"
|
||||
),
|
||||
logs_base_dir,
|
||||
);
|
||||
run_elevated_setup(
|
||||
SandboxSetupRequest {
|
||||
policy: &policy,
|
||||
policy_cwd: sandbox_policy_cwd,
|
||||
command_cwd: cwd,
|
||||
env_map: &env_map,
|
||||
codex_home,
|
||||
proxy_enforced,
|
||||
},
|
||||
SetupRootOverrides {
|
||||
read_roots: read_roots_override.map(<[PathBuf]>::to_vec),
|
||||
write_roots: write_roots_override.map(<[PathBuf]>::to_vec),
|
||||
deny_write_paths: Some(deny_write_paths_override.to_vec()),
|
||||
},
|
||||
)?;
|
||||
sandbox_creds = require_logon_sandbox_creds(
|
||||
&policy,
|
||||
sandbox_policy_cwd,
|
||||
cwd,
|
||||
&env_map,
|
||||
codex_home,
|
||||
read_roots_override,
|
||||
write_roots_override,
|
||||
deny_write_paths_override,
|
||||
proxy_enforced,
|
||||
)?;
|
||||
user_w = to_wide(&sandbox_creds.username);
|
||||
password_w = to_wide(&sandbox_creds.password);
|
||||
cmdline_vec = to_wide(&runner_full_cmd);
|
||||
launch_attempt += 1;
|
||||
}
|
||||
|
||||
if let Err(err) = connect_pipe(h_pipe_in) {
|
||||
@@ -511,6 +565,13 @@ mod windows_impl {
|
||||
fn applies_network_block_for_read_only() {
|
||||
assert!(!SandboxPolicy::new_read_only_policy().has_full_network_access());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retries_only_known_logon_errors() {
|
||||
assert!(should_retry_after_logon_failure(1326));
|
||||
assert!(should_retry_after_logon_failure(1909));
|
||||
assert!(!should_retry_after_logon_failure(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user