mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
## Why Git rejects repositories owned by the primary user when commands run as the sandbox user. Trusting only the enclosing worktree leaves nested repositories unavailable. ## What changed Add both the worktree root and its `/*` wildcard to Git's `safe.directory` environment configuration. Update the directory and gitfile unit tests to expect both entries. GitOrigin-RevId: 4b8e2bc8cc52cff580451ffbd17eb71325957404
120 lines
4.4 KiB
Rust
120 lines
4.4 KiB
Rust
//! Shared helper utilities for Windows sandbox setup.
|
|
//!
|
|
//! These helpers centralize small pieces of setup logic used across both legacy and
|
|
//! elevated paths, including unified_exec sessions and capture flows. They cover
|
|
//! codex home directory creation and git safe.directory injection so sandboxed
|
|
//! users can run git inside a repo owned by the primary user.
|
|
|
|
use anyhow::Result;
|
|
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
|
|
/// Walk upward from `start` to locate the git worktree root for `safe.directory`.
|
|
fn find_git_worktree_root_for_safe_directory(start: &Path) -> Option<std::path::PathBuf> {
|
|
let mut cur = dunce::canonicalize(start).ok()?;
|
|
loop {
|
|
if cur.join(".git").exists() {
|
|
return Some(cur);
|
|
}
|
|
let parent = cur.parent()?;
|
|
if parent == cur {
|
|
return None;
|
|
}
|
|
cur = parent.to_path_buf();
|
|
}
|
|
}
|
|
|
|
/// Ensure the sandbox codex home directory exists.
|
|
pub fn ensure_codex_home_exists(p: &Path) -> Result<()> {
|
|
std::fs::create_dir_all(p)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Adds git safe.directory entries for the repository and nested repositories.
|
|
/// git will not otherwise allow the Sandbox user to run git commands on repositories
|
|
/// which are owned by the primary user.
|
|
pub fn inject_git_safe_directory(env_map: &mut HashMap<String, String>, cwd: &Path) {
|
|
if let Some(git_root) = find_git_worktree_root_for_safe_directory(cwd) {
|
|
let mut cfg_count: usize = env_map
|
|
.get("GIT_CONFIG_COUNT")
|
|
.and_then(|v| v.parse::<usize>().ok())
|
|
.unwrap_or(0);
|
|
let git_path = git_root.to_string_lossy().replace("\\\\", "/");
|
|
let nested_git_path = format!("{git_path}/*");
|
|
for git_path in [git_path, nested_git_path] {
|
|
env_map.insert(
|
|
format!("GIT_CONFIG_KEY_{cfg_count}"),
|
|
"safe.directory".to_string(),
|
|
);
|
|
env_map.insert(format!("GIT_CONFIG_VALUE_{cfg_count}"), git_path);
|
|
cfg_count += 1;
|
|
}
|
|
env_map.insert("GIT_CONFIG_COUNT".to_string(), cfg_count.to_string());
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::inject_git_safe_directory;
|
|
use pretty_assertions::assert_eq;
|
|
use std::collections::HashMap;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
use tempfile::TempDir;
|
|
|
|
fn safe_directory_value(path: &Path) -> String {
|
|
dunce::canonicalize(path)
|
|
.expect("canonicalize path")
|
|
.to_string_lossy()
|
|
.replace("\\\\", "/")
|
|
}
|
|
|
|
#[test]
|
|
fn injects_safe_directory_for_git_directory() {
|
|
let temp = TempDir::new().expect("tempdir");
|
|
let repo = temp.path().join("repo");
|
|
let nested = repo.join("nested");
|
|
fs::create_dir_all(repo.join(".git")).expect("create .git");
|
|
fs::create_dir_all(&nested).expect("create nested dir");
|
|
|
|
let mut env_map = HashMap::new();
|
|
inject_git_safe_directory(&mut env_map, &nested);
|
|
|
|
let git_path = safe_directory_value(&repo);
|
|
let expected = HashMap::from([
|
|
("GIT_CONFIG_COUNT".to_string(), "2".to_string()),
|
|
("GIT_CONFIG_KEY_0".to_string(), "safe.directory".to_string()),
|
|
("GIT_CONFIG_VALUE_0".to_string(), git_path.clone()),
|
|
("GIT_CONFIG_KEY_1".to_string(), "safe.directory".to_string()),
|
|
("GIT_CONFIG_VALUE_1".to_string(), format!("{git_path}/*")),
|
|
]);
|
|
assert_eq!(env_map, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn injects_worktree_root_for_gitfile() {
|
|
let temp = TempDir::new().expect("tempdir");
|
|
let repo = temp.path().join("repo");
|
|
let nested = repo.join("nested");
|
|
fs::create_dir_all(&nested).expect("create nested dir");
|
|
fs::write(
|
|
repo.join(".git"),
|
|
"gitdir: C:/Users/example/repo/.git/worktrees/codex3\n",
|
|
)
|
|
.expect("write .git file");
|
|
|
|
let mut env_map = HashMap::new();
|
|
inject_git_safe_directory(&mut env_map, &nested);
|
|
|
|
let git_path = safe_directory_value(&repo);
|
|
let expected = HashMap::from([
|
|
("GIT_CONFIG_COUNT".to_string(), "2".to_string()),
|
|
("GIT_CONFIG_KEY_0".to_string(), "safe.directory".to_string()),
|
|
("GIT_CONFIG_VALUE_0".to_string(), git_path.clone()),
|
|
("GIT_CONFIG_KEY_1".to_string(), "safe.directory".to_string()),
|
|
("GIT_CONFIG_VALUE_1".to_string(), format!("{git_path}/*")),
|
|
]);
|
|
assert_eq!(env_map, expected);
|
|
}
|
|
}
|