Summary
The recursive scanner follows directory symlinks without checking the canonical workspace boundary or tracking visited directories. A symlink can expose entries outside the workspace or create a traversal cycle.
Evidence
src-tauri/src/workspace/scan.rs:77-87 calls path.metadata(), which follows symlinks, and pushes every resulting directory onto the traversal stack.
This contradicts PR-030, which requires symlinks resolving outside the workspace to be blocked and represented as tombstones.
Proposed change
- Inspect entries with
symlink_metadata.
- Canonicalize a directory before traversal and require it to remain within the canonical workspace root.
- Track visited
(device, inode) directory identities to prevent cycles and repeated traversal.
- Return an explicit blocked-symlink/tombstone entry instead of silently following or dropping it.
- Apply the same boundary helper to every filesystem command.
Acceptance criteria
- A symlink to a directory outside the workspace is never traversed.
- A symlink to an ancestor cannot cause an infinite or repeated scan.
- A valid in-root symlink follows the documented product behavior.
- Tests cover escaping symlinks, ancestor cycles, broken symlinks, and ordinary nested directories.
Summary
The recursive scanner follows directory symlinks without checking the canonical workspace boundary or tracking visited directories. A symlink can expose entries outside the workspace or create a traversal cycle.
Evidence
src-tauri/src/workspace/scan.rs:77-87callspath.metadata(), which follows symlinks, and pushes every resulting directory onto the traversal stack.This contradicts PR-030, which requires symlinks resolving outside the workspace to be blocked and represented as tombstones.
Proposed change
symlink_metadata.(device, inode)directory identities to prevent cycles and repeated traversal.Acceptance criteria