Files
git.stella-ops.org/docs/reachability/function-level-evidence.md
StellaOps Bot 6e45066e37
Some checks failed
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
up
2025-12-13 09:37:15 +02:00

15 KiB

Function-Level Evidence Guide

Last updated: 2025-12-13. Owner: Docs Guild.

This guide documents the cross-module function-level evidence chain that enables provable reachability claims. It covers the schema, identifiers, API usage, CLI commands, and integration patterns for Scanner, Signals, Policy, and Replay.


1. Overview

StellaOps implements a function-level evidence chain that anchors every vulnerability finding to immutable identifiers (code_id, symbol_id, graph_hash) enabling:

  • Provable reachability: Deterministic call-path evidence from entry points to vulnerable functions.
  • Stripped binary support: code_id + code_block_hash provides identity when symbols are absent.
  • Evidence replay: Sealed artifacts with DSSE attestation allow offline verification.
  • Cross-module linking: Scanner -> Signals -> Policy -> VEX -> UI/CLI evidence chain.

1.1 Core Identifiers

Identifier Format Purpose Example
symbol_id sym:{lang}:{base64url} Canonical function identity sym:java:R3JlZXRpbmc...
code_id code:{lang}:{base64url} Identity for name-less code blocks code:binary:YWJjZGVm...
graph_hash blake3:{hex} Content-addressable graph identity blake3:a1b2c3d4e5f6...
symbol_digest sha256:{hex} Hash of symbol_id for edge linking sha256:e5f6a7b8c9d0...
build_id gnu-build-id:{hex} ELF/PE debug identifier gnu-build-id:5f0c7c3c...

1.2 Evidence Chain Flow

Scanner -> richgraph-v1 -> Signals -> Scoring -> Policy -> VEX -> UI/CLI
   |            |             |          |         |        |        |
   |            |             |          |         |        |        +-- stella graph explain
   |            |             |          |         |        +-- OpenVEX with call-path proofs
   |            |             |          |         +-- Policy gates + reachability.state
   |            |             |          +-- Lattice state + confidence + riskScore
   |            |             +-- Runtime facts + static paths
   |            +-- BLAKE3 graph_hash + DSSE attestation
   +-- code_id, symbol_id, build_id per node

2. Schema Reference

2.1 SymbolID Construction

Per-language canonical tuple format (NUL-separated, then SHA-256 -> base64url):

Language Tuple Components Example
Java {package}\0{class}\0{method}\0{descriptor} com.example\0Foo\0bar\0(Ljava/lang/String;)V
.NET {assembly}\0{namespace}\0{type}\0{member_signature} MyApp\0Controllers\0UserController\0GetById(int)
Go {module}\0{package}\0{receiver}\0{func} github.com/user/repo\0handler\0*Server\0Handle
Node {pkg_or_path}\0{export_path}\0{kind} lodash\0get\0function
Binary {file_hash}\0{section}\0{addr}\0{name}\0{linkage}\0{code_block_hash?} sha256:abc...\0.text\00x401000\0ssl3_read\0global\0
Python {pkg_or_path}\0{module}\0{qualified_name} requests\0api\0get
Ruby {gem_or_path}\0{module}\0{method} rails\0ActionController::Base\0render
PHP {composer_pkg}\0{namespace}\0{qualified_name} symfony/http-kernel\0Kernel\0handle

2.2 CodeID Construction

For stripped binaries or name-less code blocks:

code:{lang}:{base64url_sha256(format + file_hash + addr + length + section + code_block_hash)}

Example for stripped ELF:

code:binary:YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo

2.3 Graph Node Schema

Each node in a richgraph-v1 document includes:

{
  "id": "sym:java:R3JlZXRpbmdTZXJ2aWNl...",
  "symbol_id": "sym:java:R3JlZXRpbmdTZXJ2aWNl...",
  "code_id": "code:java:...",
  "lang": "java",
  "kind": "method",
  "display": "com.example.GreetingService.greet(String)",
  "purl": "pkg:maven/com.example/greeting-service@1.0.0",
  "build_id": "gnu-build-id:5f0c7c3c...",
  "symbol_digest": "sha256:e5f6a7b8...",
  "code_block_hash": "sha256:deadbeef...",
  "symbol": {
    "mangled": null,
    "demangled": "com.example.GreetingService.greet(String)",
    "source": "DWARF",
    "confidence": 0.98
  },
  "evidence": ["import", "bytecode"],
  "attributes": {}
}

