diff --git a/src/specify_cli/integrations/base.py b/src/specify_cli/integrations/base.py index 38406138f..73e51ae7f 100644 --- a/src/specify_cli/integrations/base.py +++ b/src/specify_cli/integrations/base.py @@ -87,8 +87,8 @@ class IntegrationBase(ABC): def templates_dir(self) -> Path: """Return the path to this integration's bundled templates. - By convention, templates live in a ``templates/`` subdirectory next - to the integration's ``__init__.py``. + By convention, templates live in a ``templates/`` subdirectory + next to the file where the integration class is defined. """ import inspect diff --git a/src/specify_cli/integrations/manifest.py b/src/specify_cli/integrations/manifest.py index 08d0e1238..50ac08ea3 100644 --- a/src/specify_cli/integrations/manifest.py +++ b/src/specify_cli/integrations/manifest.py @@ -113,14 +113,15 @@ class IntegrationManifest: """Return relative paths of tracked files whose content changed on disk.""" modified: list[str] = [] for rel, expected_hash in self._files.items(): - try: - abs_path = _validate_rel_path(Path(rel), self.project_root) - except ValueError: + rel_path = Path(rel) + # Skip paths that are absolute or attempt to escape the project root + if rel_path.is_absolute() or ".." in rel_path.parts: continue - if not abs_path.exists(): + abs_path = self.project_root / rel_path + if not abs_path.exists() and not abs_path.is_symlink(): continue - # Treat non-regular-files (directories, symlinks) as modified - if not abs_path.is_file(): + # Treat symlinks and non-regular-files as modified + if abs_path.is_symlink() or not abs_path.is_file(): modified.append(rel) continue if _sha256(abs_path) != expected_hash: