#177

feat(scanner): add py-litestar-route matcher

OpenPerryLinkwants to merge intofrom

Adds a py-litestar-route matcher.

Litestar is the one major Python web framework without a matcher — the other ten (fastapi, flask, django, starlette, sanic, bottle, falcon, aiohttp, tornado, celery) all have one. rg -ni litestar was 0 hits across the repo before this change.

What it matches

  • Bare handler decorators: @get(...), @post(...), @put(...), @patch(...), @delete(...), @head(...), @options(...), @trace(...), @websocket(...), @route(...)
  • HTTPRouteHandler(...) / WebSocketRouteHandler(...)
  • Router(...) factories and route_handlers= registration
  • guards=[...] (the auth gate when wired up)

The @app.get(...) attribute form is deliberately omitted — a generic attribute walk adds a lot of noise for little signal, and Litestar projects overwhelmingly use the bare form. This matches the tradeoff the sibling FastAPI matcher already made, and it's noted in a code comment.

Files

  • new packages/scanner/src/matchers/py-litestar-route.ts (54 lines)
  • packages/scanner/src/matchers/index.ts — import + register
  • packages/scanner/src/detect-tech.ts — new litestar tech tag (required, or the requires.tech gate never opens)
  • packages/scanner/src/__tests__/framework-matchers.test.ts — fixture test appended to the existing file
  • packages/scanner/src/__tests__/detect-tech.test.ts — detection test appended to the existing file

93 insertions, 0 deletions.

Verification (local)

CommandResult
pnpm vitest run --project scanner7 files, 1939 passed, 0 failed (baseline 1923 → +16)
pnpm -r buildexit 0
pnpm lintChecked 414 files. No fixes applied.
pnpm knipexit 0

The auto-discovered matcher-examples suite went 1848 → 1862; each of the 14 examples strings fires.

Note on the full pnpm test run: it reports 9 failures, all in core/cli/processor/e2e. I confirmed these are pre-existing by building a pristine git worktree at HEAD, installing and running the full suite there — identical failures with zero Litestar code present. They are Windows-only path-separator / signal / symlink-tarball issues and none are in scanner.

Activity

6
vercel[bot]1mo ago

@PerryLink is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

auto-maintain[bot]1mo ago

🤖 auto-maintain review

Automated, advisory triage for @PerryLink's PR. Facts below are read from the GitHub API.

CheckResult
Author's merged PRs (this repo)0 — ⚠️ first-time contributor
Account established✅ (age 247d · 38 followers · 202 public repos)
Commits signed/verified✅ 2/2

Review panel: 🟡 medium highest severity

deepsec maintainer code review: 🟡 medium

The matcher is wired correctly, but persisted-cache compatibility and canonical documentation need fixes before merge.

  • packages/scanner/src/index.ts:648 — Existing tech.json files predate the new `litestar` tag, so `process --diff` silently skips `py-litestar-route` after upgrade. Documenting the stale cache does not migrate or invalidate persisted project data.
  • docs/supported-tech.md:100 — The canonical supported-tech documentation omits Litestar, including its detector, matcher, and prompt highlight, leaving published coverage documentation stale.

General code review: 🟡 medium

The matcher is wired in, but stale caches disable it for existing diff workflows and the processor guidance misstates Litestar authentication behavior.

  • packages/processor/src/prompt/highlights.ts:143 — The Litestar guidance incorrectly says authentication middleware only populates `connection.user` and that an unguarded handler is reachable by anyone. Litestar authentication middleware implementations can reject missing or invalid credentials before routing; guards provide authorization, not the sole access barrier. This prompt will generate false-positive auth findings.
  • packages/scanner/src/index.ts:664 — Existing projects with a persisted `tech.json` never receive the new `litestar` tag during `scanFiles()`, so the new tech-gated matcher remains silently disabled for `process --diff` after upgrading. The added comment documents the failure but does not invalidate or refresh the cache.

Scanner and matcher quality: 🟡 medium

The Litestar integration has actionable detection and processor-guidance gaps that should be fixed before merge.

  • packages/scanner/src/index.ts:648 — Existing projects with cached tech.json never acquire the new `litestar` tag during `process --diff`, so the new matcher and prompt highlights are silently skipped after upgrade. Add detector-version cache invalidation or re-detect here.
  • packages/processor/src/prompt/slug-notes.ts:105 — The reviewer note reverses the intended auth check: it says to confirm a guard exists and `exclude_from_auth` is absent before flagging. This steers analysis toward flagging protected handlers and away from explicit auth opt-outs; it should require no effective guard or an intentional bypass.
  • packages/scanner/src/matchers/py-litestar-route.ts:38 — The decorator and handler-class patterns omit Litestar's public `@asgi(...)` and `ASGIRouteHandler(...)` entry points, leaving those routes undetected. Add both forms and executable examples.

Sandbox and credential boundaries: 🟡 medium

