# Call Graph Analysis Pipeline ## Overview This document describes the ReachGraph module's call graph construction, analysis, and reachability determination. The call graph connects static analysis (from SBOM/binaries) with dynamic observation (from runtime) to produce high-confidence reachability verdicts. --- ## Call Graph Construction ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ CALL GRAPH CONSTRUCTION PIPELINE │ └─────────────────────────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ INPUT SOURCES │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ SBOM │ │ Binaries │ │ Source Code │ │ Runtime │ │ │ │ (packages) │ │ (ELF/PE) │ │ (if avail) │ │ (hot syms) │ │ │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ Package Deps │ │ Symbol Tables │ │ Import/Call │ │ Observed │ │ │ │ (DEPENDS_ON) │ │ (exports, │ │ Extraction │ │ Invocations │ │ │ │ │ │ imports) │ │ │ │ │ │ │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │ │ │ │ │ │ │ └──────────────────┴──────────────────┴──────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────┐ │ │ │ GRAPH INDEXER │ │ │ │ (Node + Edge │ │ │ │ Construction) │ │ │ └────────────┬────────────┘ │ │ │ │ └──────────────────────────────────────┼──────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ GRAPH DATA MODEL │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ NODE TYPES │ │ │ │ │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ PackageNode │ │ FunctionNode │ │ FileNode │ │ │ │ │ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │ │ │ │ │ purl: string │ │ name: string │ │ path: string │ │ │ │ │ │ version: string │ │ signature: str │ │ hash: string │ │ │ │ │ │ ecosystem: str │ │ address: u64 │ │ language: str │ │ │ │ │ │ license: str │ │ package: ref │ │ loc: (start,end)│ │ │ │ │ └─────────────────┘ │ file: ref │ │ package: ref │ │ │ │ │ │ visibility: enum│ └─────────────────┘ │ │ │ │ │ is_entry: bool │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ EntryPointNode │ │ CVENode │ │ │ │ │ ├─────────────────┤ ├─────────────────┤ │ │ │ │ │ type: HTTP|CLI │ │ id: string │ │ │ │ │ │ |EVENT|... │ │ severity: enum │ │ │ │ │ │ function: ref │ │ cvss: f32 │ │ │ │ │ │ route: string │ │ affected: [ref] │ │ │ │ │ │ method: string │ │ fixed: string │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ EDGE TYPES │ │ │ │ │ │ │ │ ┌───────────────────────────────────────────────────────────────────┐ │ │ │ │ │ Edge Type │ Source │ Target │ Properties │ │ │ │ │ ├─────────────────┼─────────────────┼─────────────────┼─────────────┤ │ │ │ │ │ DEPENDS_ON │ Package │ Package │ scope, dev │ │ │ │ │ │ CONTAINS │ Package │ File │ │ │ │ │ │ │ DEFINES │ File │ Function │ line_start │ │ │ │ │ │ CALLS │ Function │ Function │ call_sites │ │ │ │ │ │ IMPORTS │ Package │ Package │ symbols[] │ │ │ │ │ │ ENTRY_FOR │ EntryPoint │ Function │ route │ │ │ │ │ │ AFFECTS │ CVE │ Package/Func │ version_rng │ │ │ │ │ │ OBSERVED │ Function │ Function │ count, ts │ │ │ │ │ └───────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Graph Construction by Source ### Package Dependency Graph ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ PACKAGE DEPENDENCY GRAPH CONSTRUCTION │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ Input: SBOM (CycloneDX or SPDX) │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ SBOM PARSING │ │ │ │ │ │ │ │ CycloneDX: SPDX: │ │ │ │ ───────────── ─────── │ │ │ │ { { │ │ │ │ "components": [ "packages": [ │ │ │ │ { { │ │ │ │ "purl": "pkg:npm/express@4.18", "SPDXID": "SPDXRef-...", │ │ │ │ "type": "library" "name": "express", │ │ │ │ } "versionInfo": "4.18" │ │ │ │ ], } │ │ │ │ "dependencies": [ ], │ │ │ │ { "relationships": [ │ │ │ │ "ref": "pkg:npm/express@4.18", { │ │ │ │ "dependsOn": [ "relationshipType": │ │ │ │ "pkg:npm/body-parser@1.20" "DEPENDS_ON", │ │ │ │ ] "spdxElementId": "...", │ │ │ │ } "relatedSpdxElement": "..."│ │ │ │ ] } │ │ │ │ } ] │ │ │ │ } │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ GRAPH CONSTRUCTION │ │ │ │ │ │ │ │ For each component/package: │ │ │ │ 1. Create PackageNode with PURL as ID │ │ │ │ 2. Parse version constraints │ │ │ │ 3. Identify ecosystem (npm, maven, pypi, etc.) │ │ │ │ │ │ │ │ For each dependency relationship: │ │ │ │ 1. Create DEPENDS_ON edge │ │ │ │ 2. Mark scope (compile, runtime, dev, optional) │ │ │ │ 3. Track transitive vs direct │ │ │ │ │ │ │ │ Result: │ │ │ │ │ │ │ │ [myapp@1.0] ─DEPENDS_ON─► [express@4.18] ─DEPENDS_ON─► [body-parser@1.20] │ │ │ │ │ │ │ │ │ │ │ └──DEPENDS_ON─► [accepts@1.3] │ │ │ │ │ │ │ │ │ └──DEPENDS_ON─► [lodash@4.17] │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` ### Binary Symbol Graph ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ BINARY SYMBOL GRAPH CONSTRUCTION │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ Input: ELF/PE/Mach-O binaries from container image │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ SYMBOL EXTRACTION │ │ │ │ │ │ │ │ ELF Binary: │ │ │ │ ──────────── │ │ │ │ │ │ │ │ .dynsym section: .symtab section (if not stripped): │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ │ │ Symbol │ Type │ Bind│ │ Symbol │ Type │ Bind│ │ │ │ │ ├──────────┼───────┼─────┤ ├──────────┼───────┼─────┤ │ │ │ │ │ malloc │ FUNC │ GLOB│ │ main │ FUNC │ GLOB│ │ │ │ │ │ printf │ FUNC │ GLOB│ │ helper │ FUNC │ LOCAL│ │ │ │ │ │ __libc.. │ FUNC │ WEAK│ │ ... │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ │ │ │ │ │ │ │ │ .plt / .got sections: DWARF debug info (if available): │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ │ │ External call targets │ │ DW_TAG_subprogram │ │ │ │ │ │ (imported functions) │ │ name: "processData" │ │ │ │ │ │ malloc@GLIBC_2.2.5 │ │ decl_file: "main.c" │ │ │ │ │ │ SSL_read@OPENSSL_1_1 │ │ decl_line: 42 │ │ │ │ │ └─────────────────────────┘ │ low_pc: 0x1234 │ │ │ │ │ └─────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ CALL EDGE EXTRACTION │ │ │ │ │ │ │ │ For each function in binary: │ │ │ │ 1. Disassemble function body │ │ │ │ 2. Identify CALL/JMP instructions │ │ │ │ 3. Resolve call targets: │ │ │ │ - Direct calls: target address → symbol lookup │ │ │ │ - Indirect calls: [reg] or [mem] → mark as dynamic │ │ │ │ - PLT calls: resolve to external library symbol │ │ │ │ │ │ │ │ Example disassembly: │ │ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ processData: │ │ │ │ │ │ 0x1234: push rbp │ │ │ │ │ │ 0x1235: mov rbp, rsp │ │ │ │ │ │ ... │ │ │ │ │ │ 0x1250: call 0x4567 ; → resolves to validate() │ │ │ │ │ │ 0x1255: call 0x89ab@plt ; → resolves to SSL_read (extern) │ │ │ │ │ │ 0x125a: call [rax] ; → indirect call (unknown target) │ │ │ │ │ │ ... │ │ │ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Produces edges: │ │ │ │ [processData] ─CALLS─► [validate] (static, direct) │ │ │ │ [processData] ─CALLS─► [SSL_read] (static, external) │ │ │ │ [processData] ─CALLS─► [?] (dynamic, unresolved) │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` ### Source Code Analysis ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ SOURCE CODE CALL GRAPH EXTRACTION │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ When source code is available (e.g., interpreted languages), extract calls │ │ using language-specific parsers: │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ LANGUAGE-SPECIFIC EXTRACTION │ │ │ │ │ │ │ │ JavaScript/TypeScript: │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ // source.js │ │ │ │ │ │ const lodash = require('lodash'); │ │ │ │ │ │ const result = lodash.template(input); // ← call site │ │ │ │ │ │ │ │ │ │ │ │ Produces: │ │ │ │ │ │ [source.js:render] ─CALLS─► [lodash:template] │ │ │ │ │ │ [source.js] ─IMPORTS─► [lodash] │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Python: │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ # app.py │ │ │ │ │ │ import pickle │ │ │ │ │ │ data = pickle.loads(user_input) # ← dangerous call │ │ │ │ │ │ │ │ │ │ │ │ Produces: │ │ │ │ │ │ [app.py:process] ─CALLS─► [pickle:loads] │ │ │ │ │ │ [app.py] ─IMPORTS─► [pickle] │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Java: │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ // Service.java │ │ │ │ │ │ import org.apache.logging.log4j.Logger; │ │ │ │ │ │ logger.info("User: " + userInput); // ← CVE-2021-44228 │ │ │ │ │ │ │ │ │ │ │ │ Produces: │ │ │ │ │ │ [Service:handle] ─CALLS─► [Logger:info] │ │ │ │ │ │ [Service] ─IMPORTS─► [org.apache.logging.log4j] │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Graph Analytics Engine ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ GRAPH ANALYTICS ENGINE │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ LABEL PROPAGATION CLUSTERING │ │ │ │ │ │ │ │ Purpose: Group related packages/functions for impact analysis │ │ │ │ │ │ │ │ Algorithm: │ │ │ │ 1. Initialize: each node gets unique label │ │ │ │ 2. Iterate: each node adopts most common neighbor label │ │ │ │ 3. Converge: when labels stabilize │ │ │ │ │ │ │ │ Result: Clusters of tightly connected packages/functions │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ Cluster A (HTTP handling): Cluster B (Data processing): │ │ │ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ │ │ │ │ express │ │ lodash │ │ │ │ │ │ │ │ body-parser │ │ underscore │ │ │ │ │ │ │ │ cookie-parser │ │ ramda │ │ │ │ │ │ │ └─────────────────────┘ └─────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ Use case: "If CVE affects lodash, which other packages are │ │ │ │ │ │ in the same processing cluster and might be impacted?" │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ BETWEENNESS CENTRALITY │ │ │ │ │ │ │ │ Purpose: Identify critical nodes (bottlenecks, high-impact) │ │ │ │ │ │ │ │ Formula: C_B(v) = Σ (σ_st(v) / σ_st) │ │ │ │ Where: │ │ │ │ σ_st = number of shortest paths from s to t │ │ │ │ σ_st(v) = number of those paths passing through v │ │ │ │ │ │ │ │ High centrality nodes: │ │ │ │ • Commonly used utility functions (lodash.get, axios.request) │ │ │ │ • Core framework methods (express.Router) │ │ │ │ • Logging/serialization functions │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ [EntryPoint] ──► [auth.validate] ──► [user.fetch] ──► [db.query] │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ │ │ │ │ └────────► [logging.info] ◄─────────┴───────────────┘ │ │ │ │ │ │ ▲ │ │ │ │ │ │ HIGH CENTRALITY │ │ │ │ │ │ (many paths pass through) │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Reachability Analysis ### BFS Path Finding ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ REACHABILITY SLICE SERVICE │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ BFS TRAVERSAL ALGORITHM │ │ │ │ │ │ │ │ Query: "Find all paths from entry points to vulnerable function" │ │ │ │ │ │ │ │ function findReachablePaths(graph, target_func, max_depth=10): │ │ │ │ paths = [] │ │ │ │ queue = [(entry, [entry]) for entry in graph.entry_points] │ │ │ │ visited = set() │ │ │ │ │ │ │ │ while queue: │ │ │ │ node, path = queue.pop(0) │ │ │ │ if len(path) > max_depth: │ │ │ │ continue │ │ │ │ │ │ │ │ if node == target_func: │ │ │ │ paths.append(path) │ │ │ │ continue │ │ │ │ │ │ │ │ if node in visited: │ │ │ │ continue │ │ │ │ visited.add(node) │ │ │ │ │ │ │ │ for edge in graph.outgoing_edges(node, type=CALLS): │ │ │ │ queue.append((edge.target, path + [edge.target])) │ │ │ │ │ │ │ │ return paths │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ SLICE TYPES │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ CVE Slice │ │ │ │ │ │ │ │ │ │ │ │ Input: CVE-2021-23337 (lodash template injection) │ │ │ │ │ │ │ │ │ │ │ │ Steps: │ │ │ │ │ │ 1. Find affected function: lodash.template │ │ │ │ │ │ 2. BFS from all entry points │ │ │ │ │ │ 3. Collect all paths reaching lodash.template │ │ │ │ │ │ │ │ │ │ │ │ Output: │ │ │ │ │ │ [ │ │ │ │ │ │ { path: [main.handler → render.compile → lodash.template], │ │ │ │ │ │ depth: 2, entry_type: HTTP }, │ │ │ │ │ │ { path: [cli.process → template.render → lodash.template], │ │ │ │ │ │ depth: 2, entry_type: CLI } │ │ │ │ │ │ ] │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ Package Slice │ │ │ │ │ │ │ │ │ │ │ │ Input: pkg:npm/lodash@4.17.20 │ │ │ │ │ │ │ │ │ │ │ │ Steps: │ │ │ │ │ │ 1. Find all functions in package │ │ │ │ │ │ 2. BFS from all entry points to any package function │ │ │ │ │ │ 3. Group by function │ │ │ │ │ │ │ │ │ │ │ │ Output: │ │ │ │ │ │ { │ │ │ │ │ │ "lodash.get": { reachable: true, paths: [...] }, │ │ │ │ │ │ "lodash.set": { reachable: true, paths: [...] }, │ │ │ │ │ │ "lodash.template": { reachable: true, paths: [...] }, │ │ │ │ │ │ "lodash.chunk": { reachable: false } │ │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ Entry Point Slice (Forward) │ │ │ │ │ │ │ │ │ │ │ │ Input: HTTP /api/v1/render endpoint │ │ │ │ │ │ │ │ │ │ │ │ Steps: │ │ │ │ │ │ 1. Start from entry point function │ │ │ │ │ │ 2. BFS forward through all CALLS edges │ │ │ │ │ │ 3. Mark all reachable functions │ │ │ │ │ │ │ │ │ │ │ │ Output: Set of all functions reachable from this endpoint │ │ │ │ │ │ (Used for "attack surface" analysis) │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` ### Eight-State Reachability Lattice ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 8-STATE REACHABILITY LATTICE │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ STATE HIERARCHY │ │ │ │ │ │ │ │ ┌─────────────────────────┐ │ │ │ │ │ LiveExploitPath │ HIGHEST │ │ │ │ │ (Confirmed exploitable │ CONFIDENCE │ │ │ │ │ with runtime proof) │ │ │ │ │ └────────────┬────────────┘ │ │ │ │ │ │ │ │ │ ┌────────────▼────────────┐ │ │ │ │ │ DynamicReachable │ │ │ │ │ │ (Observed at runtime │ │ │ │ │ │ via eBPF/hot symbols) │ │ │ │ │ └────────────┬────────────┘ │ │ │ │ │ │ │ │ │ ┌────────────▼────────────┐ │ │ │ │ │ StaticReachable │ │ │ │ │ │ (Call path found via │ │ │ │ │ │ static analysis) │ │ │ │ │ └────────────┬────────────┘ │ │ │ │ │ │ │ │ │ ┌────────────▼────────────┐ │ │ │ │ │ PotentiallyReachable │ │ │ │ │ │ (Import exists but no │ │ │ │ │ │ direct call found) │ │ │ │ │ └────────────┬────────────┘ │ │ │ │ │ │ │ │ │ ┌────────────▼────────────┐ │ │ │ │ │ Unknown │ DEFAULT │ │ │ │ │ (Insufficient data │ STATE │ │ │ │ │ to determine) │ │ │ │ │ └────────────┬────────────┘ │ │ │ │ │ │ │ │ │ ┌───────────────────────┼───────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌────────▼────────┐ ┌───────▼───────┐ │ │ │ │ │ NotReachable│ │ GateBlocked │ │ NotApplicable │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Static │ │ Dead code path │ │ Language/OS │ │ │ │ │ │ analysis │ │ (ifdef, feature │ │ mismatch │ │ │ │ │ │ proves no │ │ flag disabled) │ │ │ │ │ │ │ │ path exists │ │ │ │ │ │ │ │ │ └─────────────┘ └─────────────────┘ └───────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ STATE DETERMINATION LOGIC │ │ │ │ │ │ │ │ function determineReachabilityState( │ │ │ │ static_paths: Path[], │ │ │ │ runtime_observations: Observation[], │ │ │ │ exploit_proofs: Proof[], │ │ │ │ platform_match: bool, │ │ │ │ gate_status: GateStatus │ │ │ │ ) -> ReachabilityState: │ │ │ │ │ │ │ │ if not platform_match: │ │ │ │ return NotApplicable │ │ │ │ │ │ │ │ if gate_status == BLOCKED: │ │ │ │ return GateBlocked │ │ │ │ │ │ │ │ if exploit_proofs: │ │ │ │ return LiveExploitPath │ │ │ │ │ │ │ │ if runtime_observations: │ │ │ │ return DynamicReachable │ │ │ │ │ │ │ │ if static_paths: │ │ │ │ return StaticReachable │ │ │ │ │ │ │ │ if import_exists: │ │ │ │ return PotentiallyReachable │ │ │ │ │ │ │ │ if no_path_proven: │ │ │ │ return NotReachable │ │ │ │ │ │ │ │ return Unknown │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Graph Snapshot and Determinism ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ GRAPH SNAPSHOT DETERMINISM │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────┐ │ │ │ GraphSnapshotBuilder │ │ │ │ │ │ │ │ Purpose: Create deterministic, hashable graph snapshots for: │ │ │ │ • Audit trails (prove analysis was consistent) │ │ │ │ • Caching (skip re-analysis if inputs unchanged) │ │ │ │ • DSSE attestation (sign analysis results) │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ Determinism Rules: │ │ │ │ │ │ │ │ │ │ │ │ 1. Node ordering: sorted by (type, purl/name, version) │ │ │ │ │ │ 2. Edge ordering: sorted by (type, source_id, target_id) │ │ │ │ │ │ 3. Property ordering: sorted alphabetically │ │ │ │ │ │ 4. Timestamps: ISO-8601 UTC (no local timezone) │ │ │ │ │ │ 5. Floating point: fixed precision (6 decimal places) │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Snapshot Structure: │ │ │ │ │ │ │ │ { │ │ │ │ "version": "1.0", │ │ │ │ "created_at": "2024-12-29T10:30:00Z", │ │ │ │ "image_digest": "sha256:abc...", │ │ │ │ "nodes": [ ... ], // sorted │ │ │ │ "edges": [ ... ], // sorted │ │ │ │ "reachability": { ... }, // computed states │ │ │ │ "hash": "sha256:snapshot_hash..." │ │ │ │ } │ │ │ │ │ │ │ │ Hash computation: │ │ │ │ hash = SHA256( │ │ │ │ canonical_json(nodes) || │ │ │ │ canonical_json(edges) || │ │ │ │ canonical_json(reachability) │ │ │ │ ) │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Related Documentation - [Policy Engine Data Pipeline](policy-engine-data-pipeline.md) - How reachability feeds policy - [Runtime Agents Architecture](runtime-agents-architecture.md) - Runtime observation - [Binary Analysis](../../modules/binary-index/architecture.md) - Binary symbol extraction - [ReachGraph Module](../../modules/reachgraph/architecture.md) - ReachGraph dossier - [Policy Evaluation Flow](../../flows/04-policy-evaluation-flow.md) - K4 lattice usage