save progress
This commit is contained in:
490
docs/flows/04-policy-evaluation-flow.md
Normal file
490
docs/flows/04-policy-evaluation-flow.md
Normal file
@@ -0,0 +1,490 @@
|
||||
# Policy Evaluation Flow
|
||||
|
||||
## Overview
|
||||
|
||||
The Policy Evaluation Flow describes how StellaOps applies K4 lattice logic to vulnerability findings, incorporating VEX statements, reachability analysis, and confidence scoring to produce deterministic pass/fail verdicts. This is the core decision-making flow that determines whether a container image meets security requirements.
|
||||
|
||||
**Business Value**: Consistent, explainable security verdicts with full audit trail for compliance and governance.
|
||||
|
||||
## Actors
|
||||
|
||||
| Actor | Type | Role |
|
||||
|-------|------|------|
|
||||
| Scanner | Service | Submits findings for evaluation |
|
||||
| Policy Engine | Service | Applies policy rules |
|
||||
| VexLens | Service | Provides VEX consensus |
|
||||
| ReachGraph | Service | Provides reachability state |
|
||||
| Policy Store | Component | Stores policy definitions |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Policy set configured for the tenant
|
||||
- Scan findings generated with SBOM
|
||||
- VEX statements loaded (optional)
|
||||
- Reachability analysis completed (optional)
|
||||
|
||||
## K4 Lattice Model
|
||||
|
||||
StellaOps uses a 7-state K4 lattice for vulnerability reachability:
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ ConfirmedReachable │ (Highest certainty)
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌──────────────────────┼──────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌────────────────┐ ┌─────────────────┐
|
||||
│RuntimeObserved│ │StaticallyReach.│ │ Contested │
|
||||
└───────┬───────┘ └────────┬───────┘ └────────┬────────┘
|
||||
│ │ │
|
||||
└──────────────────────┼──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ Unknown │ (Default state)
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌──────────────────────┼──────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌────────────────┐ ┌─────────────────┐
|
||||
│RuntimeUnobserv│ │Statically Unr. │ │ │
|
||||
└───────┬───────┘ └────────┬───────┘ └─────────────────┘
|
||||
│ │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ConfirmedUnreachable │ (Lowest risk)
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
### State Definitions
|
||||
|
||||
| State | Code | Description |
|
||||
|-------|------|-------------|
|
||||
| Unknown | `U` | No reachability data available |
|
||||
| StaticallyReachable | `SR` | Static analysis shows potential call path |
|
||||
| StaticallyUnreachable | `SU` | Static analysis shows no call path |
|
||||
| RuntimeObserved | `RO` | Runtime telemetry confirmed execution |
|
||||
| RuntimeUnobserved | `RU` | Runtime telemetry shows no execution |
|
||||
| ConfirmedReachable | `CR` | Both static and runtime confirm reachability |
|
||||
| ConfirmedUnreachable | `CU` | Both static and runtime confirm unreachable |
|
||||
| Contested | `X` | Conflicting evidence (requires review) |
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Policy Evaluation Flow │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌───────────┐ ┌─────────────┐
|
||||
│ Scanner │ │ Policy │ │ VexLens │ │ ReachGraph│ │Policy Store │
|
||||
└────┬────┘ └────┬────┘ └────┬────┘ └─────┬─────┘ └──────┬──────┘
|
||||
│ │ │ │ │
|
||||
│ Evaluate │ │ │ │
|
||||
│ request │ │ │ │
|
||||
│────────────>│ │ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Load policy │ │ │
|
||||
│ │ set │ │ │
|
||||
│ │─────────────────────────────────────────────>
|
||||
│ │ │ │ │
|
||||
│ │ Policy │ │ │
|
||||
│ │ rules │ │ │
|
||||
│ │<─────────────────────────────────────────────
|
||||
│ │ │ │ │
|
||||
│ │ Get VEX │ │ │
|
||||
│ │ consensus │ │ │
|
||||
│ │────────────>│ │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ Query issuers│ │
|
||||
│ │ │──────┐ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │<─────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ │ VEX status │ │ │
|
||||
│ │ per CVE │ │ │
|
||||
│ │<────────────│ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Get reach │ │ │
|
||||
│ │ states │ │ │
|
||||
│ │─────────────────────────────> │
|
||||
│ │ │ │ │
|
||||
│ │ │ │ Query call │
|
||||
│ │ │ │ graph │
|
||||
│ │ │ │───────┐ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │<──────┘ │
|
||||
│ │ │ │ │
|
||||
│ │ K4 states │ │ │
|
||||
│ │<───────────────────────────── │
|
||||
│ │ │ │ │
|
||||
│ │ Apply rules │ │ │
|
||||
│ │──────┐ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │<─────┘ │ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Compute │ │ │
|
||||
│ │ confidence │ │ │
|
||||
│ │──────┐ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │<─────┘ │ │ │
|
||||
│ │ │ │ │
|
||||
│ Verdict + │ │ │ │
|
||||
│ explain │ │ │ │
|
||||
│<────────────│ │ │ │
|
||||
│ │ │ │ │
|
||||
```
|
||||
|
||||
## Step-by-Step
|
||||
|
||||
### 1. Evaluation Request
|
||||
|
||||
Scanner submits findings for policy evaluation:
|
||||
|
||||
```http
|
||||
POST /internal/evaluate HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
### 2. Policy Loading
|
||||
|
||||
Policy Engine loads the policy set from storage:
|
||||
|
||||
```yaml
|
||||
# Policy Set: production
|
||||
version: "stella-dsl@1"
|
||||
name: production
|
||||
description: Production deployment policy
|
||||
|
||||
rules:
|
||||
- name: no-critical-reachable
|
||||
description: Block critical CVEs with reachable code
|
||||
condition: |
|
||||
severity == 'critical' AND
|
||||
reachability IN ['SR', 'RO', 'CR'] AND
|
||||
vex_status != 'not_affected'
|
||||
action: FAIL
|
||||
|
||||
- name: no-critical-unfixed
|
||||
description: Block critical CVEs without fixes
|
||||
condition: |
|
||||
severity == 'critical' AND
|
||||
fixed_version == null
|
||||
action: FAIL
|
||||
|
||||
- name: warn-high-reachable
|
||||
description: Warn on high CVEs with reachable code
|
||||
condition: |
|
||||
severity == 'high' AND
|
||||
reachability IN ['SR', 'RO', 'CR']
|
||||
action: WARN
|
||||
|
||||
- name: allow-vex-not-affected
|
||||
description: Allow CVEs marked not affected by trusted issuer
|
||||
condition: |
|
||||
vex_status == 'not_affected' AND
|
||||
vex_issuer_trust >= 0.8
|
||||
action: PASS
|
||||
|
||||
defaults:
|
||||
action: PASS
|
||||
confidence_threshold: 0.7
|
||||
```
|
||||
|
||||
### 3. VEX Consensus Query
|
||||
|
||||
Policy Engine queries VexLens for VEX statements:
|
||||
|
||||
```http
|
||||
POST /internal/vex/consensus HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
Response with issuer consensus:
|
||||
|
||||
```json
|
||||
{
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": "CVE-2024-1234",
|
||||
"status": "affected",
|
||||
"issuers": [
|
||||
{"name": "vendor-psirt", "trust": 0.95, "status": "affected"},
|
||||
{"name": "osv", "trust": 0.7, "status": "affected"}
|
||||
],
|
||||
"consensus": "affected",
|
||||
"confidence": 0.92
|
||||
},
|
||||
{
|
||||
"vulnerability": "CVE-2024-5678",
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"issuers": [
|
||||
{"name": "vendor-psirt", "trust": 0.95, "status": "not_affected"}
|
||||
],
|
||||
"consensus": "not_affected",
|
||||
"confidence": 0.95
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Reachability State Query
|
||||
|
||||
Policy Engine queries ReachGraph for K4 states:
|
||||
|
||||
```http
|
||||
POST /internal/reachability/states HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
Response with K4 lattice states:
|
||||
|
||||
```json
|
||||
{
|
||||
"states": [
|
||||
{
|
||||
"package": "pkg:npm/lodash@4.17.20",
|
||||
"state": "StaticallyReachable",
|
||||
"evidence": {
|
||||
"static": {"call_paths": 3, "entry_points": ["src/api/handler.js:45"]},
|
||||
"runtime": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "pkg:npm/express@4.18.0",
|
||||
"state": "RuntimeObserved",
|
||||
"evidence": {
|
||||
"static": {"call_paths": 12},
|
||||
"runtime": {"invocations": 1547, "last_seen": "2024-12-29T09:00:00Z"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Rule Evaluation
|
||||
|
||||
Policy Engine evaluates each finding against rules:
|
||||
|
||||
```
|
||||
Finding: CVE-2024-1234 in pkg:npm/lodash@4.17.20
|
||||
- severity: critical
|
||||
- reachability: StaticallyReachable (SR)
|
||||
- vex_status: affected
|
||||
- fixed_version: 4.17.21
|
||||
|
||||
Rule: no-critical-reachable
|
||||
- condition: severity == 'critical' AND reachability IN ['SR', 'RO', 'CR'] AND vex_status != 'not_affected'
|
||||
- evaluation: critical == 'critical' ✓ AND SR IN ['SR', 'RO', 'CR'] ✓ AND 'affected' != 'not_affected' ✓
|
||||
- result: MATCH → FAIL
|
||||
```
|
||||
|
||||
### 6. Confidence Scoring
|
||||
|
||||
Policy Engine computes confidence score based on 5 factors:
|
||||
|
||||
| Factor | Weight | Description |
|
||||
|--------|--------|-------------|
|
||||
| Reachability | 0.30 | K4 state certainty |
|
||||
| Runtime | 0.25 | Runtime observation freshness |
|
||||
| VEX | 0.20 | VEX issuer trust level |
|
||||
| Provenance | 0.15 | SBOM completeness |
|
||||
| Policy | 0.10 | Rule specificity |
|
||||
|
||||
```
|
||||
Confidence = Σ(factor_weight × factor_score)
|
||||
|
||||
For CVE-2024-1234:
|
||||
- Reachability: 0.30 × 0.7 (SR state) = 0.21
|
||||
- Runtime: 0.25 × 0.0 (no runtime data) = 0.00
|
||||
- VEX: 0.20 × 0.92 (affected consensus) = 0.18
|
||||
- Provenance: 0.15 × 1.0 (complete SBOM) = 0.15
|
||||
- Policy: 0.10 × 1.0 (exact rule match) = 0.10
|
||||
|
||||
Total Confidence: 0.64
|
||||
```
|
||||
|
||||
### 7. Verdict Assembly
|
||||
|
||||
Policy Engine assembles final verdict:
|
||||
|
||||
```json
|
||||
{
|
||||
"verdict": "FAIL",
|
||||
"confidence": 0.64,
|
||||
"summary": {
|
||||
"total_findings": 2,
|
||||
"blocked": 1,
|
||||
"warned": 0,
|
||||
"passed": 1
|
||||
},
|
||||
"violations": [
|
||||
{
|
||||
"finding": {
|
||||
"cve": "CVE-2024-1234",
|
||||
"package": "pkg:npm/lodash@4.17.20",
|
||||
"severity": "critical"
|
||||
},
|
||||
"rule": "no-critical-reachable",
|
||||
"action": "FAIL",
|
||||
"explain": {
|
||||
"reason": "Critical CVE with reachable code path",
|
||||
"factors": {
|
||||
"reachability": "StaticallyReachable - 3 call paths from entry points",
|
||||
"vex": "Marked as 'affected' by vendor-psirt (trust: 0.95)",
|
||||
"remediation": "Upgrade lodash to 4.17.21"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"passed": [
|
||||
{
|
||||
"finding": {
|
||||
"cve": "CVE-2024-5678",
|
||||
"package": "pkg:npm/express@4.18.0",
|
||||
"severity": "high"
|
||||
},
|
||||
"rule": "allow-vex-not-affected",
|
||||
"action": "PASS",
|
||||
"explain": {
|
||||
"reason": "VEX statement confirms not affected",
|
||||
"factors": {
|
||||
"vex": "Not affected - vulnerable_code_not_in_execute_path",
|
||||
"issuer": "vendor-psirt (trust: 0.95)"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Data Contracts
|
||||
|
||||
### Policy Rule Schema
|
||||
|
||||
```typescript
|
||||
interface PolicyRule {
|
||||
name: string;
|
||||
description?: string;
|
||||
condition: string; // stella-dsl@1 expression
|
||||
action: 'PASS' | 'WARN' | 'FAIL';
|
||||
priority?: number;
|
||||
exceptions?: Array<{
|
||||
id: string;
|
||||
expires?: string;
|
||||
justification: string;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
### Verdict Schema
|
||||
|
||||
```typescript
|
||||
interface PolicyVerdict {
|
||||
verdict: 'PASS' | 'WARN' | 'FAIL';
|
||||
confidence: number; // 0.0-1.0
|
||||
summary: {
|
||||
total_findings: number;
|
||||
blocked: number;
|
||||
warned: number;
|
||||
passed: number;
|
||||
};
|
||||
violations: Array<ViolationDetail>;
|
||||
warnings: Array<ViolationDetail>;
|
||||
passed: Array<PassedDetail>;
|
||||
metadata: {
|
||||
policy_set: string;
|
||||
policy_version: string;
|
||||
evaluated_at: string;
|
||||
evaluation_ms: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Recovery |
|
||||
|-------|----------|
|
||||
| Policy set not found | Use default policy or return 400 |
|
||||
| VexLens timeout | Continue without VEX data, reduce confidence |
|
||||
| ReachGraph timeout | Use Unknown state, reduce confidence |
|
||||
| Invalid rule syntax | Skip rule, log error, continue |
|
||||
| Conflicting rules | Apply highest priority rule |
|
||||
|
||||
## Observability
|
||||
|
||||
### Metrics
|
||||
|
||||
| Metric | Type | Labels |
|
||||
|--------|------|--------|
|
||||
| `policy_evaluation_total` | Counter | `policy_set`, `verdict` |
|
||||
| `policy_evaluation_duration_ms` | Histogram | `policy_set` |
|
||||
| `policy_rule_matches_total` | Counter | `rule`, `action` |
|
||||
| `policy_confidence_score` | Histogram | `policy_set` |
|
||||
|
||||
### Trace Context
|
||||
|
||||
```
|
||||
policy-evaluation
|
||||
├── policy-load
|
||||
├── vexlens-query
|
||||
├── reachgraph-query
|
||||
├── rule-evaluation
|
||||
│ ├── rule-no-critical-reachable
|
||||
│ ├── rule-no-critical-unfixed
|
||||
│ └── rule-allow-vex-not-affected
|
||||
├── confidence-scoring
|
||||
└── verdict-assembly
|
||||
```
|
||||
|
||||
## Related Flows
|
||||
|
||||
- [Scan Submission Flow](02-scan-submission-flow.md) - Parent flow
|
||||
- [CI/CD Gate Flow](10-cicd-gate-flow.md) - Pipeline integration
|
||||
- [Exception Approval Workflow](17-exception-approval-workflow.md) - Policy exceptions
|
||||
- [Multi-Tenant Policy Rollout Flow](14-multi-tenant-policy-rollout-flow.md) - Policy distribution
|
||||
| ReachGraph timeout | Use Unknown state, reduce confidence |
|
||||
| Invalid rule syntax | Skip rule, log error, continue |
|
||||
| Conflicting rules | Apply highest priority rule |
|
||||
|
||||
## Observability
|
||||
|
||||
### Metrics
|
||||
|
||||
| Metric | Type | Labels |
|
||||
|--------|------|--------|
|
||||
| `policy_evaluation_total` | Counter | `policy_set`, `verdict` |
|
||||
| `policy_evaluation_duration_ms` | Histogram | `policy_set` |
|
||||
| `policy_rule_matches_total` | Counter | `rule`, `action` |
|
||||
| `policy_confidence_score` | Histogram | `policy_set` |
|
||||
|
||||
### Trace Context
|
||||
|
||||
```
|
||||
policy-evaluation
|
||||
├── policy-load
|
||||
├── vexlens-query
|
||||
├── reachgraph-query
|
||||
├── rule-evaluation
|
||||
│ ├── rule-no-critical-reachable
|
||||
│ ├── rule-no-critical-unfixed
|
||||
│ └── rule-allow-vex-not-affected
|
||||
├── confidence-scoring
|
||||
└── verdict-assembly
|
||||
```
|
||||
|
||||
## Related Flows
|
||||
|
||||
- [Scan Submission Flow](02-scan-submission-flow.md) - Parent flow
|
||||
- [CI/CD Gate Flow](10-cicd-gate-flow.md) - Pipeline integration
|
||||
- [Exception Approval Workflow](17-exception-approval-workflow.md) - Policy exceptions
|
||||
- [Multi-Tenant Policy Rollout Flow](14-multi-tenant-policy-rollout-flow.md) - Policy distribution
|
||||
Reference in New Issue
Block a user