Private/issue 307 hono subrouter route detection - #1479
Draft
ljluestc wants to merge 3 commits into
Draft
Conversation
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.
PR: Detect Hono sub-router routes and mounted prefixes (issue #307)
Branch:
private/issue-307-hono-subrouter-route-detectionCompare:
colbymchenry/codegraph:main←ljluestc/codegraph:private/issue-307-hono-subrouter-route-detectionLinked issue: #307 (Hono sub-router detection)
Bundled work: #383 (optional MCP output sanitization)
Summary
This PR extends the framework resolver to correctly detect Hono sub-router routes and to compute full route paths across files when sub-routers are mounted with a prefix. It also bundles a related privacy-hardening change that adds an optional sanitization layer for MCP tool output (#383), so a single PR ships both workflow improvements together.
In concrete terms, this PR:
app.get/app.routesurface is compatible with the existingexpressResolver.userRoutes.get('/me', ...)) rather than only the literalapp/routernames.postExtractcross-file pass that walks JS/TS source files, resolves relative imports (./routes/users), and rewrites sub-router route names to include the parent's mount prefix — soapp.route('/users', userRoutes)+userRoutes.get('/', listUsers)yieldsGET /users(notGET /).--sanitize) for common PII/secrets, plus a custom-hook escape hatch (--sanitize-hook <module>) for organization-specific policies or external sanitizers.Problem
Issue #307 — Hono routes and mount prefixes are not visible
expressResolver.extractwas indexed on the literal namesappandrouter, so two common Hono patterns produced incomplete (or missing) routes:Sub-routers stored in user-named variables. A Hono project typically writes
Without dynamic receiver detection, the
GET /handler is dropped from the route index entirely.Sub-routers mounted with a prefix. With
the resolved route is
GET /users, notGET /. There was no cross-file pass that would first map eachHono()instance to its file, then propagate the mount prefix fromapp.route(prefix, child)calls.The end result: code browsing and "what calls this endpoint" tooling missed Hono sub-router routes, and mount prefixes were never reflected in route names.
Issue #383 — Sensitive content may leak through MCP tool output
Indexing a codebase and exposing it through MCP can surface strings that include emails, phone numbers, SSNs, credit-card-like values, or secret-like API keys. There was no pre-LLM redaction layer in the MCP response pipeline; users in regulated environments had no built-in way to enforce redaction without giving up MCP.
Solution
1) Hono detection + general receiver support in
src/resolution/frameworks/express.tshonoinpackage.jsondependencies as a framework dependency (the resolver is now explicitly multi-framework).content.includes('hono'),content.includes('new Hono('),content.includes('.route(').app/router:/\b([A-Za-z_$][\w$]*)\.(get|post|put|patch|delete|all|use)\s*\(\s*['"]([^'"]+)['"]\s*,/g2) Cross-file
postExtractpassAfter per-file extraction runs, a new
postExtractstep:Hono()(orexpress()) invocation to a file path and variable name (the "owner").parent.route('/prefix', childRouter)mounts across all files.childRouterimport to its owning file via relative-import resolution (with.ts/.tsx/.js/.jsx//index.*candidate extensions), so the prefix can be propagated across files.New helpers introduced in the same file:
parseRouteFromQualifiedName— splits a stored qualified name into method + path.joinRoutePath— joins a parent prefix path with a child route path, normalizing leading/trailing slashes.resolveImportedFile— relative-import resolution with multiple candidate extensions.3) MCP sanitization layer (
src/mcp/sanitization.ts, new)builtInSanitizationEnabled(),sanitizeText(), andsanitizeToolResult().[REDACTED_EMAIL],[REDACTED_PHONE],[REDACTED_SSN],[REDACTED_CREDIT_CARD],[REDACTED_API_KEY].sanitize) with signature(text: string) => string | Promise<string>. The hook is loaded once and cached; load/exec failures are reported to stderr ([CodeGraph MCP] Failed to load CODEGRAPH_SANITIZE_HOOK: ...,[CodeGraph MCP] CODEGRAPH_SANITIZE_HOOK execution failed: ...) without crashing the MCP server.4) Wire sanitization into
codegraph serve --mcpsrc/bin/codegraph.ts:--sanitize— propagateCODEGRAPH_SANITIZE=1.--sanitize-hook <modulePath>— propagateCODEGRAPH_SANITIZE_HOOK=<absolute-path>.ToolHandler.execute()insrc/mcp/tools.tsnow appliessanitizeToolResult()to every content block of the final tool result, after the existing worktree / staleness wrappers, so redaction happens exactly once and is consistent across all tool payloads.Changes
Production code
src/resolution/frameworks/express.tspostExtractpass; addparseRouteFromQualifiedName,joinRoutePath,resolveImportedFilehelpers.src/mcp/sanitization.ts(new)CODEGRAPH_SANITIZE,CODEGRAPH_SANITIZE_HOOK).src/mcp/tools.tssanitizeToolResulttoToolHandler.executeoutput.src/bin/codegraph.ts--sanitizeand--sanitize-hook <modulePath>tocodegraph serve.Tests
__tests__/frameworks.test.tsextracts routes from non-app/router receivers (e.g. Hono sub-router vars)— verifiesuserRoutes.get('/me', getMe)producesGET /meand a reference namedgetMe.__tests__/frameworks-integration.test.tsHono end-to-end framework extractiondescribe block: end-to-end indexing ofroutes/users.ts+main.ts(withapp.route('/users', userRoutes)) and assertion that the route set containsGET /healthandGET /users.__tests__/mcp-sanitization.test.ts(new)Documentation
README.mdcodegraph serve --mcp --sanitizeexample under command reference.site/src/content/docs/reference/cli.md--sanitizeand--sanitize-hookflags.site/src/content/docs/reference/mcp-server.mdCHANGELOG.md[Unreleased] / New Featuresentry for--sanitize/--sanitize-hook.Tooling housekeeping
91bd045) removes anPR_383_DESCRIPTION_LOCAL.mdthat was accidentally committed earlier on this branch. No content change results onmain.Test plan
Local validation commands:
Build the TypeScript output:
Run the framework tests (unit + integration):
Run the MCP sanitization tests:
Run the broader MCP test suite to confirm no regression in adjacent pipeline behavior:
Manual smoke checks:
codegraph serve --mcp --sanitizethen ask an MCP client to read a file containing an email — the response should contain[REDACTED_EMAIL].codegraph serve --mcp --sanitize-hook ./my-hook.cjswheremy-hook.cjsexports a function that wrapscustomer_id=...as[REDACTED_CUSTOMER_ID]— verify the hook's redaction is applied.main.tswithapp.route('/users', userRoutes)+routes/users.tsexportinguserRoutes.get('/', listUsers)), runcg indexAll()and confirmgetNodesByKind('route')includes bothGET /healthandGET /users.Documentation updates
README.md— installed-binary callers see the new### MCP sanitization (optional)block and an updated command-list entry.site/src/content/docs/reference/cli.md—--sanitizeand--sanitize-hookare now part of the published CLI reference.site/src/content/docs/reference/mcp-server.md— privacy-hardening paragraph and hook-contract description.CHANGELOG.md—[Unreleased] / New Featuresentry.Backward compatibility
--sanitizeorCODEGRAPH_SANITIZE=1); no existing MCP workflow is altered by default.postExtractare idempotent — running extraction twice yields the same route names.Issue linkage
02cf926without disturbing Hono framework sub-router routes not detected (~82% miss rate) #307, since the two changes touch disjoint files (src/mcp/*vssrc/resolution/frameworks/express.ts).