# VEX Consensus and Issuer Trust This document consolidates the VEX concepts StellaOps relies on: ingesting upstream VEX without rewriting it, correlating evidence across sources, and producing a deterministic, explainable "effective" status for a component-vulnerability pair. ## Scope - VEX ingestion and provenance (what is stored and why) - Correlation (linksets) versus consensus (effective status) - Issuer trust and offline operation This is not an API reference; module dossiers define concrete schemas and endpoints. ## Vocabulary (Minimal) - **VEX statement:** a claim about vulnerability status for a product/component (for example: `affected`, `fixed`, `not_affected`, `under_investigation`). - **Observation:** an immutable record of a single upstream VEX document as received (including provenance and raw payload). - **Linkset:** a deterministic correlation group that ties together statements that refer to the same `(vulnerabilityId, productKey)` across providers. - **Consensus decision (effective VEX):** the platform's deterministic result after policy rules evaluate available VEX/advisory/reachability evidence. ## Observation Model (Link, Not Merge) StellaOps treats upstream VEX as append-only evidence. An observation records: - **Provenance:** tenant, provider/issuer identity, receive timestamps (UTC), signature status, and content hash. - **Raw payload:** stored losslessly so auditors and operators can retrieve exactly what was ingested. - **Derived tuples:** extracted `(vulnerabilityId, productKey, status, justification?, version hints, references)` used for correlation and UI presentation. An observation is never mutated. If upstream publishes a revision, StellaOps stores a new observation and records a supersedes relationship. ## Linksets (Correlation Without Consensus) Linksets exist to make multi-source evidence explainable without collapsing it: - Group statements that likely refer to the same product-vulnerability pair. - Preserve conflicts (status disagreements, justification divergence, version range clashes) as first-class facts. - Provide stable IDs generated from canonical, sorted inputs (deterministic hashing). Linksets do not invent consensus; they only align evidence so downstream layers (Policy/Console/Exports) can explain what is known and what disagrees. ## Consensus (Effective Status) The effective VEX status is computed by policy evaluation using: - Correlated VEX evidence (observations + linksets) - Advisory evidence (observations/linksets from Concelier) - Optional reachability and other signals Key properties: - **Deterministic:** the same inputs yield the same output. - **Explainable:** the decision includes an explanation trace and evidence references. - **Uncertainty-aware:** when critical evidence is missing or conflicts are unresolved, the result can remain `under_investigation` instead of implying safety. ## Aggregation-Only Guardrails (AOC) To avoid hidden rewriting of upstream data, the platform enforces: - **Raw-first storage:** upstream payloads are stored as received; normalized projections are derived but do not replace raw data. - **No merge of sources:** each provider's statements remain independently addressable. - **Provenance is mandatory:** missing provenance or unverifiable signatures are surfaced as ingestion failures or warnings (policy-driven). - **Idempotent writes:** identical content hashes do not create duplicate observations. - **Deterministic outputs:** stable ordering and canonical hashing for linksets and exports. ## Issuer Directory and Trust Issuer trust is a first-class input: - Issuers are identified by stable provider IDs and, where applicable, cryptographic identity (certificate chain, key id, transparency proof). - The issuer directory defines which issuers are trusted per tenant/environment and how they are weighted/accepted by policy. - Offline sites carry required trust material (roots and allowlists) inside the Offline Kit so verification does not require network access. ## Console Integration The Console uses these concepts to keep VEX explainable: - VEX views show provider provenance, signature/issuer status, and snapshot timestamps. - Conflicts are displayed as conflicts (what disagrees and why), not silently resolved in the UI. - The effective VEX status shown in triage views links back to underlying observations/linksets and the policy explanation. See `docs/UI_GUIDE.md` for the operator workflow perspective. ## Anchor-Aware Mode (v1.1) > **Sprint:** SPRINT_20260112_004_BE_policy_determinization_attested_rules Anchor-aware mode enforces cryptographic attestation requirements on VEX proofs used for allow decisions. ### VexProofGate Options | Option | Type | Default | Strict Mode | |--------|------|---------|-------------| | `AnchorAwareMode` | bool | `false` | `true` | | `RequireVexAnchoring` | bool | `false` | `true` | | `RequireRekorVerification` | bool | `false` | `true` | | `RequireSignedStatements` | bool | `false` | `true` | | `RequireProofForFixed` | bool | `false` | `true` | | `MaxAllowedConflicts` | int | `5` | `0` | | `MaxProofAgeHours` | int | `168` | `72` | ### Strict Anchor-Aware Preset For production environments requiring maximum security: ```csharp var options = VexProofGateOptions.StrictAnchorAware; // Enables: RequireVexAnchoring, RequireRekorVerification, // RequireSignedStatements, RequireProofForFixed // Sets: MinimumConfidenceTier=high, MaxAllowedConflicts=0, MaxProofAgeHours=72 ``` ### Metadata Keys When passing VEX proof context through policy evaluation: | Key | Type | Description | |-----|------|-------------| | `vex_proof_anchored` | bool | Whether proof has DSSE anchoring | | `vex_proof_envelope_digest` | string | DSSE envelope sha256 digest | | `vex_proof_rekor_verified` | bool | Whether Rekor transparency verified | | `vex_proof_rekor_log_index` | long | Rekor log index if verified | ### Failure Reasons | Reason | Description | |--------|-------------| | `vex_not_anchored` | VEX proof requires DSSE anchoring but is not anchored | | `rekor_verification_missing` | VEX proof requires Rekor verification but not verified | ## VEX Change Events > Sprint: SPRINT_20260112_006_EXCITITOR_vex_change_events Excititor emits deterministic events when VEX statements change, enabling policy reanalysis. ### Event Types | Event | Description | Policy Trigger | |-------|-------------|----------------| | `vex.statement.added` | New statement ingested | Immediate reanalysis | | `vex.statement.superseded` | Statement replaced | Immediate reanalysis | | `vex.statement.conflict` | Status disagreement detected | Queue for review | | `vex.status.changed` | Effective status changed | Immediate reanalysis | ### Conflict Detection Conflicts are detected when multiple providers report different statuses for the same vulnerability-product pair: | Conflict Type | Description | |---------------|-------------| | `status_mismatch` | Different status values (e.g., affected vs not_affected) | | `trust_tie` | Equal trust scores with different recommendations | | `supersession_conflict` | Disagreement on which statement supersedes | ### Event Ordering Events follow deterministic ordering: 1. Ordered by timestamp (ascending) 2. Conflict events after related statement events 3. Same-timestamp events sorted by provider ID ### Integration with Policy Subscribe to VEX events for automatic reanalysis: ```yaml subscriptions: - event: vex.statement.* action: reanalyze filter: trustScore: { $gte: 0.7 } ``` See [Excititor Architecture](docs/modules/excititor/architecture.md#33-vex-change-events) for full event schemas. ## Offline / Air-Gap Operation - VEX observations/linksets are included in Offline Kit snapshots with content hashes and timestamps. - Verification workflows (signatures, issuer trust) must work offline using bundled trust roots and manifests. - The Console should surface snapshot identity and staleness budgets when operating offline. ## Related Docs - `docs/modules/excititor/architecture.md` - `docs/modules/vex-lens/architecture.md` - `docs/ARCHITECTURE_OVERVIEW.md` - `docs/OFFLINE_KIT.md`