fix(mcp): close the symlink escape in the write guard + more #171 validation - #174
Merged
Merged
Conversation
…on (#171) confine_to_root only normalized paths lexically, so a `.codeweb` symlink inside the project pointing elsewhere passed the check and the store write landed outside the permitted directory. Verified as Red first: with a symlinked .codeweb the guard accepted the path. The guard now also canonicalizes the deepest existing ancestor of the target and compares it against the canonicalized root. Both sides are canonicalized, so legitimate paths that merely traverse a symlink (e.g. /tmp on macOS) are still accepted. Additional validation added while checking the finished work: - corrupt store: queries report it explicitly and codeweb_analyze self-heals - pipelined analyze+analyze+stats requests all answer (no lock deadlock) - --project pointing at a not-yet-existing directory works with codeweb_init - init_at path branches: empty dir list, absolute source dirs preserved
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up hardening + extra validation on the #171 work (which is already merged and closed).
1. Real gap found and fixed: symlink escape in the write guard
confine_to_rootonly normalized paths lexically. A.codewebsymlink inside the project pointing elsewhere looked like an in-root path, so the store write landed outside the permitted directory.Verified as Red before fixing:
confine_rejects_symlinked_subdir_escaping_rootfailed on the old guard (lexical check passed).Fix: after the lexical check, canonicalize the deepest existing ancestor of the target and compare it with the canonicalized root. Both sides are canonicalized, so a path that merely traverses a symlink (e.g.
/tmp→/private/tmpon macOS) is still accepted — covered byconfine_accepts_real_dirs_and_symlinked_root.Integration proof:
test_mcp_analyze_rejects_symlinked_store_dirbuilds a project whose.codewebis a symlink to an outside dir, callscodeweb_analyze, and assertsstatus:"error"and that the symlink target stayed empty.2. Extra validation of the finished work (behaviors that already worked, now locked down)
codeweb_analyzeself-heals ittest_mcp_analyze_heals_corrupt_storeanalyze+analyze+statsall answer, no lock deadlock, consistent statetest_mcp_handles_pipelined_requests--projectpointing at a not-yet-existing directory works withcodeweb_inittest_mcp_init_creates_missing_project_directoryinit_at: empty dir list defaults to["."]; absolute source dirs preserved verbatiminit_at_defaults_to_root_when_no_source_dirs_given,init_at_keeps_absolute_source_dirs_absoluteThe last two
init_attests are characterization tests for previously untested branches (they pass on the existing implementation); they are not Red→Green cycles.3. Docs
Plan doc and DeveloperGuide updated to describe the two-layer guard and the new loops.
Verification
cargo fmt --all -- --checkcleancargo clippy --features full -- -D warningscleancargo test --features full -- --skip test_path_mapping_applied --skip test_serve_→ 40/40 suites ok, 0 failures (mcp_test17 passed)