跳到主要内容
RAGRAF

The CPG layer: Joern, interprocedural calls and honest degradation

What Joern (php2cpg) adds, the 12 CPG facts, the torch.sparse backend, the degraded contract, and why a missing Joern is a mode — not an accident.

本文尚未翻译成当前语言——正在显示 English.

Why a separate layer is needed #

tree-sitter gives intra-file syntax: symbols, calls within a file, SQL literals. But the agent's real questions are interprocedural: "what is reachable from this point", "does the approval route break". For PHP this hurts especially: dynamics (call_user_func, magic methods, include chains) make static reachability nontrivial. RAGRAF does not reinvent an analyzer — it plugs in Joern (Code Property Graph) as an optional L1 extractor and wraps it in its own contract.

What exactly gets added #

Pipeline stage 5 (cpg) starts the Joern server (localhost:9500, auto start/stop) and imports into graph.sqlite:

ArtifactContents
Interprocedural CALL edgescalls across file boundaries — what tree-sitter cannot see
cfg_edge / dfg_edgecontrol and data flows inside functions (groundwork for taint analysis — see future)
12 CPG coverage factswhich files/functions are CPG-covered, by which parser (php2cpg), layer version
joern_used on the revision1/0 — a flag visible in status and the panel; never "implied"

On the pilot corpus (123 PHP files) the CPG stage took 64 s of the 71 s full indexing run — Joern dominates the time, which is why it is optional and switchable (joern_enabled: false).

slice: the only CPG operation #

slice is an interprocedural slice (up/down the flows from a symbol, configurable depth). It is the only operation requiring capability=full. The degradation contract:

Text
$ ragraf -p cfg query slice --name markPaid
exit 3
{"op":"slice","capability":"degraded",
 "reason":"CPG layer unavailable: Joern not installed",
 "suggest":"install-joern.ps1 -Download, or use callers/impact (tree-sitter graph)"}

A refusal with a reason and a suggestion — instead of an empty result the agent would take for "no dependencies". Anti-requirement #4 in action.

The algorithmic backend: torch.sparse #

CPG traversal (reachability, slices) is implemented in graph_algo.py with three backends and an honest cascade:

BackendConditionCharacter
torch-gputorch + CUDA available, graph above the thresholdCSR representation on GPU; batch traversals
torch-cputorch availablethe same code, CPU tensors
noneno torchpure Python/SQLite traversal — slower but always works

The selected backend is written into the revision metadata (reason field), never implied. An honest detail: the CSR representation limits on-the-fly graph mutations — a CPG rebuild is a full pass (Joern has no incremental CPG). The tensor-path switch threshold is ~5,000 vertices (see gpu-compute).

Installation and weight #

PowerShell
./scripts/install-joern.ps1 -Download   # downloads the distribution, verifies SHA-256, restores the environment on failure

Requires JDK 21 + Joern (~5–6 GB). The installer checks the archive hash (protection against corrupted/tampered downloads) and restores the previous state on error — the pipe-deadlock and missing-timeout defects were closed by the refactor (INSTALLER-REFACTOR-NOTES).

Layer boundaries #

  • PHP-first: php2cpg is verified on PHP corpora; for other languages the CPG is experimental (Joern supports many, but RAGRAF's contract is verified on PHP).
  • Dynamics stay dynamic: call_user_func chains are not magically resolved by Joern either — derived edges with confidence 0.60 in a separate answer block (see operations).
  • Taint analysis is not included: CFG/DFG facts live in the graph as groundwork; product taint operations do not exist in v0.1.0 — a conscious release boundary and the first major future direction (future).
  • Dependencies are not declared in pyproject: torch/Joern are external optional components; formalizing extras (pip install ragraf[gpu]) is roadmap item R-PKG-1.

Related: GPU compute → · architecture → · future directions →