Here’s a compact, implementation‑ready blueprint to make your scanner’s results quiet, explainable, and auditable end‑to‑end. # Phase the “proof spine” 1. **SBOM‑only → VEX‑ready → Attested** * **SBOM (now):** Generate SPDX 3.0.1 + CycloneDX 1.6 for every image/module. Include purls, CPE (if available), license IDs, source URIs, and build metadata. * **VEX‑ready (next):** Normalize vuln inputs (OSV, GHSA, vendor feeds) to a single internal model; keep fields needed for VEX (status, justification, impact, action, timestamp, issuer). * **Attest (then):** Emit **in‑toto/DSSE** attestations that bind: (a) SBOM digest, (b) ruleset version, (c) data sources & hashes, (d) VEX decisions. Log statement references in **Rekor** (or your mirror) for transparency. # Explainability path (per alert) For every surfaced finding, materialize: * **Origin SBOM node** → component@version (with purl/CPE) * **Match rule** → which matcher hit (name+version, range, CPE heuristics, source trust) * **VEX gate** → decision with justification (e.g., affected/not_affected, component_not_present, configuration_needed) * **Reachability trace** → static (call graph path) and/or runtime (probe hits) to the vulnerable symbol(s) * **Deterministic score** → numeric risk built from stable inputs (below) Expose this as a single JSON object and a short, human‑readable proof block in the UI/CLI. # Smart‑Diff (incremental analysis) * **Change detector:** hash symbols/packages and dependency graphs; on new scans, diff against prior state. * **Selective re‑analysis:** only re‑parse/re‑solve changed modules, lockfiles, or call‑graph regions. * **Memoized match & reachability:** cache vuln matches and reachability slices per (component, version, framework‑model) key. # Scoring (quiet by design) Use stable, auditable inputs: * **Base:** CVSS v4.0 metrics (as provided by source), fall back to v3.1 if v4 missing. * **Exploit maturity:** explicit flags when present (known exploited, PoC available, none). * **Reachability boost/penalty:** function‑level confirmation > package‑level guess; runtime evidence > static‑only. * **Compensating controls:** WAF/feature flags/sandboxing recorded as gates that reduce surfaced priority (but never erase provenance). # Minimal data contracts (copy‑paste into your code) **SBOM node (core):** ```json { "purl": "pkg:npm/lodash@4.17.21", "hashes": [{"alg":"sha256","value":"..."}], "licenses": ["MIT"], "build": {"sourceUri":"git+https://...","commit":"..."}, "attestations": [{"type":"intoto","subjectDigest":"sha256:..."}] } ``` **Finding proof (per alert):** ```json { "id": "FND-abc123", "component": {"purl":"pkg:maven/org.example/foo@1.2.3"}, "vuln": {"id":"CVE-2024-XXXX","source":"OSV"}, "matchRule": {"name":"purl-eq","details":{"range":"[1.2.0,1.2.5)"}}, "vexGate": {"status":"affected","justification":"reachable_code_path"}, "reachability": { "staticPath": ["Controller.handle","Service.parse","lib/vulnFunc"], "runtimeHits": [{"symbol":"lib/vulnFunc","count":37}] }, "score": {"base":7.1,"exploit":"poc","reach":"function","final":8.4}, "provenance": { "sbomDigest":"sha256:...", "ruleset":"signals-1.4.2", "feeds":[{"name":"OSV","etag":"..."}], "attRef":"rekor:sha256:..." } } ``` # Services & where they live in Stella Ops * **Sbomer**: Syft‑backed generators (SPDX/CycloneDX) + DSSE signing. * **Feedser/Concelier**: fetch & normalize vuln feeds (OSV/GHSA/vendor), maintain trust scores; “preserve‑prune source” rule stays. * **Scanner.WebService**: orchestrates analyzers; run lattice algorithms here (per your standing rule). * **Vexer/Excititor**: VEX issuance + policy evaluation (lattice gates). * **Authority**: key management, DSSE signing, Rekor client (and mirror) endpoints. * **Signals**: event‑sourced store for proofs, reachability artifacts, and scoring outputs. # Policies (tiny DSL sketch) ```yaml version: 1 sources: - id: osv trust: 0.9 gates: - id: not-present when: component.present == false action: vex(status: not_affected, reason: component_not_present) - id: unreachable when: reachability.static == false and reachability.runtime == false action: vex(status: not_affected, reason: vulnerable_code_not_in_execute_path) scoring: base: cvss.v4 or cvss.v3 adjust: - if: exploit.maturity in ["known_exploited","poc"] add: 0.8 - if: reachability.function_confirmed add: 1.1 - if: gate == "not-present" subtract: 3.0 ``` # Attestations & transparency (pragmatic path) * **Produce** DSSE‑wrapped in‑toto statements for SBOM, ScanResult, and VEXBundle. * **Record** statement digests in Rekor (or your **Proof‑Market** mirror) with pointers back to your artifact store. * **Bundle** offline kits with SBOM+VEX+attestations and a mini‑Rekor log segment for air‑gapped audits. # UX: one‑screen truth * Table of findings with **Final Score**, a **“Why?”** button expanding the 5‑part proof chain, and **Fix** suggestions. * Global toggles: *Show only reachable*, *Mute not‑affected*, *Show deltas* (Smart‑Diff), *Export VEX*. # “Done next” checklist * Wire Syft→SPDX/CycloneDX→DSSE emit → Rekor client. * Normalize feeds to a single vuln model with trust weights. * Implement **FindingProof** schema and persist it in Signals. * Add **Symbolizer + per‑lang reachability** stubs (even minimal) to populate `reachability` fields. * Ship VEX export (OpenVEX/CSAF) based on current gates. * Add Smart‑Diff over SBOM + symbol graph hashes. * Surface the full proof chain in UI/CLI. If you want, I can drop in concrete .NET 10 interfaces/classes for each component and a first pass of the Rekor/DSSE helpers next.