修复 Codex 私有运行目录的 Windows UNC 路径转换
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m26s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m54s
Project CI / Backend tests (pull_request) Successful in 3m57s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled

保留 UNC 网络共享根,避免规范化后变成相对路径
补充 UNC、盘符及普通路径回归测试
同步运行目录路径规范与共享决策记录
This commit is contained in:
2026-09-29 09:39:28 +01:00
parent 90ccb179b9
commit aaf43ec421
3 changed files with 39 additions and 9 deletions
@@ -2193,15 +2193,20 @@ fn canonical_codex_private_runtime_dir(
}
let canonical = std::fs::canonicalize(path)
.map_err(|error| format!("解析 Codex 私有运行目录失败:{}: {error}", path.display()))?;
Ok(
match canonical
.to_str()
.and_then(|value| value.strip_prefix("\\\\?\\"))
{
Some(stripped) => std::path::PathBuf::from(stripped),
None => canonical,
},
)
Ok(normalize_codex_private_runtime_path(canonical))
}
fn normalize_codex_private_runtime_path(path: std::path::PathBuf) -> std::path::PathBuf {
if let Some(value) = path.to_str() {
// UNC 命名空间必须恢复网络共享根,不能只去掉设备前缀后变成相对路径。
if let Some(rest) = value.strip_prefix(r"\\?\UNC\") {
return std::path::PathBuf::from(format!(r"\\{rest}"));
}
if let Some(rest) = value.strip_prefix(r"\\?\") {
return std::path::PathBuf::from(rest);
}
}
path
}
fn prepare_isolated_game_creator_codex_home(
@@ -6697,6 +6702,24 @@ mod tests {
assert_eq!(resolved, outside.canonicalize().expect("canonical outside"));
}
#[test]
fn codex_private_runtime_path_preserves_unc_and_drive_roots() {
for (input, expected) in [
(r"\\?\UNC\server\share\session", r"\\server\share\session"),
(r"\\?\C:\Temp\session", r"C:\Temp\session"),
(r"\\server\share\session", r"\\server\share\session"),
(r"C:\Temp\session", r"C:\Temp\session"),
("/private/tmp/session", "/private/tmp/session"),
] {
let normalized = normalize_codex_private_runtime_path(input.into());
assert_eq!(normalized, std::path::PathBuf::from(expected));
#[cfg(windows)]
if input.starts_with('\\') || input.starts_with("C:") {
assert!(normalized.is_absolute());
}
}
}
#[cfg(unix)]
#[test]
fn codex_private_runtime_dir_resolves_a_symlink_ancestor_and_rejects_an_inner_link() {
@@ -3,6 +3,7 @@
## 2026-09-29 Codex 私有运行目录先解析系统临时路径上的符号链接
- 决策:新建的 Codex 临时目录确认是普通目录后,先解析为真实路径并去掉 Windows `\\?\` 前缀,再创建 `codex-home`、`workspace` 和隔离用户目录。macOS 的 `/var`、`/tmp` 这类系统符号链接不再阻断 Game Agent 启动。
- Windows 路径转换必须先将 `\\?\UNC\server\share\...` 恢复为 `\\server\share\...`;不能只删除 `\\?\`,否则网络共享路径会变成相对路径。盘符路径继续去掉 `\\?\` 前缀。
- 范围:`validate_game_creator_private_path_ancestors` 不放宽。AppData、客户端配置,以及临时目录内部新出现的符号链接,仍然拒绝。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs`。
@@ -1,5 +1,11 @@
# AI 游戏创作智能体 App 实施计划
## 2026-09-29 Codex 私有运行目录路径解析
新建的私有运行目录先确认是普通目录并收紧权限,再解析真实路径,后续 `codex-home`、`workspace` 和隔离用户目录均在真实路径下创建,避免 macOS 系统临时目录的符号链接阻断启动。Windows 扩展 UNC 路径 `\\?\UNC\server\share\...` 必须转换为 `\\server\share\...`,盘符路径才直接去掉 `\\?\` 前缀;转换后保留绝对路径语义。私有子目录仍执行原有祖先符号链接与 reparse point 检查。
定向验证使用 Rust 单测过滤器 `codex_private_runtime_`,覆盖 UNC、盘符和普通路径转换,以及 Unix 祖先链接解析与内部链接拒绝;Windows 绝对路径断言在 Windows 测试环境执行。
## 2026-09-28 Web 环境版本探测的用户目录隔离
Node/npm 版本探测清空继承环境后,必须设置客户端创建的临时 `HOME`、`USERPROFILE`、`APPDATA` 和 `LOCALAPPDATA`,并指定空的用户及全局 npm 配置、临时缓存和临时工作目录。临时目录保留到探测子进程退出,不依赖 Windows 用户资料查询,也不读取用户或项目的 `.npmrc`。探测继续使用校验后的客户端运行时;初始化临时环境失败返回 `runtime-probe-home-unavailable`,不回退到系统 Node 或真实用户目录。