Files
git.stella-ops.org/docs/product-advisories/25-Dec-2025 - Building a Deterministic Verdict Engine.md
StellaOps Bot 7792749bb4 feat: Add archived advisories and implement smart-diff as a core evidence primitive
- Introduced new advisory documents for archived superseded advisories, including detailed descriptions of features already implemented or covered by existing sprints.
- Added "Smart-Diff as a Core Evidence Primitive" advisory outlining the treatment of SBOM diffs as first-class evidence objects, enhancing vulnerability verdicts with deterministic replayability.
- Created "Visual Diffs for Explainable Triage" advisory to improve user experience in understanding policy decisions and reachability changes through visual diffs.
- Implemented "Weighted Confidence for VEX Sources" advisory to rank conflicting vulnerability evidence based on freshness and confidence, facilitating better decision-making.
- Established a signer module charter detailing the mission, expectations, key components, and signing modes for cryptographic signing services in StellaOps.
- Consolidated overlapping concepts from triage UI, visual diffs, and risk budget visualization advisories into a unified specification for better clarity and implementation tracking.
2025-12-26 13:01:43 +02:00

7.7 KiB
Raw Blame History

Building a Deterministic Verdict Engine

Status: PLANNED — Implementation in progress Date: 2025-12-25 Updated: 2025-12-26 Related Sprints: SPRINT_20251226_007_BE_determinism_gaps.md Merged Advisories: 25-Dec-2025 - Enforcing Canonical JSON for Stable Verdicts.md (SUPERSEDED)


Implementation Status

Component Status Location
Canonical JSON (JCS) COMPLETE StellaOps.Canonical.Json
NFC String Normalization COMPLETE StellaOps.Resolver.NfcStringNormalizer
Content-Addressed IDs COMPLETE Attestor.ProofChain/Identifiers/
DSSE Signing COMPLETE Signer/, Attestor/
Delta Verdict COMPLETE Policy/Deltas/DeltaVerdict.cs
Merkle Trees COMPLETE ProofChain/Merkle/
Determinism Guards COMPLETE Policy.Engine/DeterminismGuard/
Replay Manifest COMPLETE StellaOps.Replay.Core
Feed Snapshot Coordinator TODO SPRINT_20251226_007 DET-GAP-01..04
Keyless Signing TODO SPRINT_20251226_001
Cross-Platform Testing TODO SPRINT_20251226_007 DET-GAP-11..13

Overall Progress: ~85% complete


Advisory Content

Here's a tight, practical blueprint for evolving Stella Ops's policy engine into a fully deterministic verdict engine—so the same SBOM + VEX + reachability subgraph ⇒ the exact same, replayable verdict every time, with auditorgrade trails and signed "delta verdicts."

Why this matters (quick)

  • Reproducibility: auditors can replay any scan and get identical results.
  • Trust & scale: crossagent consensus via contentaddressed inputs and signed outputs.
  • Operational clarity: diffs between builds become crisp, machineverifiable artifacts.

Core principles

  • Determinism-first: no wallclock time, no random iteration order, no network during evaluation.
  • Contentaddressing: hash every input (SBOM, VEX docs, reachability subgraph, policy set, rule versions, feed snapshots).
  • Declarative state: a compact Scan Manifest lists input hashes + policy bundle hash + engine version.
  • Pure evaluation: the verdict function is referentially transparent: Verdict = f(Manifest).

Canonical JSON (Merged from Canonical JSON Advisory)

All JSON artifacts must use RFC 8785 JCS canonicalization with optional Unicode NFC normalization:

// Existing implementation
using StellaOps.Canonical.Json;

var canonical = CanonJson.Canonicalize(myObject);
var hash = CanonJson.Hash(myObject);
var versionedHash = CanonJson.HashVersioned(myObject, CanonVersion.V1);

Canonicalization Rules:

  1. Object keys sorted lexicographically (Ordinal)
  2. No whitespace or formatting variations
  3. UTF-8 encoding without BOM
  4. IEEE 754 number formatting
  5. Version markers for migration safety (_canonVersion: "stella:canon:v1")

