Compare commits

...

1 Commits

Author SHA1 Message Date
David Wiesen
7af113903a Fix mapped-drive runner launch cwd on Windows 2026-04-25 20:39:52 -07:00
2 changed files with 46 additions and 2 deletions

View File

@@ -10,6 +10,7 @@ use crate::runner_pipe::connect_pipe;
use crate::runner_pipe::create_named_pipe;
use crate::runner_pipe::find_runner_exe;
use crate::runner_pipe::pipe_pair;
use crate::runner_pipe::prepare_runner_launch_cwd;
use crate::winutil::quote_windows_arg;
use crate::winutil::to_wide;
use anyhow::Result;
@@ -90,6 +91,7 @@ pub(crate) fn spawn_runner_transport(
.to_str()
.map(str::to_owned)
.unwrap_or_else(|| "codex-command-runner.exe".to_string());
let runner_launch_cwd = prepare_runner_launch_cwd(codex_home, log_dir);
let runner_full_cmd = format!(
"{} {} {}",
quote_windows_arg(&runner_cmdline),
@@ -98,7 +100,7 @@ pub(crate) fn spawn_runner_transport(
);
let mut cmdline_vec = to_wide(&runner_full_cmd);
let exe_w = to_wide(&runner_cmdline);
let cwd_w = to_wide(cwd);
let cwd_w = to_wide(&runner_launch_cwd);
let user_w = to_wide(&sandbox_creds.username);
let domain_w = to_wide(".");
let password_w = to_wide(&sandbox_creds.password);
@@ -136,7 +138,11 @@ pub(crate) fn spawn_runner_transport(
CloseHandle(h_pipe_in);
CloseHandle(h_pipe_out);
}
return Err(anyhow::anyhow!("CreateProcessWithLogonW failed: {err}"));
return Err(anyhow::anyhow!(
"CreateProcessWithLogonW failed: {err} (runner_cwd={} requested_cwd={})",
runner_launch_cwd.display(),
cwd.display()
));
}
let expected_runner_pid = pi.dwProcessId;

View File

@@ -9,6 +9,7 @@
use crate::helper_materialization::HelperExecutable;
use crate::helper_materialization::resolve_helper_for_launch;
use crate::logging::log_note;
use crate::winutil::resolve_sid;
use crate::winutil::string_from_sid_bytes;
use crate::winutil::to_wide;
@@ -44,6 +45,27 @@ pub fn find_runner_exe(codex_home: &Path, log_dir: Option<&Path>) -> PathBuf {
resolve_helper_for_launch(HelperExecutable::CommandRunner, codex_home, log_dir)
}
/// Picks a stable local directory for launching the elevated runner itself.
///
/// The requested workspace cwd may be a mapped drive or other user-session-specific path that
/// `CreateProcessWithLogonW` cannot use when starting the sandbox user. The runner only needs a
/// local bootstrap directory; it receives the real command cwd later in the framed spawn request.
pub fn prepare_runner_launch_cwd(codex_home: &Path, log_dir: Option<&Path>) -> PathBuf {
let runner_cwd = codex_home.join(".sandbox").join("runner-cwd");
if let Err(err) = std::fs::create_dir_all(&runner_cwd) {
log_note(
&format!(
"runner launch cwd: failed to create {}: {err}; falling back to {}",
runner_cwd.display(),
codex_home.display()
),
log_dir,
);
return codex_home.to_path_buf();
}
runner_cwd
}
/// Generates a unique named-pipe path used to communicate with the runner process.
pub fn pipe_pair() -> (String, String) {
let mut rng = SmallRng::from_entropy();
@@ -133,3 +155,19 @@ pub fn connect_pipe(h: HANDLE, expected_runner_pid: u32) -> io::Result<()> {
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::prepare_runner_launch_cwd;
#[test]
fn prepare_runner_launch_cwd_creates_sandbox_runner_dir() {
let tmp = tempfile::tempdir().expect("tempdir");
let codex_home = tmp.path().join("codex-home");
let launch_cwd = prepare_runner_launch_cwd(&codex_home, None);
assert_eq!(launch_cwd, codex_home.join(".sandbox").join("runner-cwd"));
assert!(launch_cwd.is_dir());
}
}