273 lines
7.4 KiB
Markdown
273 lines
7.4 KiB
Markdown
# 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.0–1.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)
|