Data artifacts

  • Scan Manifest (manifest.jsonc)

    • sbom_sha256, vex_set_sha256[], reach_subgraph_sha256, feeds_snapshot_sha256, policy_bundle_sha256, engine_version, policy_semver, options_hash
  • Verdict (verdict.json)

    • canonical JSON (stable key order); includes:
      • risk_score, status (pass/warn/fail), unknowns_count
      • evidence_refs: content IDs for cited VEX statements, nodes/edges from reachability, CVE records, featureflags, envguards
      • explanations: stable, templatedriven strings (+ machine reasons)
  • Delta Verdict (delta.json)

    • computed between two manifests/verdicts:
      • added_findings[], removed_findings[], severity_shift[], unknowns_delta, policy_effects[]
    • signed (DSSE/COSE/JWS), timestamped, and linkable to both verdicts

Engine architecture (deterministic path)

  1. Normalize inputs

    • SBOM: sort by packageUrl/name@version; resolve aliases; freeze semver comparison rules.
    • VEX: normalize provider → vex_id, product_ref, status (affected, not_affected, …), with source trust score precomputed from a trust registry (strict, versioned).
    • Reachability: store subgraph as adjacency lists sorted by node ID; hash after topological stable ordering.
    • Feeds: lock to a snapshot (timestamp + commit/hash); no live calls.
  2. Policy bundle

    • Declarative rules (e.g., lattice/merge semantics), compiled to a canonical IR (e.g., OPARego → sorted DNF).
    • Merge precedence is explicit (e.g., vendor > distro > internal can be replaced by a latticemerge table).
    • Unknowns policy baked in: e.g., fail_if_unknowns > N in prod.
  3. Evaluation

    • Build a finding set: (component, vuln, context) tuples with deterministic IDs.
    • Apply latticebased VEX merge (proofcarrying): each suppression must carry an evidence pointer (feature flag off, code path unreachable, patchedbackport proof).
    • Compute final status and risk_score using fixedprecision math; round rules are part of the bundle.
  4. Emit

    • Canonicalize verdict JSON; attach evidence map (content IDs only).
    • Sign verdict; attach as OCI attestation to image/digest.

APIs (minimal but complete)

  • POST /evaluate → returns verdict.json + attestation
  • POST /delta with {base_verdict, head_verdict}delta.json (signed)
  • GET /replay?manifest_sha= → reexecutes using cached snapshot bundles, returns the same verdict_sha
  • GET /evidence/:cid → fetches immutable evidence blobs (offlineready)

Storage & indexing

  • CAS (contentaddressable store): /evidence/<sha256> for SBOM/VEX/graphs/feeds/policies.
  • Verdict registry: keyed by (image_digest, manifest_sha, engine_version).
  • Delta ledger: appendonly, signed; supports crossagent consensus (multiple engines can cosign identical deltas).

UI slices (where it lives)

  • Run details → "Verdict" tab: status, risk score, unknowns, top evidence links.
  • "Diff" tab: render Delta Verdict (added/removed/changed), with drilldown to proofs.
  • "Replay" button: shows the exact manifest & engine version; oneclick reevaluation (offline possible).
  • Audit export: zip of manifest.jsonc, verdict.json, delta.json (if any), attestation, and referenced evidence.

Testing & QA (musthave)

  • Golden tests: fixtures of manifests → frozen verdict JSONs (byteforbyte).
  • Chaos determinism tests: vary thread counts, env vars, map iteration seeds; assert identical verdicts.
  • Crossengine roundtrips: two independent builds of the engine produce the same verdict for the same manifest.
  • Timetravel tests: replay older feed snapshots to ensure stability.

Rollout plan

  1. Phase 1: Introduce Manifest + canonical verdict format alongside existing policy engine (shadow mode).
  2. Phase 2: Make verdicts the firstclass artifact (OCIattached); ship UI "Verdict/Diff".
  3. Phase 3: Enforce deltagates in CI/CD (risk budgets + exception packs referenceable by content ID).
  4. Phase 4: Open consensus mode—accept externally signed identical delta verdicts to strengthen trust.

Notes for Stella modules

  • scanner.webservice: keep lattice algorithms here (per your standing rule). Concelier/Excitors "preserveprune source."
  • Authority/Attestor: handle DSSE signing, key management, regional crypto profiles (eIDAS/FIPS/GOST/SM).
  • Feedser/Vexer: produce immutable snapshot bundles; never query live during evaluation.
  • Router/Scheduler: schedule replay jobs; cache manifests to speed up audits.
  • Db: Postgres as SoR; Valkey only for ephemeral queues/caches (per your BSDonly profile).