Files
git.stella-ops.org/docs/technical/architecture/call-graph-analysis.md
StellaOps Bot 83c37243e0 save progress
2026-01-03 11:02:24 +02:00

603 lines
67 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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