# VEX Trust Lattice Specification > **Status**: Implementation Complete (Sprint 7100) > **Version**: 1.0.0 > **Last Updated**: 2025-12-22 > **Source Advisory**: `docs/product-advisories/archived/22-Dec-2026 - Building a Trust Lattice for VEX Sources.md` ## 1. Overview The VEX Trust Lattice provides a mathematically rigorous framework for converting heterogeneous VEX claims from multiple sources into a single, signed, reproducible verdict with a numeric confidence and a complete audit trail. ### Goals 1. **Explainability**: Every verdict includes a full breakdown of how it was computed 2. **Reproducibility**: Same inputs always produce identical verdicts (deterministic) 3. **Auditability**: Signed verdict manifests with pinned inputs for regulatory compliance 4. **Tunability**: Per-tenant, per-source trust configuration without code changes ### Non-Goals - Real-time vulnerability detection (handled by Scanner) - VEX document ingestion (handled by Excititor core) - Policy enforcement (handled by Policy Engine) --- ## 2. Trust Vector Model Each VEX source is assigned a 3-component trust vector scored in the range [0..1]. ### 2.1 Provenance (P) Measures cryptographic and process integrity of the source. | Score | Description | |-------|-------------| | 1.00 | DSSE-signed, timestamped, Rekor/Git anchored, key in allow-list, rotation policy OK | | 0.75 | DSSE-signed + public key known, but no transparency log | | 0.40 | Unsigned but retrieved via authenticated, immutable artifact repo | | 0.10 | Opaque/CSV/email/manual import | ### 2.2 Coverage (C) Measures how well the statement's scope maps to the target asset. | Score | Description | |-------|-------------| | 1.00 | Exact package + version/build digest + feature/flag context matched | | 0.75 | Exact package + version range matched; partial feature context | | 0.50 | Product-level only; maps via CPE/PURL family | | 0.25 | Family-level heuristics; no version proof | ### 2.3 Replayability (R) Measures whether the claim can be deterministically re-derived. | Score | Description | |-------|-------------| | 1.00 | All inputs pinned (feeds, SBOM hash, ruleset hash, lattice version); replays byte-identical | | 0.60 | Inputs mostly pinned; non-deterministic ordering tolerated but stable outcome | | 0.20 | Ephemeral APIs; no snapshot | ### 2.4 Weight Configuration The base trust score is computed as: ``` BaseTrust(S) = wP * P + wC * C + wR * R ``` **Default weights:** - `wP = 0.45` (Provenance) - `wC = 0.35` (Coverage) - `wR = 0.20` (Replayability) Weights are tunable per policy and sum to 1.0. --- ## 3. Claim Scoring ### 3.1 Base Trust Calculation ```csharp double BaseTrust(double P, double C, double R, TrustWeights W) => W.wP * P + W.wC * C + W.wR * R; ``` ### 3.2 Claim Strength Multipliers (M) Each VEX claim carries a strength multiplier based on evidence quality: | Strength | Value | Description | |----------|-------|-------------| | ExploitabilityWithReachability | 1.00 | Exploitability analysis + reachability proof subgraph provided | | ConfigWithEvidence | 0.80 | Config/feature-flag reason with evidence | | VendorBlanket | 0.60 | Vendor blanket statement | | UnderInvestigation | 0.40 | "Under investigation" | ### 3.3 Freshness Decay (F) Time-decay curve with configurable half-life: ```csharp double Freshness(DateTime issuedAt, DateTime cutoff, double halfLifeDays = 90, double floor = 0.35) { var ageDays = (cutoff - issuedAt).TotalDays; var decay = Math.Exp(-Math.Log(2) * ageDays / halfLifeDays); return Math.Max(decay, floor); } ``` **Parameters:** - `halfLifeDays = 90` (default): Score halves every 90 days - `floor = 0.35` (default): Minimum freshness unless revoked ### 3.4 ClaimScore Formula ``` ClaimScore = BaseTrust(S) * M * F ``` **Example calculation:** ``` Source: Red Hat (Vendor) P = 0.90, C = 0.75, R = 0.60 BaseTrust = 0.45*0.90 + 0.35*0.75 + 0.20*0.60 = 0.405 + 0.2625 + 0.12 = 0.7875 Claim: ConfigWithEvidence (M = 0.80) Freshness: 30 days old (F = 0.79) ClaimScore = 0.7875 * 0.80 * 0.79 = 0.498 ``` --- ## 4. Lattice Merge Algorithm ### 4.1 Partial Ordering Claims are ordered by a tuple: `(scope_specificity, ClaimScore)`. Scope specificity levels: 1. Exact digest match (highest) 2. Exact version match 3. Version range match 4. Product family match 5. Platform match (lowest) ### 4.2 Conflict Detection Conflicts occur when claims for the same (CVE, Asset) have different statuses: ```csharp bool HasConflict(IEnumerable claims) => claims.Select(c => c.Status).Distinct().Count() > 1; ``` ### 4.3 Conflict Penalty When conflicts exist, apply a penalty to weaker/older claims: ```csharp const double ConflictPenalty = 0.25; if (contradictory) { var strongest = claims.OrderByDescending(c => c.Score).First(); foreach (var claim in claims.Where(c => c.Status != strongest.Status)) { claim.AdjustedScore = claim.Score * (1 - ConflictPenalty); } } ``` ### 4.4 Winner Selection Final verdict is selected by: ```csharp var winner = scored .OrderByDescending(x => (x.Claim.ScopeSpecificity, x.AdjustedScore)) .First(); ``` ### 4.5 Audit Trail Generation Every merge produces: ```csharp public sealed record MergeResult { public VexStatus Status { get; init; } public double Confidence { get; init; } public ImmutableArray Explanations { get; init; } public ImmutableArray EvidenceRefs { get; init; } public string PolicyHash { get; init; } public string LatticeVersion { get; init; } } ``` --- ## 5. Policy Gates Gates are evaluated after merge to enforce policy requirements. ### 5.1 MinimumConfidenceGate Requires minimum confidence by environment for certain statuses. ```yaml gates: minimumConfidence: enabled: true thresholds: production: 0.75 staging: 0.60 development: 0.40 applyToStatuses: - not_affected - fixed ``` **Behavior**: Fails if confidence < threshold for specified statuses. ### 5.2 UnknownsBudgetGate Limits exposure to unknown/unscored dependencies. ```yaml gates: unknownsBudget: enabled: true maxUnknownCount: 5 maxCumulativeUncertainty: 2.0 ``` **Behavior**: Fails if: - `#unknown_deps > maxUnknownCount`, OR - `sum(1 - ClaimScore) > maxCumulativeUncertainty` ### 5.3 SourceQuotaGate Prevents single-source dominance without corroboration. ```yaml gates: sourceQuota: enabled: true maxInfluencePercent: 60 corroborationDelta: 0.10 ``` **Behavior**: Fails if single source influence > 60% AND no second source within delta=0.10. ### 5.4 ReachabilityRequirementGate Requires reachability proof for critical vulnerabilities. ```yaml gates: reachabilityRequirement: enabled: true severityThreshold: CRITICAL requiredForStatuses: - not_affected bypassReasons: - component_not_present ``` **Behavior**: Fails if `not_affected` on CRITICAL CVE without reachability proof (unless bypass reason applies). --- ## 6. Deterministic Replay ### 6.1 Input Pinning To guarantee "same inputs → same verdict", pin: - SBOM digest(s) - Vuln feed snapshot IDs - VEX document digests - Reachability graph IDs - Policy file hash - Lattice version - Clock cutoff (evaluation timestamp) ### 6.2 Verdict Manifest ```json { "manifestId": "verd:tenant:asset:cve:1234567890", "tenant": "acme-corp", "assetDigest": "sha256:abc123...", "vulnerabilityId": "CVE-2025-12345", "inputs": { "sbomDigests": ["sha256:..."], "vulnFeedSnapshotIds": ["nvd:2025-12-22"], "vexDocumentDigests": ["sha256:..."], "reachabilityGraphIds": ["graph:..."], "clockCutoff": "2025-12-22T12:00:00Z" }, "result": { "status": "not_affected", "confidence": 0.82, "explanations": [...] }, "policyHash": "sha256:...", "latticeVersion": "1.2.0", "evaluatedAt": "2025-12-22T12:00:01Z", "manifestDigest": "sha256:..." } ``` ### 6.3 Signing Verdict manifests are signed using DSSE with predicate type: ``` https://stella-ops.org/attestations/vex-verdict/1 ``` ### 6.4 Replay Verification ``` POST /api/v1/authority/verdicts/{manifestId}/replay Response: { "success": true, "originalManifest": {...}, "replayedManifest": {...}, "differences": [], "signatureValid": true } ``` --- ## 7. Configuration Reference ### Full Configuration Example ```yaml # etc/trust-lattice.yaml version: "1.0" trustLattice: weights: provenance: 0.45 coverage: 0.35 replayability: 0.20 freshness: halfLifeDays: 90 floor: 0.35 conflictPenalty: 0.25 defaults: vendor: provenance: 0.90 coverage: 0.70 replayability: 0.60 distro: provenance: 0.80 coverage: 0.85 replayability: 0.60 internal: provenance: 0.85 coverage: 0.95 replayability: 0.90 gates: minimumConfidence: enabled: true thresholds: production: 0.75 staging: 0.60 development: 0.40 unknownsBudget: enabled: true maxUnknownCount: 5 maxCumulativeUncertainty: 2.0 sourceQuota: enabled: true maxInfluencePercent: 60 corroborationDelta: 0.10 reachabilityRequirement: enabled: true severityThreshold: CRITICAL ``` --- ## 8. API Reference ### Endpoints | Method | Path | Description | |--------|------|-------------| | GET | `/api/v1/excititor/verdicts/{manifestId}` | Get verdict manifest | | GET | `/api/v1/excititor/verdicts` | List verdicts (paginated) | | POST | `/api/v1/authority/verdicts/{manifestId}/replay` | Verify replay | | GET | `/api/v1/authority/verdicts/{manifestId}/download` | Download signed manifest | See `docs/09_API_CLI_REFERENCE.md` for complete API documentation. --- ## 9. Examples ### Example 1: High-Confidence Verdict **Input:** - Red Hat VEX: `not_affected` with `component_not_present` - Ubuntu VEX: `not_affected` with `component_not_present` **Calculation:** ``` Red Hat: BaseTrust=0.78, M=0.80, F=0.95 → ClaimScore=0.59 Ubuntu: BaseTrust=0.72, M=0.80, F=0.90 → ClaimScore=0.52 No conflict (both agree) Winner: Red Hat (higher score) Confidence: 0.59 Gates: All pass (> 0.40 threshold) ``` ### Example 2: Conflict Resolution **Input:** - Vendor VEX: `not_affected` - Internal scan: `affected` **Calculation:** ``` Vendor: ClaimScore=0.65 Internal: ClaimScore=0.55 Conflict detected → penalty applied Internal adjusted: 0.55 * 0.75 = 0.41 Winner: Vendor Confidence: 0.65 Note: Conflict recorded in audit trail ``` --- --- ## 10. Implementation Reference ### 10.1 Source Files | Component | Location | |-----------|----------| | TrustVector | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/TrustVector.cs` | | TrustWeights | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/TrustWeights.cs` | | ClaimStrength | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/ClaimStrength.cs` | | FreshnessCalculator | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/FreshnessCalculator.cs` | | DefaultTrustVectors | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/DefaultTrustVectors.cs` | | ProvenanceScorer | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/ProvenanceScorer.cs` | | CoverageScorer | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/CoverageScorer.cs` | | ReplayabilityScorer | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/ReplayabilityScorer.cs` | | SourceClassificationService | `src/Excititor/__Libraries/StellaOps.Excititor.Core/TrustVector/SourceClassificationService.cs` | | ClaimScoreMerger | `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/ClaimScoreMerger.cs` | | MinimumConfidenceGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/MinimumConfidenceGate.cs` | | UnknownsBudgetGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/UnknownsBudgetGate.cs` | | SourceQuotaGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/SourceQuotaGate.cs` | | ReachabilityRequirementGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/ReachabilityRequirementGate.cs` | | TrustVectorCalibrator | `src/Excititor/__Libraries/StellaOps.Excititor.Core/Calibration/TrustVectorCalibrator.cs` | ### 10.2 Configuration Files | File | Purpose | |------|---------| | `etc/trust-lattice.yaml.sample` | Trust vector weights, freshness parameters, default vectors | | `etc/policy-gates.yaml.sample` | Gate thresholds and enable/disable flags | | `etc/excititor-calibration.yaml.sample` | Calibration learning parameters | ### 10.3 Database Schema - **Calibration manifests**: `src/Excititor/__Libraries/StellaOps.Excititor.Storage.Postgres/Migrations/002_calibration_schema.sql` - **Verdict storage**: See Authority module for verdict manifest persistence ### 10.4 Test Coverage | Test Suite | Location | |------------|----------| | TrustVector tests | `src/Excititor/__Tests/StellaOps.Excititor.Core.Tests/TrustVector/` | | ClaimScoreMerger tests | `src/Policy/__Tests/StellaOps.Policy.Tests/TrustLattice/` | | Gate tests | `src/Policy/__Tests/StellaOps.Policy.Tests/Gates/` | | Calibration tests | `src/Excititor/__Tests/StellaOps.Excititor.Core.Tests/Calibration/` | --- ## Related Documentation - [Excititor Architecture](./architecture.md) - [Verdict Manifest Specification](../authority/verdict-manifest.md) - [Policy Gates Configuration](../policy/architecture.md) - [API Reference](../../09_API_CLI_REFERENCE.md) --- *Document Version: 1.0.0* *Sprint: 7100.0003.0002* *Created: 2025-12-22*