Files
git.stella-ops.org/docs/modules/policy/guides/risk-provider-configuration.md
2026-01-16 23:30:47 +02:00

273 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Risk Provider Configuration Guide
> **Module:** Policy Engine / RiskProfile
> **Sprint:** SPRINT_20260117_010_CLI_policy_engine (PEN-004)
> **Last Updated:** 2026-01-16
This guide documents the configuration of risk providers within the Stella Ops Policy Engine. Risk providers supply signals (data points) used in risk scoring calculations.
---
## Overview
Risk profiles define how vulnerability findings are scored and prioritized. Each profile consists of:
1. **Signals** — Data sources that contribute to the risk assessment
2. **Weights** — Relative importance of each signal (0.01.0)
3. **Overrides** — Rules that modify severity or decisions based on signal combinations
4. **Metadata** — Optional profile metadata
---
## Risk Profile Schema
Risk profiles follow the `risk-profile-schema@1.json` schema. The canonical schema is available at:
- **Schema URI:** `https://stellaops.dev/schemas/risk-profile-schema@1.json`
- **Source:** `src/Policy/StellaOps.Policy.RiskProfile/Schemas/risk-profile-schema@1.json`
### Required Properties
| Property | Type | Description |
|----------|------|-------------|
| `id` | string | Stable identifier (slug or URN) |
| `version` | string | SemVer version (e.g., `1.0.0`) |
| `signals` | array | Signal definitions (min 1) |
| `weights` | object | Weight per signal name |
| `overrides` | object | Severity and decision overrides |
---
## Signal Configuration
Each signal definition requires:
```json
{
"name": "kev",
"source": "cisa",
"type": "boolean",
"path": "/evidence/kev/known",
"transform": null,
"unit": null
}
```
### Signal Properties
| Property | Required | Type | Description |
|----------|:--------:|------|-------------|
| `name` | ✅ | string | Logical signal key (e.g., `reachability`, `kev`, `exploit_chain`) |
| `source` | ✅ | string | Upstream provider or calculation origin |
| `type` | ✅ | enum | `boolean`, `numeric`, or `categorical` |
| `path` | | string | JSON Pointer to the signal in the evidence document |
| `transform` | | string | Transform applied before weighting (e.g., `log`, `normalize`) |
| `unit` | | string | Unit for numeric signals |
### Built-in Signal Sources
| Source | Signal Names | Type | Description |
|--------|-------------|------|-------------|
| `cvss` | `base_score`, `temporal_score`, `environmental_score` | numeric | CVSS v4.0 scores |
| `epss` | `probability`, `percentile` | numeric | EPSS v4 exploit prediction |
| `cisa` | `kev` | boolean | Known Exploited Vulnerabilities |
| `reachability` | `reachable`, `confidence`, `depth` | mixed | Reachability analysis results |
| `vex` | `status`, `justification` | categorical | VEX consensus status |
| `patch` | `available`, `verified` | boolean | Patch availability evidence |
| `runtime` | `observed`, `observation_count` | mixed | Runtime signal correlation |
---
## Weight Configuration
Weights determine the relative importance of each signal in the final risk score. Weights are normalized by the scoring engine.
```json
{
"weights": {
"base_score": 0.3,
"kev": 0.25,
"reachability": 0.25,
"epss_probability": 0.15,
"patch_available": 0.05
}
}
```
**Weight Rules:**
- Values must be between 0.0 and 1.0
- Weights are normalized (sum to 1.0) at runtime
- Missing signals receive zero contribution
---
## Override Configuration
Overrides allow conditional severity adjustments and decision actions.
### Severity Overrides
```json
{
"overrides": {
"severity": [
{
"when": { "kev": true, "reachable": true },
"set": "critical"
},
{
"when": { "patch_available": true, "reachable": false },
"set": "low"
}
]
}
}
```
**Severity Levels:** `critical`, `high`, `medium`, `low`, `informational`
### Decision Overrides
```json
{
"overrides": {
"decisions": [
{
"when": { "kev": true },
"action": "deny",
"reason": "Active exploitation detected via CISA KEV"
},
{
"when": { "reachable": false, "vex_status": "not_affected" },
"action": "allow",
"reason": "Unreachable and verified not affected"
}
]
}
}
```
**Decision Actions:** `allow`, `review`, `deny`
---
## Example Risk Profile
```json
{
"id": "stella-default-v1",
"version": "1.0.0",
"description": "Default risk profile for container vulnerability assessment",
"signals": [
{ "name": "base_score", "source": "cvss", "type": "numeric", "path": "/cvss/baseScore" },
{ "name": "kev", "source": "cisa", "type": "boolean", "path": "/evidence/kev/known" },
{ "name": "epss_probability", "source": "epss", "type": "numeric", "path": "/epss/probability" },
{ "name": "reachable", "source": "reachability", "type": "boolean", "path": "/reachability/reachable" },
{ "name": "reachability_confidence", "source": "reachability", "type": "numeric", "path": "/reachability/confidence" },
{ "name": "patch_available", "source": "patch", "type": "boolean", "path": "/patch/available" },
{ "name": "vex_status", "source": "vex", "type": "categorical", "path": "/vex/status" }
],
"weights": {
"base_score": 0.25,
"kev": 0.20,
"epss_probability": 0.15,
"reachable": 0.20,
"reachability_confidence": 0.10,
"patch_available": 0.05,
"vex_status": 0.05
},
"overrides": {
"severity": [
{ "when": { "kev": true, "reachable": true }, "set": "critical" },
{ "when": { "reachable": false }, "set": "low" }
],
"decisions": [
{ "when": { "kev": true, "reachable": true }, "action": "deny", "reason": "Active exploitation in reachable code" },
{ "when": { "vex_status": "not_affected" }, "action": "allow", "reason": "VEX confirms not affected" }
]
},
"metadata": {
"author": "platform-team",
"compliance": ["SOC2", "ISO27001"]
}
}
```
---
## CLI Commands
### List Risk Profiles
```bash
stella policy profiles list --format table
```
### Show Profile Details
```bash
stella policy profiles show <profile-id> --format json
```
### Validate Profile
```bash
stella policy profiles validate profile.json
```
### Apply Profile
```bash
stella policy profiles apply <profile-id> --scope tenant:default
```
---
## Configuration Files
Risk profiles can be stored as YAML or JSON:
- **Default location:** `etc/risk-profiles/`
- **Environment variable:** `STELLA_RISK_PROFILES_PATH`
- **Configuration key:** `policy:riskProfiles:path`
### appsettings.yaml Example
```yaml
policy:
riskProfiles:
path: /etc/stella/risk-profiles
default: stella-default-v1
validation:
strict: true
allowUnknownSignals: false
```
---
## Validation Rules
1. **Schema validation** — Profile must conform to `risk-profile-schema@1.json`
2. **Signal consistency** — All signals in `weights` must be defined in `signals`
3. **Weight bounds** — All weights must be in [0.0, 1.0] range
4. **Override predicates**`when` clauses must reference valid signal names
5. **Version format** — Must be valid SemVer
### Validation Errors
| Code | Description |
|------|-------------|
| `RISK_PROFILE_001` | Missing required property |
| `RISK_PROFILE_002` | Invalid weight value |
| `RISK_PROFILE_003` | Unknown signal in weights |
| `RISK_PROFILE_004` | Invalid override predicate |
| `RISK_PROFILE_005` | Version format invalid |
---
## Related Documentation
- [Policy Engine Architecture](../architecture.md)
- [CVSS v4.0 Integration](../cvss-v4.md)
- [Policy Templates](../POLICY_TEMPLATES.md)
- [Determinization Architecture](../determinization-architecture.md)