up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-25 22:09:44 +02:00
parent 6bee1fdcf5
commit 9f6e6f7fb3
116 changed files with 4495 additions and 730 deletions

View File

@@ -0,0 +1,56 @@
# Effective Severity Selection
Last updated: 2025-11-25 (Docs Tasks Md.V)
## Goal
Provide a deterministic, explainable way to pick the *effective* severity for a vulnerability or VEX observation when multiple signals exist (CVSS, KEV, exploit intel, VEX status, asset criticality, policy overrides).
## Inputs
- **Base scores**: CVSS v3/v4 (base + temporal) and ecosystem-native severities (npm/yarn, PyPI, Maven). Missing scores are treated as `null`.
- **Exploitability**: KEV flag, EPSS probability, in-the-wild sightings, vendor exploit flags.
- **VEX status**: `not_affected`, `affected`, `fixed`, `under_investigation`, `unknown` (per OpenVEX/CSAF/CycloneDX-VEX).
- **Context signals**: asset criticality, exposure surface (`internet`, `intranet`, `airgap`), runtime enablement flag, workload type.
- **Policy overrides**: tenant/org rules (allow lists, waiver ids, force-upgrade requirements, SLA class).
## Algorithm (deterministic)
1) **Normalize** all scores to a 010 float with 3-decimal rounding; store provenance for each signal.
2) **VEX gate**
- `not_affected` → effective severity `None` (score 0). Short-circuit unless override `force_evaluate=true`.
- `fixed` → keep score but add mitigation note.
3) **Exploit boost**: if `KEV=true` or `EPSS >= 0.7`, set `exploit_boost = +1.0` (cap at 10). Record reason.
4) **Exposure clamp**
- `airgap` → max score 7.0 unless override `allow_airgap_breakglass`.
- `intranet` → no cap; `internet` → no cap.
5) **Criticality weight**: multiply by asset criticality weight (default 1.0; high=1.2, medium=1.0, low=0.8). Clamp 010.
6) **Policy override**: apply explicit tenant rules (force severity, waive to `None`, or constrain max). Overrides always log the applied rule id.
7) **Bucket** into severity bands (stable mapping):
| Score range (inclusive) | Band |
| --- | --- |
| 9.010.0 | Critical |
| 7.08.9 | High |
| 4.06.9 | Medium |
| 0.13.9 | Low |
| 0 | None |
All arithmetic uses `decimal` and rounds only when persisted or returned (3 decimals) to stay replayable.
## Examples
- CVSS 7.5 + KEV + internet + high criticality → base 7.5 → +1.0 exploit → *before clamp* 8.5 → ×1.2 = 10.2 → clamp 10.0 → **Critical**.
- CVSS 5.0, `not_affected` VEX → short-circuit to **None** (score 0) with rationale `vex:not_affected`.
- No CVSS, EPSS 0.2, exposure `airgap` → default score 0, band **None**; remains deterministic.
## Observability
- Emit `stellaops.policy.effective_severity` histogram (010) with tags `tenant`, `source`, `vex_status`, `kev`, `epss_bucket`, `criticality`, `override_id`.
- Log structured event `severity.selected` containing input signals, applied steps, final score/band.
- Traces: span attribute `severity.score` and `severity.band`; link to upstream ingest span (`traceparent` propagated).
## Determinism & Offline posture
- No live network lookups during evaluation; KEV/EPSS/VEX feeds must be preloaded from frozen bundles.
- Sorting of tied severities: break ties by subject id (lexicographic) then source priority (`vex` > `kev` > `cvss` > `ecosystem`).
- All timestamps are UTC ISO-8601; caches keyed by `(tenant, subject, advisory)`.
## Contract for consumers
- API and CLI MUST return both the raw inputs and the chosen band/score so auditors can replay decisions.
- Downstream UIs should surface the rationale chain (steps 26) and any overrides applied.
- Waivers must reference the override id that changed the severity.