2.4 Graph Edge Schema

Edges carry callee purl and symbol_digest for SBOM correlation:

{
  "from": "sym:java:caller...",
  "to": "sym:java:callee...",
  "kind": "call",
  "purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
  "symbol_digest": "sha256:f1e2d3c4...",
  "confidence": 0.92,
  "evidence": ["bytecode", "import"],
  "candidates": []
}

2.5 Evidence Block Schema

Evidence blocks in Policy/VEX responses cite all relevant identifiers:

{
  "evidence": {
    "graph_hash": "blake3:a1b2c3d4e5f6...",
    "graph_cas_uri": "cas://reachability/graphs/a1b2c3d4e5f6...",
    "dsse_uri": "cas://reachability/graphs/a1b2c3d4e5f6....dsse",
    "path": [
      {"symbol_id": "sym:java:...", "display": "main()"},
      {"symbol_id": "sym:java:...", "display": "processRequest()"},
      {"symbol_id": "sym:java:...", "display": "log4j.error()"}
    ],
    "path_length": 3,
    "confidence": 0.85,
    "runtime_hits": ["probe:jfr:1234"],
    "analyzer": {
      "name": "scanner.java",
      "version": "1.2.0",
      "toolchain_digest": "sha256:..."
    }
  }
}

3. API Usage

3.1 Signals Callgraph Ingestion

Submit a callgraph and receive a deterministic graph_hash:

POST /signals/callgraphs
Authorization: Bearer <token>
Content-Type: application/json

{
  "schema": "richgraph-v1",
  "analyzer": {"name": "scanner.java", "version": "1.2.0"},
  "nodes": [...],
  "edges": [...],
  "roots": [...]
}

Response:

{
  "graphHash": "blake3:a1b2c3d4e5f6...",
  "casUri": "cas://reachability/graphs/a1b2c3d4e5f6...",
  "dsseUri": "cas://reachability/graphs/a1b2c3d4e5f6....dsse",
  "nodeCount": 1247,
  "edgeCount": 3891
}

3.2 Signals Runtime Facts

Submit runtime observations with code_id anchors:

POST /signals/runtime-facts/ndjson?scanId=scan-123&imageDigest=sha256:abc123
Authorization: Bearer <token>
Content-Type: application/x-ndjson
Content-Encoding: gzip

{"symbolId":"sym:java:...","codeId":"code:java:...","hitCount":47,"loaderBase":"0x7f...","processId":1234,"observedAt":"2025-12-13T10:00:00Z"}
{"symbolId":"sym:java:...","codeId":"code:java:...","hitCount":12,"loaderBase":"0x7f...","processId":1234,"observedAt":"2025-12-13T10:00:01Z"}

Response:

{
  "accepted": 128,
  "duplicates": 2,
  "evidenceUri": "cas://reachability/runtime/sha256:xyz789..."
}

3.3 Fetch Reachability Facts

Query reachability state for a subject:

GET /signals/facts/{subjectKey}
Authorization: Bearer <token>

Response:

{
  "subjectKey": "scan:123:pkg:maven/log4j:2.14.1:CVE-2021-44228",
  "metadata": {
    "fact": {
      "digest": "sha256:abc123...",
      "version": 3
    }
  },
  "states": [
    {
      "symbol": "sym:java:...",
      "latticeState": "CR",
      "bucket": "runtime",
      "confidence": 0.92,
      "score": 0.78,
      "path": ["sym:java:main...", "sym:java:process...", "sym:java:log4j..."],
      "evidence": {
        "static": {"graphHash": "blake3:...", "pathLength": 3, "confidence": 0.85},
        "runtime": {"probeId": "probe:jfr:1234", "hitCount": 47, "observedAt": "2025-12-13T10:00:00Z"}
      }
    }
  ],
  "score": 0.78,
  "aggregateTier": "T2",
  "riskScore": 0.65
}