No sandbox, egress, credential, or path-handling surface is touched by this diff, and the matcher itself is sound (line-wise `regexMatcher` use is correct, the `WebsocketRouteHandler` vs `WebSocketRoute` casing distinction is right and tested). Merge is gated on four housekeeping issues: an oversized prompt highlight that violates the file's stated size rule and squeezes the shared 6000-char all-or-nothing budget, a new tech tag that is dead-on-arrival for existing projects because `scanFiles` never invalidates `tech.json`, a missing entry in the canonical supported-tech doc, and undisclosed scope — the Pipfile detection change affects every Python framework tag, not just Litestar.

  • packages/processor/src/prompt/highlights.ts:139 — The new `litestar` highlight renders at ~1070 chars / ~270 tokens, the largest of all 78 entries (next largest is `apex` at 706) and roughly double the median. It breaks the file's own stated contract at highlights.ts:7 ("Hard rule: 3–6 bullet lines, ~80–200 tokens … reviewers should push back on tutorial-style additions") — two bullets are 250–300 char paragraphs, one carrying an issue-tracker citation. It only passes CI because the guard in prompt-assemble.test.ts asserts `toBeLessThanOrEqual(1200)` while the test name says 800. Concrete consequence: `renderFrameworkSection` is all-or-nothing against `FRAMEWORK_SECTION_CHAR_BUDGET = 6000` (assemble.ts:14) with no truncation or ranking, so this one entry consumes ~18% of the budget and pushes any Litestar-plus-a-few-frameworks repo over the line, at which point every bullet for every framework is discarded in favor of the one-line summary.
  • packages/scanner/src/index.ts:664 — `scanFiles()` accepts a cached `tech.json` on existence alone, so for any project scanned before this PR the new `litestar` tag never appears: `py-litestar-route` stays permanently gated off and the new prompt highlight never renders on the `process --diff` path (only `scan()` at index.ts:461 re-detects). The PR ships a 16-line comment documenting this rather than the one-line mitigation that would make its own feature work — e.g. a detector/tag-set version stamped into the cache and compared here. As written the feature is inert on existing installs until an operator manually deletes `data/<projectId>/tech.json`, and nothing surfaces that to them.
  • docs/supported-tech.md:101 — `docs/supported-tech.md` is declared the canonical list of recognized frameworks and was not updated. Litestar now has all three pieces the page's own checklist (lines 186–205) requires — detector, dedicated gated matcher, prompt highlight — so it needs a `### Litestar (litestar)` section parallel to FastAPI (87–91) and Flask (93–98). Appending it to the "Other Python detected" list here would be actively wrong, since line 102 says "dedicated matchers are roadmap". The Django entry's sentinel line (81) is also now stale: it lists only `requirements.txt`/`pyproject.toml`/`setup.py`, but `Pipfile` contents now feed detection too.
  • packages/scanner/src/detect-tech.ts:152 — Folding `Pipfile` into the shared dependency haystack changes detection for all eleven Python tags (django, flask, fastapi, starlette, sanic, bottle, falcon, celery, airflow, …), not just `litestar` — any existing Pipfile-only repo can now gain tags it never had, altering matcher gating and prompt content well beyond this feature. That scope is invisible from the PR description, which claims 5 files / 93 insertions / 0 deletions while the actual diff is 9 files / 232 insertions / 4 deletions and also silently includes the processor prompt changes and the scanner cache comment. Reviewers approving against the stated file list would not review the parts that change behavior for existing projects.

Durability and distributed state: 🟡 medium

The Litestar matcher is not reliably activated for existing cached projects.

  • packages/scanner/src/index.ts:664 — scanFiles trusts any existing tech.json without version invalidation, so projects upgraded with a pre-Litestar cache silently skip the new tech-gated matcher during `process --diff` until a full scan or manual cache deletion.

Posted by auto-maintain. This automated code review is advisory; a human maintainer makes the call.

PerryLink1mo ago

All three review findings addressed in 1cc8207 — two fixed, one deliberately deferred with the reasoning below.

1. docs/supported-tech.md — fixed. Litestar was absent entirely, so the canonical coverage documentation was stale against the detector, matcher and prompt highlight this PR adds. Added a Litestar section in the Python group, in the same shape as its neighbours, with the detection and matcher facts read from the code rather than assumed: detect-tech.ts tags on litestar in deps, and matchers/index.ts registers py-litestar-route.

2. highlights.ts:143 — the auth claim was too strong; reworded. The original said the Auth middleware "only populates connection.user" and that a handler with no guard "is reachable by anyone". The second half overstates it: the middleware can still reject an unauthenticated request before the handler runs, so what a missing guard actually means is that the handler carries no authorization check. It now says that, and keeps the authentication/authorization split the guidance is built on.

I verified the rest of the Litestar bullets against the upstream docs before leaving them alone, since the review described the guidance as misstating Litestar behaviour generally. docs.litestar.dev — Guards confirms each: guards are what "authorize" a request; connection.user is attached "thanks to the JWT middleware"; guards "do not override each other but are rather cumulative"; and the OPTIONS caveat is documented there citing litestar-org/litestar#2314 — the same reference the bullet carries.

3. scanner/src/index.ts:648 — acknowledged, not fixed here, and I want to be explicit that this is a judgement rather than an oversight. The review's point is correct: documenting the stale cache does not migrate or invalidate persisted project data, and a project whose tech.json predates a tag keeps the old tag set, so tech-gated matchers — py-litestar-route included — are silently skipped under process --diff until something calls scan() or the operator deletes the cache.

The comment added in 5b5214f already states that limitation and argues why it belongs elsewhere: real invalidation is a cross-cutting change (cache schema plus a detector version that every matcher author has to bump), which is a poor fit for the matcher PR that surfaced it. That is still my read, but it is your call to accept — if you would rather have invalidation land now, say so and I will open it as its own change against main rather than growing this one.