Skip to content

Consolidate the triplicated path_within_root containment helper into one shared module - #161

Merged
mikebronner merged 3 commits into
mainfrom
chore/156-consolidate-the-triplicated-path-within-root-conta
Jun 16, 2026
Merged

mikebronner merged 3 commits into
mainfrom
chore/156-consolidate-the-triplicated-path-within-root-conta

Conversation

@mikebronner

@mikebronner mikebronner commented Jun 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements #156 — consolidates the canonical-first root-containment check, which had drifted into three copies with three divergent fallbacks, into one shared path_containment module. Built to Option 3 (Mike's call): one module, two entry points sharing a canonical-first core, so the security guards keep their #155 fail-closed behavior while salsa_impl's speculative-candidate filter keeps its lexical fallback.

Changes

  • New laravel-lsp/src/path_containment.rs, declared pub mod path_containment; in lib.rs, with a shared canonical-first core (canonical_containment) and two public entry points:
  • Removed the private fn path_within_root from main.rs; all call-sites (including the one Rename path resolution: wire collect_route_declaration_targets' page-path read through path_within_root #157 added in collect_route_declaration_targets) route through laravel_lsp::path_containment::path_within_root.
  • Removed the private fn path_within_root from slot_navigation.rs; its caller now uses the shared guard — upgrade: raw-textual fallback → fail-closed.
  • Replaced the inline containment check in salsa_impl.rs with path_within_root_lexical (preserves speculative-candidate admission — not fail-closed).
  • Updated the stale "Mirrors path_within_root in main.rs" doc-comments to reference path_containment.
  • Bundled (Mike's call, unrelated area): two find_block_terminator tests in blade_var_rename/tests.rs — a fake @endphp inside a /* … */ block comment, and inside a double-quoted-label heredoc (<<<"LABEL").

Acceptance Criteria

Test Plan

  • cargo build --release — clean
  • cargo fmt --check — clean
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo test --all-features — lib suite green (2179 tests), incl. all containment tests now routing through the shared module; new path_containment tests (5) and bundled blade tests (2) pass
  • Verified the 8 integration-test failures are pre-existing and environment-only (gitignored .env + composer vendor/), identical on clean origin/main; CI bootstraps both

Fixes #156

@dr-john-h-watson

Copy link
Copy Markdown

Resume spec for the scheduled pipeline — Mike approved Option 3; this draft PR is the work surface (resume it, don't open a new one). Implement against the item's amended acceptance criteria:

Design — one module, two entry points:

  • New laravel-lsp/src/path_containment.rs, declared pub mod path_containment; in lib.rs, with a shared canonical-first core and:
    • pub fn path_within_root(path, root) -> bool — fail-closed (canonicalize failure ⇒ false; preserves harden: make path_within_root fail-closed for security-guard callers (dangling-symlink leg) #155). Used by main.rs (no behavior change) and slot_navigation.rs (upgrade from its current raw-textual fallback).
    • pub fn path_within_root_lexical(path, root) -> bool — normalize_path lexical fallback for not-yet-existing candidates. Used by salsa_impl.rs's retain (must not be fail-closed — it filters speculative paths that can't canonicalize yet).
  • Remove the private fn path_within_root from main.rs and slot_navigation.rs; replace salsa_impl.rs's inline check (~line 2950) with path_within_root_lexical.

Critical:

Bundled (Mike's call, unrelated area): add two tests to blade_var_rename/tests.rs for already-working-but-uncovered find_block_terminator paths — a fake @endphp inside a /* … */ block comment, and a <<<"LABEL" double-quoted heredoc body.

Once green, flip to ready-for-review; Holmes reviews, Mike merges. (Note: closing #156 also unblocks #145, which is queued behind it.)

…module.

The canonical-first root-containment check lived in three copies with three
divergent fallbacks: main.rs (fail-closed, #155), slot_navigation.rs
(raw-textual), and an inline `retain` in salsa_impl.rs (lexical, for
speculative candidates). Three copies can drift, and any future hardening
had to land in all three and stay in sync.

Extract one `path_containment` module with a shared canonical-first core and
two public entry points:
- `path_within_root` — fail-closed; the security guard, used by main.rs (no
  behavior change) and slot_navigation.rs (upgrade: raw-textual → fail-closed).
- `path_within_root_lexical` — normalize_path lexical fallback that admits
  not-yet-created candidates, used by salsa_impl.rs's component-path filter
  (which must not fail-close).

All main.rs call-sites (including the one #157 added in
collect_route_declaration_targets) now route through the shared guard. Unit
tests cover in-root, sibling-root, interior-`..` escape, and the fail-closed
dangling-under-root-symlink leg.

Fixes: #156
…eredoc legs.

Two already-working but uncovered paths in `find_block_terminator`'s @php-block
masking: a literal @endphp inside a `/* … */` block comment, and inside a
double-quoted-label heredoc (`<<<"LABEL"`). Existing tests only reach the `//`
line-comment, bare-label heredoc, and nowdoc legs.

Bundled from #93/#164 (unrelated area, folded into #156's PR by request).
@mikebronner
mikebronner force-pushed the chore/156-consolidate-the-triplicated-path-within-root-conta branch from 3bcfef3 to 4e736d6 Compare June 16, 2026 15:04
@mikebronner
mikebronner marked this pull request as ready for review June 16, 2026 15:04

@mr-sherlock-holmes mr-sherlock-holmes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved

Review Summary

  • Consolidates the triplicated path_within_root containment guard into one shared laravel-lsp/src/path_containment.rs module behind a private canonical-first core (canonical_containment) and two public entry points — exactly as the contract requires.
  • Every acceptance criterion is met:
    • ✅ New path_containment.rs created and declared pub mod path_containment; (lib.rs:58).
    • ✅ Fail-closed path_within_root (path_containment.rs:51, unwrap_or(false)) and lexical path_within_root_lexical (:63, unwrap_or_else(|| normalize_path(path).starts_with(root))).
    • ✅ Private fn path_within_root removed from main.rs; all call-sites resolve to the shared import (main.rs:30) — verified by grep across main.rs (4843, 4874, 13927, 18958, 19515, 21759), including the collect_route_declaration_targets site PR #157 added. Only one production definition survives.
    • ✅ Private fn removed from slot_navigation.rs; caller now uses the shared fail-closed guard (:278) — a genuine security upgrade over the old raw-textual fallback.
    • ✅ salsa_impl.rs's inline retain swapped for path_within_root_lexical (:2952), preserving speculative-candidate admission (not fail-closed).
    • ✅ Unit tests cover all four named cases plus a fifth (speculative in-root admit): in-root⇒true, sibling⇒false, interior-..-escape⇒false, dangling-symlink fail-closed⇒false (path_containment.rs:72–172).
    • ✅ Stale "Mirrors path_within_root in main.rs" doc-comments retired in both slot_navigation.rs and salsa_impl.rs.
    • ✅ Two bundled blade_var_rename tests added (block-comment and double-quoted-heredoc @endphp), tests.rs:947–980.
  • Tests verified: CI fully green (LSP test+fmt+clippy, extension wasm+fmt+clippy, CodeQL); lens reviewers independently ran cargo test — 1850 tests pass, new tests included. The new tests exercise distinct legs and would fail on a logic reversion (not tautologies).

The security review confirmed the consolidation introduces no bypass: the lexical entry point is used only on the speculative-candidate path in salsa_impl.rs, never on a read/emit path, and normalize_path correctly defeats interior-.. escapes. Excellent, surgical work — well-documented and the slot-navigation leg is now stronger than before.

📋 Non-blocking follow-ups

  • None.

Ready for @mikebronner to merge.

@mikebronner
mikebronner merged commit a26575d into main Jun 16, 2026
5 checks passed
@mikebronner
mikebronner deleted the chore/156-consolidate-the-triplicated-path-within-root-conta branch June 16, 2026 17:45
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.

Consolidate the triplicated path_within_root containment helper into one shared module

1 participant