Files
StellaOps Bot 999e26a48e up
2025-12-13 02:22:15 +02:00

270 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 |