diff --git a/codex-rs/core/src/config/permissions.rs b/codex-rs/core/src/config/permissions.rs index 943c82c0e9..6d938e9185 100644 --- a/codex-rs/core/src/config/permissions.rs +++ b/codex-rs/core/src/config/permissions.rs @@ -383,6 +383,16 @@ fn validate_glob_scan_max_depth(max_depth: Option) -> io::Result bool { + contains_glob_chars_for_platform(path, cfg!(windows)) +} + +fn contains_glob_chars_for_platform(path: &str, is_windows: bool) -> bool { + let normalized_windows_path = if is_windows { + normalize_windows_device_path(path) + } else { + None + }; + let path = normalized_windows_path.as_deref().unwrap_or(path); path.chars().any(|ch| matches!(ch, '*' | '?' | '[' | ']')) } diff --git a/codex-rs/core/src/config/permissions_tests.rs b/codex-rs/core/src/config/permissions_tests.rs index c2c902b23d..e021db3d2d 100644 --- a/codex-rs/core/src/config/permissions_tests.rs +++ b/codex-rs/core/src/config/permissions_tests.rs @@ -30,6 +30,18 @@ fn normalize_absolute_path_for_platform_simplifies_windows_verbatim_paths() { assert_eq!(parsed, PathBuf::from(r"D:\c\x\worktrees\2508\swift-base")); } +#[test] +fn windows_verbatim_path_prefix_does_not_count_as_glob_syntax() { + assert!(!contains_glob_chars_for_platform( + r"\\?\D:\c\x\worktrees\2508\swift-base", + /*is_windows*/ true, + )); + assert!(contains_glob_chars_for_platform( + r"\\?\D:\c\x\worktrees\2508\**\*.env", + /*is_windows*/ true, + )); +} + #[tokio::test] async fn restricted_read_implicitly_allows_helper_executables() -> std::io::Result<()> { let temp_dir = TempDir::new()?;