mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
fs: support pruning hidden directories during walks (#31570)
Why Filtering hidden directories after a walk is too late: their descendants consume traversal limits, and canonical directory deduplication can let a hidden path claim a target before a visible symlink reaches it. What this changes - Add an optional pruneHiddenDirectories walk option. It defaults to false and is omitted from the wire when disabled. - Return hidden directory entries, but do not traverse them or add their canonical identities to the visited set. - Cover the visible-symlink-to-hidden-directory case through both local and remote filesystem implementations. This is the small filesystem prerequisite for #31566. Skill-specific behavior remains in that PR.
This commit is contained in:
@@ -402,6 +402,7 @@ async fn file_system_walk_returns_a_bounded_tree(
|
||||
max_directories: 10,
|
||||
max_entries: 10,
|
||||
follow_directory_symlinks: false,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
@@ -447,6 +448,7 @@ async fn file_system_walk_returns_a_bounded_tree(
|
||||
max_directories: 10,
|
||||
max_entries: 10,
|
||||
follow_directory_symlinks: false,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
@@ -469,6 +471,7 @@ async fn file_system_walk_returns_a_bounded_tree(
|
||||
max_directories: 1,
|
||||
max_entries: 10,
|
||||
follow_directory_symlinks: false,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
@@ -491,6 +494,7 @@ async fn file_system_walk_returns_a_bounded_tree(
|
||||
max_directories: 10,
|
||||
max_entries: 1,
|
||||
follow_directory_symlinks: false,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
@@ -535,6 +539,7 @@ async fn file_system_walk_honors_read_sandbox(
|
||||
max_directories: 2,
|
||||
max_entries: 2,
|
||||
follow_directory_symlinks: false,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
Some(&sandbox),
|
||||
)
|
||||
|
||||
@@ -299,6 +299,7 @@ async fn file_system_walk_handles_directory_symlinks(
|
||||
max_directories: 4,
|
||||
max_entries: 8,
|
||||
follow_directory_symlinks: false,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
@@ -321,6 +322,7 @@ async fn file_system_walk_handles_directory_symlinks(
|
||||
max_directories: 4,
|
||||
max_entries: 8,
|
||||
follow_directory_symlinks: true,
|
||||
prune_hidden_directories: false,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
@@ -351,6 +353,68 @@ async fn file_system_walk_handles_directory_symlinks(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(FileSystemImplementation::Local ; "local")]
|
||||
#[test_case(FileSystemImplementation::Remote ; "remote")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn file_system_walk_prunes_hidden_directories_without_claiming_visible_aliases(
|
||||
implementation: FileSystemImplementation,
|
||||
) -> Result<()> {
|
||||
let context = create_file_system_context(implementation).await?;
|
||||
let file_system = context.file_system;
|
||||
|
||||
let tmp = TempDir::new()?;
|
||||
let root = tmp.path().join("root");
|
||||
let hidden = root.join(".hidden");
|
||||
let hidden_nested = hidden.join("nested");
|
||||
let visible = root.join("visible");
|
||||
std::fs::create_dir_all(&hidden_nested)?;
|
||||
std::fs::write(hidden_nested.join("note.txt"), "visible through alias")?;
|
||||
symlink(&hidden, &visible)?;
|
||||
|
||||
let outcome = file_system
|
||||
.walk(
|
||||
&PathUri::from_host_native_path(&root)?,
|
||||
WalkOptions {
|
||||
max_depth: 3,
|
||||
max_directories: 3,
|
||||
max_entries: 6,
|
||||
follow_directory_symlinks: true,
|
||||
prune_hidden_directories: true,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
.await
|
||||
.with_context(|| format!("mode={implementation}"))?;
|
||||
|
||||
assert_eq!(
|
||||
outcome,
|
||||
WalkOutcome {
|
||||
entries: vec![
|
||||
WalkEntry {
|
||||
path: PathUri::from_host_native_path(hidden)?,
|
||||
kind: WalkEntryKind::Directory,
|
||||
},
|
||||
WalkEntry {
|
||||
path: PathUri::from_host_native_path(&visible)?,
|
||||
kind: WalkEntryKind::Directory,
|
||||
},
|
||||
WalkEntry {
|
||||
path: PathUri::from_host_native_path(visible.join("nested"))?,
|
||||
kind: WalkEntryKind::Directory,
|
||||
},
|
||||
WalkEntry {
|
||||
path: PathUri::from_host_native_path(visible.join("nested/note.txt"))?,
|
||||
kind: WalkEntryKind::File,
|
||||
},
|
||||
],
|
||||
errors: Vec::new(),
|
||||
truncated: false,
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(FileSystemImplementation::Local ; "local")]
|
||||
#[test_case(FileSystemImplementation::Remote ; "remote")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
Reference in New Issue
Block a user