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

67 KiB
Raw Blame History

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)                                          │   │
│  │   )                                                                          │   │
│  │                                                                               │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                                                                      │
└─────────────────────────────────────────────────────────────────────────────────────┘