# 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 { "scan_id": "scan-7f3a9b2c-...", "tenant_id": "acme-corp", "policy_set": "production", "image": { "name": "docker.io/library/nginx", "digest": "sha256:abc123..." }, "findings": [ { "cve": "CVE-2024-1234", "severity": "critical", "cvss": 9.8, "package": "pkg:npm/lodash@4.17.20", "fixed_version": "4.17.21" }, { "cve": "CVE-2024-5678", "severity": "high", "cvss": 7.5, "package": "pkg:npm/express@4.18.0", "fixed_version": "4.18.2" } ] } ``` ### 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 { "product": "docker.io/library/nginx:1.25", "vulnerabilities": ["CVE-2024-1234", "CVE-2024-5678"] } ``` 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 { "image_digest": "sha256:abc123...", "packages": [ "pkg:npm/lodash@4.17.20", "pkg:npm/express@4.18.0" ] } ``` 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; warnings: Array; passed: Array; 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