Skip to content

fix(resolver): scope registry rehydrate to the indexed project (#711)#727

Merged
vitali87 merged 1 commit into
mainfrom
fix/711-cross-project-resolution-leak
Jul 12, 2026
Merged

fix(resolver): scope registry rehydrate to the indexed project (#711)#727
vitali87 merged 1 commit into
mainfrom
fix/711-cross-project-resolution-leak

Conversation

@vitali87

Copy link
Copy Markdown
Owner

Summary

Fixes #711. When more than one project shared a Memgraph database, indexing project A could resolve unqualified / bare-name calls into a same-named definition in an unrelated project B, producing wrong cross-project CALLS edges and (with the io capture group) wrong cross-project FLOWS_TO taint edges.

Root cause

_rehydrate_registry_from_graph runs on every non---clean run and re-registers every definition qualified name from the graph into the in-memory resolver trie. The three queries it uses (CYPHER_ALL_DEFINITION_QNS, CYPHER_ALL_MODULE_QNS, CYPHER_ALL_INHERITS) had no project filter, so the trie built while indexing one project was polluted with every other project's symbols. The call resolver's bare-name fallback then bound an unqualified call in A to another project's symbol.

Fix

Scope all three rehydrate queries to the project being indexed with a $project_prefix (<project_name>.) STARTS WITH filter, threaded through as a query param. The rehydrate exists to restore edges into unchanged files of the same project (issue #532); cross-project symbols never belonged in the trie. Real cross-project links still flow through actual IMPORTS edges, not the bare-name fallback.

Test (RED → GREEN)

New integration test test_cross_project_resolution_e2e.py reproduces the issue's exact scenario: index collide (defines bare len/getenv) then caller (calls len(t) on a tainted value) into one DB, and asserts zero caller.* -> collide.* edges. Confirmed RED before the fix (3 leaked edges: two CALLS, one FLOWS_TO) and GREEN after.

Full suite: 5021 passed, 10 skipped. ruff + ty clean.

@greptile-apps

greptile-apps Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR limits resolver rehydration to the project being indexed. The main changes are:

  • Adds $project_prefix filters to definition, module, and inheritance rehydration Cypher queries.
  • Passes the current project prefix into the registry and class-inheritance rehydration calls.
  • Adds an integration test for shared Memgraph databases with colliding bare names across projects.
  • Bumps the editable package version in uv.lock.

Confidence Score: 5/5

Safe to merge with minimal risk.

The change is narrow, uses the existing project-prefix pattern, and includes focused regression coverage for the reported cross-project leakage path.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • The initial integration attempt failed because essential cmake tooling was inaccessible, blocking the pymgclient build.
  • A separate environment check confirmed that docker, cmake, cmake3, memgraph, and java commands were not available in the container.
  • A fallback green run was executed, and Ruff completed with All checks passed and exit code 0.
  • A type-check pass using ty was attempted, but dependencies could not be resolved in the no-project environment, producing two project_params type diagnostics.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
codebase_rag/constants/graph.py Scopes registry, module, and inheritance rehydration Cypher queries with a project prefix so only symbols from the indexed project are restored.
codebase_rag/graph_updater.py Threads the current project's qualified-name prefix into all rehydration queries before rebuilding resolver state.
codebase_rag/tests/integration/test_cross_project_resolution_e2e.py Adds an integration regression test proving shared-database indexing does not create caller-to-collide cross-project CALLS or FLOWS_TO edges.
uv.lock Updates the editable package version from 0.0.315 to 0.0.316 without changing third-party dependencies.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant GU as GraphUpdater
participant DB as Memgraph
participant FR as Resolver registry
participant DP as Definition processor

GU->>GU: "Build project_prefix = project_name + \".\""
GU->>DB: Fetch definition QNs where qualified_name STARTS WITH project_prefix
DB-->>GU: Same-project definitions only
GU->>FR: Re-register missing same-project symbols
GU->>DB: Fetch module QNs where qualified_name STARTS WITH project_prefix
DB-->>GU: Same-project modules only
GU->>DP: Restore module/interface targets
GU->>DB: Fetch INHERITS where child qualified_name STARTS WITH project_prefix
DB-->>GU: Same-project inheritance rows
GU->>DP: Restore class inheritance for unchanged same-project files
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant GU as GraphUpdater
participant DB as Memgraph
participant FR as Resolver registry
participant DP as Definition processor

GU->>GU: "Build project_prefix = project_name + \".\""
GU->>DB: Fetch definition QNs where qualified_name STARTS WITH project_prefix
DB-->>GU: Same-project definitions only
GU->>FR: Re-register missing same-project symbols
GU->>DB: Fetch module QNs where qualified_name STARTS WITH project_prefix
DB-->>GU: Same-project modules only
GU->>DP: Restore module/interface targets
GU->>DB: Fetch INHERITS where child qualified_name STARTS WITH project_prefix
DB-->>GU: Same-project inheritance rows
GU->>DP: Restore class inheritance for unchanged same-project files
Loading

Reviews (1): Last reviewed commit: "fix(resolver): scope registry rehydrate ..." | Re-trigger Greptile

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request scopes the rehydration of the in-memory function registry, module names, and class inheritance to the specific project being indexed by filtering Cypher queries with a $project_prefix. This prevents symbols from other projects in a shared database from polluting the resolver trie and causing cross-project leaks during incremental runs. An integration test has been added to verify this behavior, and the package version has been bumped in uv.lock. There are no review comments, so I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@sonarqubecloud

Copy link
Copy Markdown

@vitali87 vitali87 merged commit 08a984b into main Jul 12, 2026
22 checks passed
@vitali87 vitali87 deleted the fix/711-cross-project-resolution-leak branch July 12, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Cross-project call resolution leaks bare-name calls (and FLOWS_TO taint) between projects sharing one database

1 participant