fix: prevent nested project paths to avoid data conflicts (#338)

Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Paul Hernandez
2025-10-07 09:44:39 -05:00
committed by GitHub
parent 07e304ce8e
commit 795e339333
8 changed files with 1310 additions and 954 deletions
@@ -88,6 +88,40 @@ class ProjectService:
name
)
def _check_nested_paths(self, path1: str, path2: str) -> bool:
"""Check if two paths are nested (one is a prefix of the other).
Args:
path1: First path to compare
path2: Second path to compare
Returns:
True if one path is nested within the other, False otherwise
Examples:
_check_nested_paths("/foo", "/foo/bar") # True (child under parent)
_check_nested_paths("/foo/bar", "/foo") # True (parent over child)
_check_nested_paths("/foo", "/bar") # False (siblings)
"""
# Normalize paths to ensure proper comparison
p1 = Path(path1).resolve()
p2 = Path(path2).resolve()
# Check if either path is a parent of the other
try:
# Check if p2 is under p1
p2.relative_to(p1)
return True
except ValueError:
# Not nested in this direction, check the other
try:
# Check if p1 is under p2
p1.relative_to(p2)
return True
except ValueError:
# Not nested in either direction
return False
async def add_project(self, name: str, path: str, set_default: bool = False) -> None:
"""Add a new project to the configuration and database.
@@ -142,6 +176,29 @@ class ProjectService:
else:
resolved_path = Path(os.path.abspath(os.path.expanduser(path))).as_posix()
# Check for nested paths with existing projects
existing_projects = await self.list_projects()
for existing in existing_projects:
if self._check_nested_paths(resolved_path, existing.path):
# Determine which path is nested within which for appropriate error message
p_new = Path(resolved_path).resolve()
p_existing = Path(existing.path).resolve()
# Check if new path is nested under existing project
if p_new.is_relative_to(p_existing):
raise ValueError(
f"Cannot create project at '{resolved_path}': "
f"path is nested within existing project '{existing.name}' at '{existing.path}'. "
f"Projects cannot share directory trees."
)
else:
# Existing project is nested under new path
raise ValueError(
f"Cannot create project at '{resolved_path}': "
f"existing project '{existing.name}' at '{existing.path}' is nested within this path. "
f"Projects cannot share directory trees."
)
# First add to config file (this will validate the project doesn't exist)
project_config = self.config_manager.add_project(name, resolved_path)