/* * 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 #include /* 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 */