From 660bbf615a86ee6937e641b05b67fbfa15524af8 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 27 Sep 2026 00:01:47 -0700 Subject: [PATCH] fix: refuse home dir when base path has a trailing separator The home-directory guard compared raw OsStr bytes against dirs::home_dir(), so "/home/u/" slipped past a check written for "/home/u". fff-mcp hits this whenever $HOME is itself a git repository: git root discovery returns the root with a trailing slash, the guard never fires, and the whole home directory is indexed without --enable-home-scan. Compare as Path instead, which is component-wise and ignores the trailing separator. Adds a regression test that fails on the old comparison. Co-Authored-By: Claude Opus 5.5 --- crates/fff-core/src/file_picker.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/fff-core/src/file_picker.rs b/crates/fff-core/src/file_picker.rs index 0d6a6d624..d25158cf9 100644 --- a/crates/fff-core/src/file_picker.rs +++ b/crates/fff-core/src/file_picker.rs @@ -894,9 +894,8 @@ impl FilePicker { error!("Refusing to index filesystem root: {}", path.display()); return Err(Error::FilesystemRoot(path)); } - if !options.enable_home_dir_scanning - && Some(path.as_os_str()) == dirs::home_dir().as_ref().map(|p| p.as_os_str()) - { + // Path equality compares components, so "~/" (as git root discovery returns it) matches too. + if !options.enable_home_dir_scanning && dirs::home_dir().is_some_and(|home| path == home) { error!("Refusing to index home directory: {}", path.display()); return Err(Error::FilesystemRoot(path)); } @@ -2474,6 +2473,23 @@ pub(crate) fn hint_allocator_collect() { mod tests { use super::*; + #[test] + fn refuses_home_dir_with_trailing_separator() { + let Some(home) = dirs::home_dir() else { return }; + for base in [home.clone(), home.join("")] { + let result = FilePicker::new(FilePickerOptions { + base_path: base.to_string_lossy().into_owned(), + watch: false, + ..Default::default() + }); + assert!( + matches!(result, Err(Error::FilesystemRoot(_))), + "home dir accepted as {}", + base.display() + ); + } + } + /// The watcher must watch every ancestor directory up to `base_path`, /// not just the immediate parents of indexed files. The dir table is /// built from the walker's visited dirs, so pure ancestors (dirs that