From 7c47952f7c2c27f7d45cb7f9d4a42671814ef71e Mon Sep 17 00:00:00 2001 From: iceweasel-oai Date: Tue, 11 Aug 2026 22:04:42 +0000 Subject: [PATCH] Allow nested Git repositories in the Windows sandbox (#38080) ## 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 --- .../windows-sandbox-rs/src/sandbox_utils.rs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/codex-rs/windows-sandbox-rs/src/sandbox_utils.rs b/codex-rs/windows-sandbox-rs/src/sandbox_utils.rs index fa08309550..1dfd768302 100644 --- a/codex-rs/windows-sandbox-rs/src/sandbox_utils.rs +++ b/codex-rs/windows-sandbox-rs/src/sandbox_utils.rs @@ -30,9 +30,9 @@ pub fn ensure_codex_home_exists(p: &Path) -> Result<()> { Ok(()) } -/// Adds a git safe.directory entry to the environment when running inside a repository. -/// git will not otherwise allow the Sandbox user to run git commands on the repo directory -/// which is owned by the primary user. +/// 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, cwd: &Path) { if let Some(git_root) = find_git_worktree_root_for_safe_directory(cwd) { let mut cfg_count: usize = env_map @@ -40,12 +40,15 @@ pub fn inject_git_safe_directory(env_map: &mut HashMap, cwd: &Pa .and_then(|v| v.parse::().ok()) .unwrap_or(0); let git_path = git_root.to_string_lossy().replace("\\\\", "/"); - 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; + 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()); } } @@ -77,13 +80,13 @@ mod tests { 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(), "1".to_string()), + ("GIT_CONFIG_COUNT".to_string(), "2".to_string()), ("GIT_CONFIG_KEY_0".to_string(), "safe.directory".to_string()), - ( - "GIT_CONFIG_VALUE_0".to_string(), - safe_directory_value(&repo), - ), + ("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); } @@ -103,13 +106,13 @@ mod tests { 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(), "1".to_string()), + ("GIT_CONFIG_COUNT".to_string(), "2".to_string()), ("GIT_CONFIG_KEY_0".to_string(), "safe.directory".to_string()), - ( - "GIT_CONFIG_VALUE_0".to_string(), - safe_directory_value(&repo), - ), + ("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); }