mirror of
https://github.com/openai/codex.git
synced 2026-09-07 15:40:00 +00:00
fix(windows-sandbox): normalize mapped drive workspaces
This commit is contained in:
@@ -84,6 +84,7 @@ features = [
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_System_Registry",
|
||||
"Win32_NetworkManagement_WNet",
|
||||
]
|
||||
version = "0.52"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::ipc_framed::Message;
|
||||
use crate::ipc_framed::SpawnRequest;
|
||||
use crate::ipc_framed::read_frame;
|
||||
use crate::ipc_framed::write_frame;
|
||||
use crate::path_normalization::resolve_sandbox_path;
|
||||
use crate::runner_pipe::PIPE_ACCESS_INBOUND;
|
||||
use crate::runner_pipe::PIPE_ACCESS_OUTBOUND;
|
||||
use crate::runner_pipe::connect_pipe;
|
||||
@@ -241,7 +242,8 @@ 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 resolved_cwd = resolve_sandbox_path(cwd);
|
||||
let cwd_w = to_wide(&resolved_cwd);
|
||||
let user_w = to_wide(&sandbox_creds.username);
|
||||
let domain_w = to_wide(".");
|
||||
let password_w = to_wide(&sandbox_creds.password);
|
||||
|
||||
@@ -34,6 +34,7 @@ mod windows_impl {
|
||||
use crate::logging::log_failure;
|
||||
use crate::logging::log_start;
|
||||
use crate::logging::log_success;
|
||||
use crate::path_normalization::resolve_sandbox_path;
|
||||
use crate::policy::SandboxPolicy;
|
||||
use crate::policy::parse_policy;
|
||||
use crate::runner_client::spawn_runner_transport;
|
||||
@@ -184,12 +185,14 @@ mod windows_impl {
|
||||
}
|
||||
|
||||
(|| -> Result<CaptureResult> {
|
||||
let resolved_cwd = resolve_sandbox_path(cwd);
|
||||
let resolved_policy_cwd = resolve_sandbox_path(sandbox_policy_cwd);
|
||||
let spawn_request = SpawnRequest {
|
||||
command: command.clone(),
|
||||
cwd: cwd.to_path_buf(),
|
||||
cwd: resolved_cwd,
|
||||
env: env_map.clone(),
|
||||
policy_json_or_preset: policy_json_or_preset.to_string(),
|
||||
sandbox_policy_cwd: sandbox_policy_cwd.to_path_buf(),
|
||||
sandbox_policy_cwd: resolved_policy_cwd,
|
||||
codex_home: sandbox_base.clone(),
|
||||
real_codex_home: codex_home.to_path_buf(),
|
||||
cap_sids,
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
use crate::winutil::to_wide;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::path::Prefix;
|
||||
use windows_sys::Win32::Foundation::ERROR_MORE_DATA;
|
||||
use windows_sys::Win32::Foundation::NO_ERROR;
|
||||
use windows_sys::Win32::NetworkManagement::WNet::WNetGetConnectionW;
|
||||
|
||||
pub fn canonicalize_path(path: &Path) -> PathBuf {
|
||||
dunce::canonicalize(path).unwrap_or_else(|_| path.to_path_buf())
|
||||
let mapped_path = resolve_sandbox_path(path);
|
||||
dunce::canonicalize(&mapped_path).unwrap_or(mapped_path)
|
||||
}
|
||||
|
||||
pub fn normalize_spawn_cwd(path: &Path) -> PathBuf {
|
||||
@@ -50,11 +55,67 @@ pub fn path_uses_unc_prefix(path: &Path) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_sandbox_path(path: &Path) -> PathBuf {
|
||||
resolve_mapped_drive_path(path).unwrap_or_else(|| path.to_path_buf())
|
||||
}
|
||||
|
||||
fn resolve_mapped_drive_path(path: &Path) -> Option<PathBuf> {
|
||||
let (drive, suffix) = split_mapped_drive_path(path)?;
|
||||
let drive_w = to_wide(drive);
|
||||
let mut remote_len = 0u32;
|
||||
let mut status =
|
||||
unsafe { WNetGetConnectionW(drive_w.as_ptr(), std::ptr::null_mut(), &mut remote_len) };
|
||||
if status != ERROR_MORE_DATA && status != NO_ERROR {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut remote_buf = vec![0u16; remote_len as usize + 1];
|
||||
status =
|
||||
unsafe { WNetGetConnectionW(drive_w.as_ptr(), remote_buf.as_mut_ptr(), &mut remote_len) };
|
||||
if status != NO_ERROR {
|
||||
return None;
|
||||
}
|
||||
|
||||
let remote_end = remote_buf
|
||||
.iter()
|
||||
.position(|ch| *ch == 0)
|
||||
.unwrap_or(remote_buf.len());
|
||||
let remote = String::from_utf16_lossy(&remote_buf[..remote_end]);
|
||||
if remote.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut resolved = PathBuf::from(remote);
|
||||
if let Some(suffix) = suffix {
|
||||
resolved.push(suffix);
|
||||
}
|
||||
Some(resolved)
|
||||
}
|
||||
|
||||
fn split_mapped_drive_path(path: &Path) -> Option<(&str, Option<&str>)> {
|
||||
let raw = path.to_str()?;
|
||||
let bytes = raw.as_bytes();
|
||||
if bytes.len() < 2 || !bytes[0].is_ascii_alphabetic() || bytes[1] != b':' {
|
||||
return None;
|
||||
}
|
||||
if bytes.len() > 2 && bytes[2] != b'\\' && bytes[2] != b'/' {
|
||||
return None;
|
||||
}
|
||||
|
||||
let suffix = if bytes.len() > 3 {
|
||||
Some(&raw[3..])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some((&raw[..2], suffix))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::canonical_path_key;
|
||||
use super::normalize_spawn_cwd;
|
||||
use super::path_uses_unc_prefix;
|
||||
use super::split_mapped_drive_path;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
@@ -97,4 +158,17 @@ mod tests {
|
||||
PathBuf::from(r"\\server\share\repo")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_mapped_drive_path_keeps_drive_relative_paths_unchanged() {
|
||||
assert_eq!(split_mapped_drive_path(Path::new(r"L:repo")), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_mapped_drive_path_extracts_drive_root_suffix() {
|
||||
assert_eq!(
|
||||
split_mapped_drive_path(Path::new(r"L:\cs-web\context")),
|
||||
Some(("L:", Some("cs-web\\context")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ use crate::allow::compute_allow_paths;
|
||||
use crate::helper_materialization::helper_bin_dir;
|
||||
use crate::logging::log_note;
|
||||
use crate::path_normalization::canonical_path_key;
|
||||
use crate::path_normalization::canonicalize_path;
|
||||
use crate::path_normalization::resolve_sandbox_path;
|
||||
use crate::policy::SandboxPolicy;
|
||||
use crate::setup_error::SetupErrorCode;
|
||||
use crate::setup_error::SetupFailure;
|
||||
@@ -177,7 +179,7 @@ fn run_setup_refresh_inner(
|
||||
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(),
|
||||
command_cwd: resolve_sandbox_path(request.command_cwd),
|
||||
read_roots,
|
||||
write_roots,
|
||||
deny_write_paths,
|
||||
@@ -322,7 +324,7 @@ fn canonical_existing(paths: &[PathBuf]) -> Vec<PathBuf> {
|
||||
if !p.exists() {
|
||||
return None;
|
||||
}
|
||||
Some(dunce::canonicalize(p).unwrap_or_else(|_| p.clone()))
|
||||
Some(canonicalize_path(p))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -727,7 +729,7 @@ pub fn run_elevated_setup(
|
||||
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(),
|
||||
command_cwd: resolve_sandbox_path(request.command_cwd),
|
||||
read_roots,
|
||||
write_roots,
|
||||
deny_write_paths,
|
||||
|
||||
Reference in New Issue
Block a user