8.0 KiB
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:
- No false safety: "not_affected" requires strong evidence of unreachability
- Explicit uncertainty: Missing evidence triggers "under_investigation" rather than silence
- 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:
{
"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):
- Block all definitive statuses: Neither "not_affected" nor "affected" allowed
- Force "under_investigation": Auto-assign until triage resolves conflict
- Emit triage event: Notify VEX operators of conflict with evidence links
- 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:
{
"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:
justificationis 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:
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:
{
"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):
{
"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_totalrate > threshold → Audit reviewstellaops_contested_states_total> 10 → Triage backlog alert
10. Related Documents
- Lattice Model — v1 formal 7-state lattice
- Uncertainty States — Tier definitions and risk scoring
- Evidence Schema — richgraph-v1 schema
- VEX Contract — VEX document schema
Changelog
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0.0 | 2025-12-13 | Policy Guild | Initial design from Sprint 0401 |