* feat(webui): add project workspaces and access controls * feat(webui): add project workspaces and access controls * refactor(tools): centralize workspace access resolution * refactor(webui): remove unused workspace host state * fix(webui): hide estimated file edit label * fix(webui): clarify file edit deletion feedback * fix(webui): label deleted file activity * fix(webui): flatten file edit activity rows * fix(core): remove path-only patch deletion * fix(core): keep apply patch non-destructive * refactor(webui): trim workspace host plumbing * fix(tools): register exec with tools config
31 lines
887 B
Python
31 lines
887 B
Python
"""Shared path helpers for workspace-scoped tools."""
|
|
|
|
from pathlib import Path
|
|
|
|
from nanobot.config.paths import get_media_dir
|
|
from nanobot.security.workspace_policy import (
|
|
is_path_within,
|
|
resolve_allowed_path,
|
|
)
|
|
|
|
|
|
def is_under(path: Path, directory: Path) -> bool:
|
|
"""Return True when path resolves under directory."""
|
|
return is_path_within(path, directory)
|
|
|
|
|
|
def resolve_workspace_path(
|
|
path: str,
|
|
workspace: Path | None = None,
|
|
allowed_dir: Path | None = None,
|
|
extra_allowed_dirs: list[Path] | None = None,
|
|
) -> Path:
|
|
"""Resolve path against workspace and enforce allowed directory containment."""
|
|
extra_roots = [get_media_dir(), *(extra_allowed_dirs or [])] if allowed_dir else None
|
|
return resolve_allowed_path(
|
|
path,
|
|
workspace=workspace,
|
|
allowed_root=allowed_dir,
|
|
extra_allowed_roots=extra_roots,
|
|
)
|