3.4 Policy Findings with Reachability Evidence

GET /api/policy/findings/{policyId}/{findingId}/explain?mode=verbose
Authorization: Bearer <token>

Response (excerpt):

{
  "findingId": "P-7:S-42:pkg:maven/log4j@2.14.1:CVE-2021-44228",
  "reachability": {
    "state": "CR",
    "confidence": 0.92,
    "evidence": {
      "graph_hash": "blake3:a1b2c3d4...",
      "path": [
        {"symbol_id": "sym:java:...", "display": "main()"},
        {"symbol_id": "sym:java:...", "display": "Logger.error()"}
      ],
      "runtime_hits": 47,
      "fact_digest": "sha256:abc123..."
    }
  },
  "steps": [
    {"rule": "reachability_gate", "state": "CR", "allowed": true},
    {"rule": "severity_baseline", "severity": {"normalized": "Critical", "score": 10.0}}
  ]
}

4. CLI Usage

4.1 Graph Explain Command

View the call path and evidence for a finding:

stella graph explain --finding "pkg:maven/log4j@2.14.1:CVE-2021-44228" --scan-id scan-123

# Output:
Finding: CVE-2021-44228 in pkg:maven/log4j@2.14.1
Reachability: CONFIRMED_REACHABLE (CR)
Confidence: 0.92
Graph Hash: blake3:a1b2c3d4e5f6...

Call Path (3 hops):
  1. main() [sym:java:R3JlZXRpbmcuLi4=]
     -> processRequest() [direct call]
  2. processRequest() [sym:java:cHJvY2Vzcy4uLg==]
     -> Logger.error() [virtual call]
  3. Logger.error() [sym:java:bG9nNGouLi4=]
     [VULNERABLE: CVE-2021-44228]

Runtime Evidence:
  - JFR probe hit: 47 times
  - Last observed: 2025-12-13T10:00:00Z

DSSE Attestation: cas://reachability/graphs/a1b2c3d4....dsse

4.2 Graph Export Command

Export a reachability graph for offline analysis:

stella graph export --scan-id scan-123 --output ./evidence-bundle/

# Creates:
# ./evidence-bundle/richgraph-v1.json       # Canonical graph
# ./evidence-bundle/richgraph-v1.json.dsse  # DSSE envelope
# ./evidence-bundle/meta.json               # Metadata
# ./evidence-bundle/runtime-facts.ndjson    # Runtime observations

4.3 Graph Verify Command

Verify a graph's DSSE signature and Rekor inclusion:

stella graph verify --graph ./evidence-bundle/richgraph-v1.json \
                    --dsse ./evidence-bundle/richgraph-v1.json.dsse \
                    --rekor-log

# Output:
Graph Hash: blake3:a1b2c3d4e5f6...
DSSE Signature: VALID (key: scanner-signing-2025)
Rekor Entry: 12345678 (verified)
Timestamp: 2025-12-13T09:30:00Z

5. OpenVEX Integration

5.1 OpenVEX with Reachability Evidence

When Policy emits VEX decisions, reachability evidence is included:

{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "@id": "https://stellaops.example/vex/2025-12-13/001",
  "author": "StellaOps Policy Engine",
  "timestamp": "2025-12-13T10:00:00Z",
  "version": 1,
  "statements": [
    {
      "vulnerability": {"@id": "CVE-2021-44228"},
      "products": [{"@id": "pkg:oci/myapp@sha256:abc123..."}],
      "status": "affected",
      "justification": "vulnerable_code_in_container",
      "impact_statement": "Vulnerable Log4j method reachable from main entry point.",
      "action_statement": "Upgrade to log4j 2.17.1 or later.",
      "stellaops:reachability": {
        "state": "CR",
        "confidence": 0.92,
        "graph_hash": "blake3:a1b2c3d4e5f6...",
        "path_length": 3,
        "evidence_uri": "cas://reachability/graphs/a1b2c3d4..."
      }
    }
  ]
}

5.2 VEX "not_affected" with Unreachability Evidence

When code is provably unreachable:

