fix: correct ProjectItem.home property to return path instead of name (#341)

Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Paul Hernandez
2025-10-08 01:03:12 -05:00
committed by GitHub
parent 1fa93ecbd2
commit 3e876a7549
5 changed files with 139 additions and 79 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ async def lifespan(app: FastAPI): # pragma: no cover
# Instrument httpx client for distributed tracing when in cloud mode
if app_config.cloud_mode_enabled:
try:
import logfire
import logfire # pyright: ignore[reportMissingImports]
from basic_memory.mcp.async_client import client as httpx_client
logger.info("Cloud mode enabled - instrumenting httpx client for distributed tracing")
+1 -1
View File
@@ -183,7 +183,7 @@ class ProjectItem(BaseModel):
@property
def home(self) -> Path: # pragma: no cover
return Path(self.name)
return Path(self.path).expanduser()
@property
def project_url(self) -> str: # pragma: no cover
+6 -14
View File
@@ -138,21 +138,13 @@ class ProjectService:
if project_root:
base_path = Path(project_root)
# Sanitize the input path
# Strip leading slashes, home directory references, and parent directory references
clean_path = path.lstrip("/").replace("~/", "").replace("~", "")
# In cloud mode (when project_root is set), ignore user's path completely
# and use sanitized project name as the directory name
# This ensures flat structure: /app/data/test-bisync instead of /app/data/documents/test bisync
sanitized_name = generate_permalink(name)
# Remove any parent directory traversal attempts and normalize to lowercase
# to prevent case-sensitivity issues on Linux filesystems
path_parts = []
for part in clean_path.split("/"):
if part and part != "." and part != "..":
# Convert to lowercase to ensure case-insensitive consistency
path_parts.append(part.lower())
clean_path = "/".join(path_parts) if path_parts else ""
# Construct path relative to project_root
resolved_path = (base_path / clean_path).resolve().as_posix()
# Construct path using sanitized project name only
resolved_path = (base_path / sanitized_name).resolve().as_posix()
# Verify the resolved path is actually under project_root
if not resolved_path.startswith(base_path.resolve().as_posix()):