Skip to content

chore(tools): Workspace path validation and dir move support#658

Merged
JeanMertz merged 5 commits into
mainfrom
prr226
May 19, 2026
Merged

chore(tools): Workspace path validation and dir move support#658
JeanMertz merged 5 commits into
mainfrom
prr226

Conversation

@JeanMertz
Copy link
Copy Markdown
Collaborator

All filesystem tools previously validated user-supplied paths through ad-hoc inline checks (is_absolute, trim_start_matches, etc.) with no protection against symlink escape attacks. This commit replaces those scattered checks with a shared check_workspace_path pipeline in fs/utils.rs and two public entry points:

  • resolve_workspace_path — canonicalizes through symlinks on existing ancestors, guaranteeing the result lies inside the workspace root. Used by write tools (create_file, delete_file, modify_file, move_file, read_file).
  • clean_workspace_path — lexically normalizes without following symlinks, while still verifying the canonical ancestor stays in-root. Used by read/search tools (grep_files, list_files) where the returned path should match the user's input shape.

The validator rejects absolute paths, ..-escape attempts that survive normalization, symlinks whose canonical target falls outside the root, path components exceeding 100 bytes, and paths with more than 20 components.

fs_move_file was also expanded to handle directories in addition to files: directories are moved atomically with fs::rename, require the target to not already exist, and get a broader dirty check via count_dirty_paths_impl (any non-empty git status --porcelain line counts). A same-path guard prevents no-op moves, and the success message now distinguishes between file and directory moves. The tool description in .jp/mcp/tools/fs/move_file.toml is updated to reflect the new capability.

Base automatically changed from prr225 to main May 19, 2026 08:45
All filesystem tools previously validated user-supplied paths through
ad-hoc inline checks (is_absolute, trim_start_matches, etc.) with no
protection against symlink escape attacks. This commit replaces those
scattered checks with a shared `check_workspace_path` pipeline in
`fs/utils.rs` and two public entry points:

- `resolve_workspace_path` — canonicalizes through symlinks on existing
  ancestors, guaranteeing the result lies inside the workspace root.
  Used by write tools (`create_file`, `delete_file`, `modify_file`,
  `move_file`, `read_file`).
- `clean_workspace_path` — lexically normalizes without following
  symlinks, while still verifying the canonical ancestor stays in-root.
  Used by read/search tools (`grep_files`, `list_files`) where the
  returned path should match the user's input shape.

The validator rejects absolute paths, `..`-escape attempts that survive
normalization, symlinks whose canonical target falls outside the root,
path components exceeding 100 bytes, and paths with more than 20
components.

`fs_move_file` was also expanded to handle directories in addition to
files: directories are moved atomically with `fs::rename`, require the
target to not already exist, and get a broader dirty check via
`count_dirty_paths_impl` (any non-empty `git status --porcelain` line
counts). A same-path guard prevents no-op moves, and the success message
now distinguishes between file and directory moves. The tool description
in `.jp/mcp/tools/fs/move_file.toml` is updated to reflect the new
capability.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
JeanMertz added 4 commits May 19, 2026 11:51
Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
@JeanMertz JeanMertz merged commit f6061e7 into main May 19, 2026
14 checks passed
@JeanMertz JeanMertz deleted the prr226 branch May 19, 2026 17:40
JeanMertz added a commit that referenced this pull request May 19, 2026
JeanMertz added a commit that referenced this pull request May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant