# Reachability Evidence Policy Gates > **Status:** Design v1 (Sprint 0401) > **Owners:** Policy Guild, Signals Guild, VEX Guild This document defines the policy gates that enforce reachability evidence requirements for VEX decisions. Gates prevent unsafe "not_affected" claims when evidence is insufficient. --- ## 1. Overview Policy gates act as checkpoints between evidence (reachability lattice state, uncertainty tier) and VEX status transitions. They ensure that: 1. **No false safety:** "not_affected" requires strong evidence of unreachability 2. **Explicit uncertainty:** Missing evidence triggers "under_investigation" rather than silence 3. **Audit trail:** All gate decisions are logged with evidence references --- ## 2. Gate Types ### 2.1 Lattice State Gate Guards VEX status transitions based on the v1 lattice state (see `docs/reachability/lattice.md` §9). | Requested VEX Status | Required Lattice State | Gate Action | |---------------------|------------------------|-------------| | `not_affected` | `CU` (ConfirmedUnreachable) | ✅ Allow | | `not_affected` | `SU` (StaticallyUnreachable) | ⚠️ Allow with warning, requires `justification` | | `not_affected` | `RU` (RuntimeUnobserved) | ⚠️ Allow with warning, requires `justification` | | `not_affected` | `U`, `SR`, `RO`, `CR`, `X` | ❌ Block | | `affected` | `CR` (ConfirmedReachable) | ✅ Allow | | `affected` | `SR`, `RO` | ✅ Allow | | `affected` | `U`, `SU`, `RU`, `CU`, `X` | ⚠️ Warn (potential false positive) | | `under_investigation` | Any | ✅ Allow (safe default) | | `fixed` | Any | ✅ Allow (remediation action) | ### 2.2 Uncertainty Tier Gate Guards VEX status transitions based on the uncertainty tier (see `docs/uncertainty/README.md` §1.1). | Requested VEX Status | Uncertainty Tier | Gate Action | |---------------------|------------------|-------------| | `not_affected` | T1 (High) | ❌ Block | | `not_affected` | T2 (Medium) | ⚠️ Warn, require explicit override | | `not_affected` | T3 (Low) | ⚠️ Allow with advisory note | | `not_affected` | T4 (Negligible) | ✅ Allow | | `affected` | T1 (High) | ⚠️ Review required (may be false positive) | | `affected` | T2-T4 | ✅ Allow | ### 2.3 Evidence Completeness Gate Guards based on the presence of required evidence artifacts. | VEX Status | Required Evidence | Gate Action if Missing | |------------|-------------------|----------------------| | `not_affected` | `graphHash` (DSSE-attested) | ❌ Block | | `not_affected` | `pathAnalysis.pathLength >= 0` | ❌ Block | | `not_affected` | `confidence >= 0.8` | ⚠️ Warn if < 0.8 | | `affected` | `graphHash` OR `runtimeProbe` | ⚠️ Warn if neither | | `under_investigation` | None required | ✅ Allow | --- ## 3. Gate Evaluation Order Gates are evaluated in this order; first blocking gate stops evaluation: ``` 1. Evidence Completeness Gate → Block if required evidence missing 2. Lattice State Gate → Block if state incompatible with status 3. Uncertainty Tier Gate → Block/warn based on tier 4. Confidence Threshold Gate → Warn if confidence below threshold ``` --- ## 4. Gate Decision Document Each gate evaluation produces a decision document: ```json { "gateId": "gate:vex:not_affected:2025-12-13T10:00:00Z", "requestedStatus": "not_affected", "subject": { "vulnId": "CVE-2025-12345", "purl": "pkg:maven/com.example/foo@1.0.0", "symbolId": "sym:java:..." }, "evidence": { "latticeState": "CU", "uncertaintyTier": "T3", "graphHash": "blake3:...", "riskScore": 0.25, "confidence": 0.92 }, "gates": [ { "name": "EvidenceCompleteness", "result": "pass", "reason": "graphHash present" }, { "name": "LatticeState", "result": "pass", "reason": "CU allows not_affected" }, { "name": "UncertaintyTier", "result": "pass_with_note", "reason": "T3 allows with advisory note", "note": "MissingPurl uncertainty at 35% entropy" } ], "decision": "allow", "advisory": "VEX status allowed with note: T3 uncertainty from MissingPurl", "decidedAt": "2025-12-13T10:00:00Z" } ``` --- ## 5. Contested State Handling When lattice state is `X` (Contested): 1. **Block all definitive statuses:** Neither "not_affected" nor "affected" allowed 2. **Force "under_investigation":** Auto-assign until triage resolves conflict 3. **Emit triage event:** Notify VEX operators of conflict with evidence links 4. **Evidence overlay:** Show both static and runtime evidence for manual review ### Contested Resolution Workflow ``` 1. System detects X state 2. VEX status locked to "under_investigation" 3. Triage event emitted to operator queue 4. Operator reviews: a. Static evidence (graph, paths) b. Runtime evidence (probes, hits) 5. Operator provides resolution: a. Trust static → state becomes SU/SR b. Trust runtime → state becomes RU/RO c. Add new evidence → recompute lattice 6. Gate re-evaluates with new state ``` --- ## 6. Override Mechanism Operators with `vex:gate:override` permission can bypass gates with mandatory fields: ```json { "override": { "gateId": "gate:vex:not_affected:...", "operator": "user:alice@example.com", "justification": "Manual review confirms code path is dead code", "evidence": { "type": "ManualReview", "reviewId": "review:2025-12-13:001", "attachments": ["cas://evidence/review/..."] }, "approvedAt": "2025-12-13T11:00:00Z", "expiresAt": "2026-01-13T11:00:00Z" } } ``` Override requirements: - `justification` is mandatory and logged - Overrides expire after configurable period (default: 30 days) - All overrides are auditable and appear in compliance reports --- ## 7. Configuration Gate thresholds are configurable via `PolicyGatewayOptions`: ```yaml PolicyGateway: Gates: LatticeState: AllowSUForNotAffected: true # Allow SU with warning AllowRUForNotAffected: true # Allow RU with warning RequireJustificationForWeakStates: true UncertaintyTier: BlockT1ForNotAffected: true WarnT2ForNotAffected: true EvidenceCompleteness: RequireGraphHashForNotAffected: true MinConfidenceForNotAffected: 0.8 MinConfidenceWarning: 0.6 Override: DefaultExpirationDays: 30 RequireJustification: true ``` --- ## 8. API Integration ### POST `/api/v1/vex/status` Request: ```json { "vulnId": "CVE-2025-12345", "purl": "pkg:maven/com.example/foo@1.0.0", "status": "not_affected", "justification": "vulnerable_code_not_present", "reachabilityEvidence": { "factDigest": "sha256:...", "graphHash": "blake3:..." } } ``` Response (gate blocked): ```json { "success": false, "gateDecision": { "decision": "block", "blockedBy": "LatticeState", "reason": "Lattice state SR (StaticallyReachable) incompatible with not_affected", "currentState": "SR", "requiredStates": ["CU", "SU", "RU"], "suggestion": "Submit runtime probe evidence or change to under_investigation" } } ``` --- ## 9. Metrics & Alerts The policy gateway emits metrics: | Metric | Labels | Description | |--------|--------|-------------| | `stellaops_gate_decisions_total` | `gate`, `result`, `status` | Total gate decisions | | `stellaops_gate_blocks_total` | `gate`, `reason` | Total blocked requests | | `stellaops_gate_overrides_total` | `operator` | Total override uses | | `stellaops_contested_states_total` | `vulnId` | Active contested states | Alert conditions: - `stellaops_gate_overrides_total` rate > threshold → Audit review - `stellaops_contested_states_total` > 10 → Triage backlog alert --- ## 10. Related Documents - [Lattice Model](./lattice.md) — v1 formal 7-state lattice - [Uncertainty States](../uncertainty/README.md) — Tier definitions and risk scoring - [Evidence Schema](./evidence-schema.md) — richgraph-v1 schema - [VEX Contract](../contracts/vex-v1.md) — VEX document schema --- ## Changelog | Version | Date | Author | Changes | |---------|------|--------|---------| | 1.0.0 | 2025-12-13 | Policy Guild | Initial design from Sprint 0401 |