Files
git.stella-ops.org/docs/flows/04-policy-evaluation-flow.md
StellaOps Bot ca578801fd save progress
2026-01-03 00:49:19 +02:00

18 KiB
Raw Blame History

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:

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:

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

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:

{
  "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:

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:

{
  "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:

{
  "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

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

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