From f2de920185d074e4b4a4dadfdeab5e95b46f437b Mon Sep 17 00:00:00 2001 From: Max Kong Date: Tue, 20 Jan 2026 16:59:59 -0500 Subject: [PATCH] fix(windows-sandbox): deny .git file entries under writable roots (#9314) ## Summary - Deny `.git` entries under writable roots even when `.git` is a file (worktrees/submodules) - Add a unit test for `.git` file handling ## Testing - `cargo test -p codex-windows-sandbox` (Windows) Fixes #9313 --- codex-rs/windows-sandbox-rs/src/allow.rs | 33 +++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/codex-rs/windows-sandbox-rs/src/allow.rs b/codex-rs/windows-sandbox-rs/src/allow.rs index 015555dab..83d72f7e5 100644 --- a/codex-rs/windows-sandbox-rs/src/allow.rs +++ b/codex-rs/windows-sandbox-rs/src/allow.rs @@ -52,9 +52,9 @@ pub fn compute_allow_paths( let canonical = canonicalize(&candidate).unwrap_or(candidate); add_allow(canonical.clone()); - let git_dir = canonical.join(".git"); - if git_dir.is_dir() { - add_deny(git_dir); + let git_entry = canonical.join(".git"); + if git_entry.exists() { + add_deny(git_entry); } }; @@ -178,6 +178,33 @@ mod tests { assert_eq!(expected_deny, paths.deny); } + #[test] + fn denies_git_file_inside_writable_root() { + let tmp = TempDir::new().expect("tempdir"); + let command_cwd = tmp.path().join("workspace"); + let git_file = command_cwd.join(".git"); + let _ = fs::create_dir_all(&command_cwd); + let _ = fs::write(&git_file, "gitdir: .git/worktrees/example"); + + let policy = SandboxPolicy::WorkspaceWrite { + writable_roots: vec![], + network_access: false, + exclude_tmpdir_env_var: true, + exclude_slash_tmp: false, + }; + + let paths = compute_allow_paths(&policy, &command_cwd, &command_cwd, &HashMap::new()); + let expected_allow: HashSet = [dunce::canonicalize(&command_cwd).unwrap()] + .into_iter() + .collect(); + let expected_deny: HashSet = [dunce::canonicalize(&git_file).unwrap()] + .into_iter() + .collect(); + + assert_eq!(expected_allow, paths.allow); + assert_eq!(expected_deny, paths.deny); + } + #[test] fn skips_git_dir_when_missing() { let tmp = TempDir::new().expect("tempdir");