{
  "statements": [
    {
      "vulnerability": {"@id": "CVE-2023-XXXXX"},
      "products": [{"@id": "pkg:oci/myapp@sha256:abc123..."}],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path",
      "impact_statement": "Vulnerable function not reachable from any entry point.",
      "stellaops:reachability": {
        "state": "CU",
        "confidence": 0.88,
        "graph_hash": "blake3:d4e5f6a7b8c9...",
        "evidence_uri": "cas://reachability/graphs/d4e5f6a7b8c9...",
        "runtime_observation_window": "72h",
        "runtime_hits": 0
      }
    }
  ]
}

6. Replay Manifest v2

6.1 Manifest Structure

Replay manifests now enforce BLAKE3 hashing and CAS registration:

{
  "schema": "stellaops.replay.manifest@v2",
  "subject": "scan:123",
  "generatedAt": "2025-12-13T10:00:00Z",
  "hashAlg": "blake3",
  "artifacts": [
    {
      "kind": "richgraph",
      "uri": "cas://reachability/graphs/blake3:a1b2c3d4e5f6...",
      "hash": "blake3:a1b2c3d4e5f6...",
      "dsseUri": "cas://reachability/graphs/blake3:a1b2c3d4e5f6....dsse"
    },
    {
      "kind": "runtime-facts",
      "uri": "cas://reachability/runtime/sha256:xyz789...",
      "hash": "sha256:xyz789..."
    },
    {
      "kind": "sbom",
      "uri": "cas://scanner-artifacts/sbom.cdx.json",
      "hash": "sha256:def456..."
    }
  ],
  "analyzer": {
    "name": "scanner.java",
    "version": "1.2.0",
    "toolchain_digest": "sha256:..."
  },
  "code_id_coverage": {
    "total_symbols": 1247,
    "with_code_id": 1189,
    "coverage_pct": 95.3
  }
}

6.2 Determinism Verification

Replay a manifest to verify determinism:

stella replay verify --manifest ./manifest.json --sealed

# Output:
Manifest: stellaops.replay.manifest@v2
Subject: scan:123
Artifacts: 3

Verifying richgraph...
  Computed: blake3:a1b2c3d4e5f6...
  Expected: blake3:a1b2c3d4e5f6...
  Status: MATCH

Verifying runtime-facts...
  Computed: sha256:xyz789...
  Expected: sha256:xyz789...
  Status: MATCH

Verifying sbom...
  Computed: sha256:def456...
  Expected: sha256:def456...
  Status: MATCH

All artifacts verified. Determinism check PASSED.

7. Module Integration Guide

7.1 Scanner -> Signals

Scanner emits richgraph-v1 with code_id and symbol_id:

  1. Scanner analyzes container/artifact
  2. Callgraph generators emit nodes with symbol_id, code_id, build_id
  3. RichGraphWriter canonicalizes (sorted arrays/keys) and computes graph_hash (BLAKE3)
  4. DSSE signer wraps canonical JSON
  5. CAS store persists body + envelope
  6. Signals ingestion API receives URI reference

7.2 Signals -> Policy

Signals provides reachability facts to Policy:

  1. Policy queries /signals/facts/{subjectKey}
  2. Response includes metadata.fact.digest, states[], score
  3. Policy gates check latticeState (U, SR, SU, RO, RU, CR, CU, X)
  4. Evidence blocks in findings reference graph_hash, path[], runtime_hits[]

7.3 Policy -> VEX/UI

Policy emits OpenVEX with evidence:

  1. VexDecisionEmitter serializes OpenVEX with stellaops:reachability extension
  2. UI explain drawer fetches evidence via /api/policy/findings/{id}/explain
  3. CLI stella graph explain renders call path and attestation refs

8. CAS Layout Reference

cas://reachability/
  graphs/
    {blake3}/                    # Graph body (canonical JSON)
    {blake3}.dsse                # DSSE envelope
  edges/
    {graph_hash}/{bundle_id}     # Edge bundle body (optional)
    {graph_hash}/{bundle_id}.dsse
  runtime/
    {sha256}/                    # Runtime facts NDJSON


Last updated: 2025-12-13. See Sprint 0401 GAP-DOC-008 for change history.