Files
codebase-memory-mcp/internal/cbm/service_patterns.h
T
Martin Vogel 4d97d7819b fix(routes): read a ServeMux pattern only for Handle and HandleFunc
The Go 1.22 pattern split ran for every route-verb callee, so other Go
calls whose name ends in Get/Post/Put/Delete/Patch became route
registrations: st.Get("users/123") on a project method minted
__route__GET__/123 and lost its CALLS edge to Store.Get, and
c.Get("https://api.example.com/v1/x") split "https:" off as a host and
minted __route__GET__//api.example.com/v1/x, in both passes.

cbm_service_pattern_mux_route_path reads the pattern only for a callee
ending ".Handle" or ".HandleFunc", and never for an argument containing
"://". The extractor's handler capture and both passes (route_reg_path,
find_route_path_in_args, cbm_pipeline_route_reg_method) go through it,
so the two passes still mint identical Routes. Two negative cases
extend pipeline_go_servemux_method_patterns_issue2537 in both passes,
and the infrascan unit covers the gate.

Refs #2537

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-26 01:46:33 +01:00

124 lines
6.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* service_patterns.h — Allowlists for HTTP clients, async dispatch, and config accessors.
*
* Used during call resolution to classify CALLS edges as:
* HTTP_CALLS — synchronous HTTP client calls
* ASYNC_CALLS — async message/task dispatch
* CONFIGURES — config/env access
*
* Lookup is O(1) via hash table initialized once at startup.
*/
#ifndef CBM_SERVICE_PATTERNS_H
#define CBM_SERVICE_PATTERNS_H
#include <stdbool.h>
#include <stddef.h>
/* Edge type returned by pattern match. */
typedef enum {
CBM_SVC_NONE = 0, /* Not a service pattern — use normal CALLS */
CBM_SVC_HTTP = 1, /* Synchronous HTTP client call */
CBM_SVC_ASYNC = 2, /* Async dispatch (message broker, task queue) */
CBM_SVC_CONFIG = 3, /* Config/env accessor */
CBM_SVC_ROUTE_REG = 4, /* Route registration (router.GET, app.get, Route::post) */
CBM_SVC_GRPC = 5, /* gRPC client call (protobuf stub invocation) */
CBM_SVC_GRAPHQL = 6, /* GraphQL client query/mutation */
CBM_SVC_TRPC = 7, /* tRPC client procedure call */
} cbm_svc_kind_t;
/* Initialize the pattern lookup tables. Call once at startup. Thread-safe after init. */
void cbm_service_patterns_init(void);
/* Check if a resolved QN contains a known service library identifier.
* Returns the pattern kind, or CBM_SVC_NONE if no match.
* Matches on library name substrings in the QN (e.g., "requests" in
* "project.venv.requests.api.get"). Import-alias transparent. */
cbm_svc_kind_t cbm_service_pattern_match(const char *resolved_qn);
/* True for a bare, unqualified call to the native `fetch()` API. Deliberately
* NOT part of the substring tables above: those are matched unconditionally
* against the raw callee name before/regardless of registry resolution
* (the #523 external-library bypass), and "fetch" — unlike "axios" or
* "requests" — collides with a plausible local identifier. Callers must
* only consult this after registry resolution has come back empty, so a
* locally resolvable `function fetch(){}` / `const fetch = () => {}` is
* classified via its real resolved QN instead and never reaches this check. */
bool cbm_service_pattern_is_global_fetch(const char *callee_name);
/* True when a string literal is a plausible HTTP route for the given callee.
* Rejects filesystem paths and non-HTTP string consumers. */
bool cbm_service_pattern_is_http_route_literal(const char *literal, const char *callee_name);
/* True when a JS/TS-family call is client-side navigation rather than a
* network request (#1250): Angular Router.navigate/navigateByUrl, Ionic navigation, Nuxt
* navigateTo, react-router navigate, router/history push|replace|prefetch,
* History pushState/replaceState, Location go|assign|replace, bare goto /
* redirect / permanentRedirect. Its slash-prefixed argument is a client route,
* so it must not mint an arg_url HTTP_CALLS edge. js_family is the caller's
* FILE-language gate: false always returns false, so no other language's
* recall is traded (suppressors stay per-language). */
bool cbm_service_pattern_is_client_navigation(bool js_family, const char *callee_name);
/* True when text that reached a path slot is a source comment rather than a
* path: a block comment (slash-star … star-slash), a line comment (slash-slash
* followed by a space), or any text with a line break. The wildcard route
* (slash-star alone) is a path. */
bool cbm_service_pattern_is_comment_text(const char *text);
/* Per-worker TLS cache for cbm_service_pattern_match results. The
* pattern matcher runs once per resolved CALL edge in emit_service_
* edge — that's 6 pattern lists × ~30 patterns × strstr per call ≈
* ~180 strstrs per call. The same resolved QN repeats across most of
* the call edges in a project (e.g. "fmt.Errorf"), so caching turns
* a linear pattern-list scan into one hash lookup. Call _begin once
* per worker thread before the resolve loop and _end at the end. */
void cbm_service_pattern_cache_begin(void);
void cbm_service_pattern_cache_end(void);
/* Get the HTTP method from the callee name suffix (e.g., ".get" → "GET").
* Returns NULL if method cannot be inferred. */
const char *cbm_service_pattern_http_method(const char *callee_name);
/* Get the HTTP method from a route registration callee name suffix
* (e.g., "router.GET" → "GET", "app.post" → "POST").
* Returns NULL if not a known route registration method. */
const char *cbm_service_pattern_route_method(const char *callee_name);
/* Go 1.22+ net/http ServeMux pattern "[METHOD ][HOST]/[PATH]" (#2537):
* "POST /v1/x", "GET api.example.com/v1/x", "api.example.com/v1/x". Returns a
* pointer to PATH's leading slash inside `pattern`, or NULL when the pattern
* names neither a method nor a host before a slash (a plain "/v1/x" is NULL
* too: there is nothing to split). METHOD is a run of uppercase letters ended
* by spaces or tabs; it is copied to `method` (NUL-terminated, "" when the
* pattern names none) when `method` is non-NULL; a method that does not fit
* `method_sz` then makes the pattern NULL. The grammar is Go's: callers gate
* on the file language. */
const char *cbm_service_pattern_mux_split(const char *pattern, char *method, size_t method_sz);
/* The path of a ServeMux registration's pattern (#2537): only a callee ending
* ".Handle" or ".HandleFunc" registers one, and never with a URL ("://").
* Another route-verb call names no pattern: `store.Get("users/123")` is no
* host "users" + path "/123", `client.Get("https://...")` no host "https:".
* The split of cbm_service_pattern_mux_split for such a registration, else
* NULL. The grammar is Go's: callers gate on the file language. */
const char *cbm_service_pattern_mux_route_path(const char *callee_name, const char *pattern);
/* Get the broker name for an async QN (e.g., "pubsub" from a Pub/Sub QN).
* Returns NULL if not an async pattern. */
const char *cbm_service_pattern_broker(const char *resolved_qn);
/* GraphQL operation identity of a client call argument (#598).
* Scans `doc` as a GraphQL document (skipping comments, strings, `${...}`
* template interpolations and leading fragment definitions) and reports the
* first operation: *op_type is "query", "mutation" or "subscription" ("query"
* for the `{ ... }` shorthand). Returns true and writes the operation name to
* name_buf when the operation is named. Returns false for an anonymous
* operation, or with *op_type = "operation" when `doc` is not a GraphQL
* document (NULL, a URL, a bare word such as a dict key ...). The operation
* text itself is never copied, so callers can key Routes on a bounded
* identity. */
bool cbm_service_pattern_graphql_operation(const char *doc, const char **op_type, char *name_buf,
size_t name_sz);
#endif /* CBM_SERVICE_PATTERNS_H */