consolidation of some of the modules, localization fixes, product advisories work, qa work
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
Here’s a compact, plug‑and‑play blueprint for making **“unknown” a first‑class, auditable state** in your VEX pipeline (fits Stella Ops nicely).
|
||||
|
||||
# Why this matters (quick)
|
||||
|
||||
VEX (OpenVEX/CSAF) often forces binary “affected/not_affected.” In practice, evidence is missing, conflicting, or stale. Treating **unknown** as a deliberate, signed, and replayable decision keeps you compliant (CRA/NIS2/DORA) and operationally honest.
|
||||
|
||||
# Lifecycle & precedence
|
||||
|
||||
```
|
||||
unvalidated
|
||||
→ evidence_ingested
|
||||
→ proof_anchored
|
||||
→ merge_candidate
|
||||
→ merged_outcome { affected | not_affected | unknown }
|
||||
→ scored
|
||||
→ triage
|
||||
```
|
||||
|
||||
* **Default unknown at ingest** if anything is missing/ambiguous.
|
||||
* **Precedence:** latest valid timestamp wins; hard tie → **lexicographic source_id** tie‑break.
|
||||
* Carry a **provenance bundle** with every hop: `{source_id, timestamp, proof_hash}`.
|
||||
* Every **merged outcome** and **score** is **DSSE‑wrapped** and **Rekor‑anchored**.
|
||||
|
||||
# Four readiness gates (fail fast)
|
||||
|
||||
1. **ingest_validation**
|
||||
|
||||
* Schema‑valid OpenVEX/CSAF + DSSE envelope present.
|
||||
* Reject → `unvalidated` (record reasons).
|
||||
|
||||
2. **proof_anchor**
|
||||
|
||||
* Rekor entry (UUID) + inclusion proof persisted.
|
||||
* Reject if no inclusion proof or log not reachable (offline mode: queue + mark `unknown`).
|
||||
|
||||
3. **merge_precheck**
|
||||
|
||||
* Deterministic timestamp precedence; evidence sufficiency (at least one attestation + SBOM ref).
|
||||
* Reject if conflicts unresolved → stay at `proof_anchored` and set target outcome `unknown`.
|
||||
|
||||
4. **scoring_precondition**
|
||||
|
||||
* `replay_success_ratio` (e.g., ≥0.95) on verification of DSSE/rekor bundles + provenance presence.
|
||||
* Reject if below threshold or provenance gaps → do not score; outcome remains `unknown`.
|
||||
|
||||
# Deterministic merge rules
|
||||
|
||||
* Normalize identifiers (CVE, package PURL, image digest).
|
||||
* Collapse equivalent justifications (OpenVEX) and product trees (CSAF).
|
||||
* If any required justification absent or conflicting → **merged_outcome = unknown** with rationale snapshot.
|
||||
* Merge is **idempotent**: same inputs → byte‑identical output and provenance trace.
|
||||
|
||||
# API surface (minimal)
|
||||
|
||||
```
|
||||
POST /v1/vex/ingest
|
||||
Body: DSSE-envelope { payload: OpenVEX|CSAF, signatures:[] }
|
||||
Resp: { state: "evidence_ingested"|"unvalidated", provenance_bundle, rekor_hint? }
|
||||
|
||||
POST /v1/vex/merge
|
||||
Body: { product_ref, candidates:[{openvex_or_csaf_ref, provenance_bundle}], strategy:"timestamp_lexi_tiebreak" }
|
||||
Resp: { merged_outcome, provenance_trace[], dsse_signed_merged }
|
||||
|
||||
POST /v1/score
|
||||
Body: { merged_outcome_ref, policy_id, replay_window }
|
||||
Resp: { signed_score_dsse, replay_verification:{ratio, failures[]}, gate_passed:boolean }
|
||||
|
||||
GET /v1/triage?outcome=unknown
|
||||
Resp: [{ product_ref, vuln_id, last_timestamp, missing_evidence[], next_actions[] }]
|
||||
```
|
||||
|
||||
# Evidence & storage
|
||||
|
||||
* **EvidenceLocker** (your module) keeps: raw docs, DSSE envelopes, Rekor inclusion proofs, SBOM/attestation refs, provenance bundles.
|
||||
* Hash all decision artifacts; store `{artifact_hash → Rekor UUID}` map.
|
||||
* Offline/air‑gap: stage to local transparency log; when online, **bridge** to Rekor and backfill inclusion proofs.
|
||||
|
||||
# Scoring model (example)
|
||||
|
||||
* Base score source (e.g., CVSS/CVSS‑SR).
|
||||
* Dampener if outcome=`unknown`: apply policy (e.g., cap at 6.9 or bump to triage queue).
|
||||
* Require `replay_success_ratio ≥ threshold` and `provenance.complete=true` before emitting scores.
|
||||
|
||||
# Acceptance tests (must‑pass)
|
||||
|
||||
1. **missing_evidence_defaults_unknown**
|
||||
|
||||
* Ingest CSAF missing justification → merged outcome is `unknown` with rationale.
|
||||
|
||||
2. **dsse_anchor_presence**
|
||||
|
||||
* Attempt score without Rekor inclusion → gate fails.
|
||||
|
||||
3. **timestamp_precedence_tiebreak**
|
||||
|
||||
* Two equal timestamps from different sources → lexicographic `source_id` decides, deterministic.
|
||||
|
||||
4. **merge_idempotence**
|
||||
|
||||
* Re‑run merge with same inputs → identical `dsse_signed_merged` hash.
|
||||
|
||||
5. **scoring_gate_replay_success**
|
||||
|
||||
* Corrupt one signature in replay set → `replay_success_ratio` drops; scoring blocked.
|
||||
|
||||
# CLI hints (nice DX)
|
||||
|
||||
```
|
||||
stella vex ingest --file advisories/openvex.json --sign key.pem --rekor-url $REKOR
|
||||
stella vex merge --product my/image:sha256:… --inputs dir:./evidence
|
||||
stella score --policy default --replay-window 30d
|
||||
stella triage --outcome unknown --limit 50
|
||||
```
|
||||
|
||||
# UI touchpoints (lean)
|
||||
|
||||
* **Evidence Ingest**: file drop (OpenVEX/CSAF), DSSE status, Rekor anchor badge.
|
||||
* **Merge Review**: side‑by‑side justifications, conflicts, deterministic decision summary.
|
||||
* **Scoring Gate**: replay bar (ratio), provenance checklist.
|
||||
* **Triage (unknown)**: prioritized queue with “missing evidence” chips and one‑click requests.
|
||||
|
||||
# Drop‑in for Stella Ops modules
|
||||
|
||||
* **Concelier**: orchestrates gates.
|
||||
* **Attestor**: DSSE wrap/verify.
|
||||
* **EvidenceLocker**: storage + provenance.
|
||||
* **AdvisoryAI**: explanation/triage suggestions (surfacing unknowns first).
|
||||
* **ReleaseOrchestrator**: policy “block if unknown>0 and critical path”.
|
||||
|
||||
If you want, I can generate:
|
||||
|
||||
* a ready OpenAPI spec for the 4 endpoints,
|
||||
* the DSSE/Rekor wiring stubs (C#) and a minimal SQLite/Postgres schema,
|
||||
* a Playwright test suite implementing the five acceptance tests.
|
||||
Reference in New Issue
Block a user