mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-10 08:27:27 +00:00
5 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9772bcd24f
|
feat(api_impact): list the callers of the requesting function as indirect consumers (#3720)
* feat(api_impact): list the callers of the requesting function as indirect consumers The FETCHES edge is file-level, so api_impact saw only the file that sends the request. The files that call its request function never mention the URL and were missing from the report (#3644). The edge's reason now names the callables whose spans contain the request sites, one `|via:<id>` field each, under the containment rule the R3-6 sink set already uses; that rule moves into EnclosingCallableIndex so both stay one. Several sites of one file for one route now share the edge instead of colliding on its id. api_impact follows the CALLS edges into those callables one level up and reports the callers as `indirectConsumers`, apart from the direct consumers and outside the risk level. Direct consumer files and the handler file are left out. An index built before the attribution carries no field. Expo navigation sites carry their real line so they attribute to the component that contains them. Closes #3644 * fix(api_impact): attribute a request site by its AST enclosing callable A helper defined on the line of the request has the smaller span, so the line-only lookup named it and the callers of the real requesting function vanished from indirectConsumers. The parser now records the enclosing callable of each fetch site and of each wrapper call (through the call's position), and attribution prefers that identity; the span lookup remains for sites found by text scan. The same preference applies to the R3-6 sink set. A real analyze of the fixture followed by api_impact pins the helper case and the wrapper case. * test(bench): rebaseline receiver resolution for the indirect-consumers fixture The api-impact-indirect-consumers fixture adds three receiver-unresolved sites to the corpus: two `.then(...)` calls on the untyped return of `fetch(...)` and of the local wrapper `apiFetch(...)`, and one `req.query.path` read inside an inline Express handler with an untyped `req`. Call drops 138 -> 140, reads 30 -> 31, all kinds 168 -> 171. No shape-arm state and no existing site changed. * fix(api_impact): preserve module-scope request attribution Keep AST-confirmed module scope distinct from missing attribution for direct fetches, HTTP clients, and wrapper calls. Prevent overlapping callable spans from inventing indirect consumers or process sinks. Preserve span fallback for callable forms the generic identity walk cannot name. Add eight regression cases, including real analyze/api_impact coverage. Rebaseline receiver-resolution counts for the two then calls and one property read added by this PR's existing fixtures; shape expectations are unchanged. --------- Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |
||
|
|
f3fa67b144
|
fix(routes): link consumers to wrapper-composed URLs (#3697)
* fix(routes): resolve wrapper URL prefixes Carry proven URL composition through lexical bindings and wrapper calls so consumers match the runtime mount path. Refs #2858 * fix(review): apply review findings * fix(routes): address PR review feedback (#3697) * fix(routes): avoid native parent walks in URL facts --------- Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> |
||
|
|
01af833875
|
fix(scope): preserve lexical bindings in HTTP wrapper detection (#3632)
* docs(scope): clarify lexical binding ownership and wrapper provenance Checkpoint for #3630. Publishing the implemented source, regression tests, and benchmark harness as a draft PR; full-suite and final scaling validation remain in progress. * fix(scope): publish #3630 docs/plans * fix(scope): publish #3630 gitnexus/bench/lexical-binding-provenance * fix(scope): publish #3630 gitnexus/bench/lexical-binding-provenance/fixtures * fix(scope): publish #3630 gitnexus/bench/lexical-binding-provenance/results * fix(scope): publish #3630 gitnexus/src/core/ingestion * fix(scope): publish #3630 gitnexus/src/core/ingestion/languages/typescript * fix(scope): publish #3630 gitnexus/src/core/ingestion/languages * fix(scope): publish #3630 gitnexus/src/core/ingestion/pipeline-phases * fix(scope): publish #3630 gitnexus/src/core/ingestion/route-extractors * fix(scope): publish #3630 gitnexus/src/core/ingestion/workers * fix(scope): publish #3630 gitnexus/test/fixtures/lang-resolution/fetch-wrapper-target-identity/lib * fix(scope): publish #3630 gitnexus/test/fixtures/lang-resolution/fetch-wrapper-target-identity * fix(scope): publish #3630 gitnexus/test/fixtures/lang-resolution/fetch-wrapper-target-identity/packages/http * fix(scope): publish #3630 gitnexus/test/fixtures/lang-resolution/fetch-wrapper-target-identity/packages/http/src * fix(scope): publish #3630 gitnexus/test/fixtures/lang-resolution/fetch-wrapper-target-identity/server * fix(scope): publish #3630 gitnexus/test/fixtures/lang-resolution/fetch-wrapper-target-identity/web * fix(scope): publish #3630 gitnexus/test/integration/resolvers * fix(scope): publish #3630 gitnexus/test/unit * fix(scope): publish #3630 gitnexus/test/unit/group * fix(scope): publish #3630 gitnexus/test/unit/scope-resolution * fix(scope): publish #3630 gitnexus/test/unit/scope-resolution/typescript * fix(scope): publish #3630 gitnexus-shared/src/scope-resolution * fix(scope): treat wrapped assignment targets as writes `(app) = new Map()`, `(app as T) = x` and `app! = x` assign the same binding as `app = x`, but route-fact invalidation and the shared pattern walker stopped at the wrapper, so Express provenance survived the write and produced a false route. Recurse through parenthesized, as/satisfies and non-null targets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): resolve wrappers through overloads, declarator lists and barrels Three wrapper shapes lost their identity: - Bodyless overload signatures were indexed as separate definitions sharing the implementation's binding, so the binding looked ambiguous and both local and imported calls were rejected. Signatures now declare no callable. - Facts for `const base = 0, request = (url) => fetch(url)` followed the first declarator. The captured name now selects its own declarator. - An import resolved to a workspace barrel stopped at index.ts. Workers now record named, star and imported-then-exported re-exports, and resolution follows them to the declaring module: local and named exports shadow `export *`, star exports never carry `default`, and conflicting star exports block the name. No repository-wide name fallback is restored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(scope): assert closure ownership against the declaration The closure-write assertion compared one lookup with itself, which also passes when both are undefined. Compare it with the outer declaration and the shadowing parameter, and keep the memoization check explicit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(routes): share lexical helpers and release per-file HTTP contexts - Share binding keys, parameter patterns and transparent expression wrappers from lexical-bindings instead of four local copies; drop the unused moduleStem export; name the inferred-source predicates in lookup. - Key the per-file HTTP context by its tree rather than its ParsedFile. Workers retain ParsedFiles for the whole chunk, which kept every file's AST and traversal maps alive until the chunk flushed. - Index re-exports by name, memoize barrel walks per starting export, and keep facts without import targets as-is instead of copying them. - Move TS-only wrapper cases into the TS describe.each instead of branching inside the per-language loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): keep wrapper identity for HOCs, CommonJS, object keys and fetch packages Four definition shapes that main linked by name lost their wrapper identity: - `const load = useCallback((url) => fetch(url))` and curried HOCs produced no facts because definition lookup stopped at the call; it now follows the callable argument, as the structural definition capture does. - `module.exports = { request }`, `exports.x = …` and `module.exports.x = …` were not exports, so destructured `require` callers missed the wrapper. CommonJS export assignments are recorded when `module`/`exports` are the unshadowed globals, including functions defined inline in the export object. - An object-literal key or method name was resolved as a lexical binding and collided with a same-named module wrapper. Only binding identifiers now name a definition's binding. - `import fetch from 'node-fetch'` no longer counted as fetch. Imports of known fetch implementations (node-fetch, cross-fetch, isomorphic-fetch, the fetch member of undici and whatwg-fetch) are fetch evidence again; parameters and other local names still are not. Reference identifiers are also resolved only when their name is bound to a callable or class region; other identifiers cannot add a reachability edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(routes): drive the forwarding fallback case from data and cover re-export merges Replace the boolean-switched forwarding fallback case with table rows instead of branching inside the test, and assert that barrel re-export facts survive worker sub-batch merges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(bench): reject stale or dirty call-graph exports The committed comparison named a candidate revision that is not on this branch, and nothing stopped it. Comparison now requires both exports to come from clean checkouts and the candidate export to come from the checkout running the comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(bench): regenerate the call-graph comparison on the reviewed head Clean baseline |
||
|
|
aa33a6e94c
|
fix(routes): link base-URL fetch calls made through wrapper chains (#3628)
* fix(routes): link base-URL fetch calls made through wrapper chains (#3488) GitNexus's own web client calls `fetchWithTimeout(`${_backendUrl}/api/repos`)`, which reaches fetch through `resilientFetch` and a local `fetchImpl` alias. `api_impact` found none of those consumers, for three independent reasons: - normalizeFetchURL rejected any URL that did not start with `/`, so a leading base-URL binding dropped the call. It now strips a leading `${...}` run followed by `/`, with the same rules as the group layer's consumer normalizer (#3111); the helper moves to route-path.ts so both layers share it. A path whose every segment is a param (`${base}/${id}`, `${base}/${id}.json`) is rejected, since it would match every route of that depth. Interpolations are collapsed brace-balanced before the query split, so `${repo ? `?repo=${repo}` : ''}` no longer ends the path, and one glued to the last static segment is treated as a query or suffix. - The wrapper call collector required a `/`-leading literal, so the same template never became a wrapper candidate. - Wrapper detection only looked five AST levels deep for a call to an identifier named `fetch`. Arrow-const wrappers sit deeper than that, and `resilientFetch` calls an alias of `globalThis.fetch`. Detection now walks the whole definition and accepts `globalThis`/`window`/`self.fetch` and aliases whose value names fetch (through `??`, `||`, `?:`), read from the AST rather than the text. It records whether the first parameter reaches fetch's URL argument and which callees receive that parameter. The routes phase closes the wrapper set over that forwarding: `fetchWithTimeout` is a wrapper because it forwards its URL to `resilientFetch`. A callee declared in the caller's file or imported from a relative module must carry a URL in exactly that module; a package-imported name is followed only when every recorded function of that name carries one. A fetch caller whose first parameter is not the URL (`track(event)`) or a same-named function elsewhere (an IPC `request(channel)`) lends nothing. When `[param]` matches several sibling routes (`/api/analyze/upload` and `/api/analyze/:jobId`), the fetch now links to the route whose segments match by kind instead of the first one registered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): match wrapper calls by declaring module and decline ambiguous fetch matches Review follow-ups for #3488: - A propagated wrapper's name went into a repo-wide set, so a literal call to an unrelated same-named function in another module was taken as a fetch. Wrapper call candidates now carry the module declaring a bare callee when the file declares or imports it relatively, and must reach a wrapper defined in exactly that module. Package and member callees keep the name match. - An alias declared in a nested helper (`const fetchImpl = globalThis.fetch`) marked an outer call to a same-named parameter as a fetch. An alias now counts only where its declaring function encloses the call. - A first parameter redeclared inside the function (`{ const url = ...; fetch(url) }`) was taken as the URL. A shadowed parameter is no longer followed. - A fetch whose `[param]` ties between sibling static routes (`/api/kinds/foo`, `/api/kinds/bar`) linked to the first registered one. A tie now links none. - The fixture's `resilientFetch` returns the last response instead of rejecting with `undefined`, and its client encodes the repo query value. The release tool-accuracy gate now passes `api.template-wrapper`, so its known-gap allowance is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): keep call-site wrapper names and ignore helpers that never run - A wrapper call through a renamed relative import (`import { request as send }`) stored the exported name, so a configured `fetchWrappers` entry naming the call-site `send` no longer matched. The call keeps its call-site name and carries the declared name separately for the module lookup. - A nested helper bound to a local that is never referenced again (`const later = () => resilientFetch(url)`) made its enclosing function forward its URL. Calls inside such a helper are ignored; a helper that is called or passed on, such as a retry callback, still counts. - The fixture's `resilientFetch` no longer retries after a timeout or abort. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): let a nested parameter shadow a fetch alias A function parameter between a fetch alias and a call shadows the alias there (`function send(fetchImpl) { return fetchImpl(event) }` beside an outer `const fetchImpl = globalThis.fetch`), so that call no longer marks the enclosing function as a fetch wrapper. The fixture's retry helper also stops returning a stale 5xx response after a later attempt throws. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): drop fetch aliases whose name is redeclared with another value A block that redeclares an alias name with a non-fetch value (`{ const fetchImpl = other; fetchImpl('/x') }`) let the inner call read as a fetch. A name declared anywhere in the function with a value that does not name fetch is no longer an alias, which covers every block-scoped shadow without lexical scope tracking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(routes): ignore uncalled nested declarations and shadowed global objects - An uncalled nested `function helper() { fetch('/x') }` made its enclosing function a fetch wrapper. Nested function declarations that are never referenced are now ignored, as unused function-valued locals already were. - `window.fetch(url)` through a parameter or local named `window` (or `self`, `globalThis`) was read as the platform fetch. Such a root is now that value's method. A bare `fetch` parameter is still taken as fetch, since injecting a fetch implementation is the common reason for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(bench): refresh the receiver-resolution baseline for the fetch fixture The new `fetch-base-url-wrapper` fixture in `test/fixtures/lang-resolution` adds one unresolved TypeScript chain-field call to the committed check corpus (127 to 128 call drops). Regenerated with `measure.mjs --update-baseline` after a fresh build and cleared parse caches; no other counter moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |
||
|
|
b51f25606c
|
fix(routes): match configured fetch wrapper calls that pass type arguments (#3567)
Some checks failed
Devcontainer Smoke / Build devcontainer image (push) Has been cancelled
Devcontainer Smoke / Config-transform unit tests (push) Has been cancelled
Skill copy sync / shipped skills drift guard (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
|