154 lines
5.3 KiB
Markdown
154 lines
5.3 KiB
Markdown
# Uncertainty States & Entropy Scoring
|
||
|
||
> **Status:** Draft – aligns with the November 2025 advisory on explicit uncertainty tracking.
|
||
> **Owners:** Signals Guild · Concelier Guild · UI Guild.
|
||
|
||
Stella Ops treats missing data and untrusted evidence as **first-class uncertainty states**, not silent false negatives. Each finding stores a list of `UncertaintyState` entries plus supporting evidence; the risk scorer uses their entropy to adjust final risk. Policy and UI surfaces reveal uncertainty to operators rather than hiding it.
|
||
|
||
---
|
||
|
||
## 1. Core states (extensible)
|
||
|
||
| Code | Name | Meaning |
|
||
|------|------------------------|---------------------------------------------------------------------------|
|
||
| `U1` | MissingSymbolResolution| Vulnerability → function mapping unresolved (no PDB/IL map, missing dSYMs). |
|
||
| `U2` | MissingPurl | Package identity/version ambiguous (lockfile absent, heuristics only). |
|
||
| `U3` | UntrustedAdvisory | Advisory source lacks DSSE/Sigstore provenance or corroboration. |
|
||
| `U4+`| (future) | e.g. partial SBOM coverage, missing container layers, unresolved transitives. |
|
||
|
||
Each state records `entropy` (0–1) and an evidence list pointing to analyzers, heuristics, or advisory sources that asserted the uncertainty.
|
||
|
||
---
|
||
|
||
## 2. Schema
|
||
|
||
```jsonc
|
||
{
|
||
"uncertainty": {
|
||
"states": [
|
||
{
|
||
"code": "U1",
|
||
"name": "MissingSymbolResolution",
|
||
"entropy": 0.72,
|
||
"evidence": [
|
||
{
|
||
"type": "AnalyzerProbe",
|
||
"sourceId": "dotnet.symbolizer",
|
||
"detail": "No PDB/IL map for Foo.Bar::DoWork"
|
||
}
|
||
],
|
||
"timestamp": "2025-11-12T14:12:00Z"
|
||
},
|
||
{
|
||
"code": "U2",
|
||
"name": "MissingPurl",
|
||
"entropy": 0.55,
|
||
"evidence": [
|
||
{
|
||
"type": "PackageHeuristic",
|
||
"sourceId": "jar.manifest",
|
||
"detail": "Guessed groupId=com.example, version ~= 1.9.x"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### C# models
|
||
|
||
```csharp
|
||
public sealed record UncertaintyEvidence(string Type, string SourceId, string Detail);
|
||
|
||
public sealed record UncertaintyState(
|
||
string Code,
|
||
string Name,
|
||
double Entropy,
|
||
IReadOnlyList<UncertaintyEvidence> Evidence);
|
||
```
|
||
|
||
Store them alongside `FindingDocument` in Signals and expose via APIs/CLI/GraphQL so downstream services can display them or enforce policies.
|
||
|
||
---
|
||
|
||
## 3. Risk score math
|
||
|
||
```
|
||
riskScore = baseScore
|
||
× reachabilityFactor (0..1)
|
||
× trustFactor (0..1)
|
||
× (1 + entropyBoost)
|
||
|
||
entropyBoost = clamp(avg(uncertainty[i].entropy) × k, 0 .. 0.5)
|
||
```
|
||
|
||
* `k` defaults to `0.5`. With mean entropy = 0.8, boost = 0.4 → risk increases 40% to highlight unknowns.
|
||
* If no uncertainty states exist, entropy boost = 0 and the previous scoring remains.
|
||
|
||
Persist both `uncertainty.states` and `riskScore` so policies, dashboards, and APIs stay deterministic.
|
||
|
||
---
|
||
|
||
## 4. Policy + actions
|
||
|
||
Use uncertainty in Concelier/Excitors policies:
|
||
|
||
* **Block release** if critical CVE has `U1` with entropy ≥ 0.70 until symbols or runtime probes are provided.
|
||
* **Warn** when only `U3` exists – allow deployment but require corroboration (OSV/GHSA, CSAF).
|
||
* **Auto-create tasks** for `U2` to fix SBOM/purl data quality.
|
||
|
||
Recommended policy predicates:
|
||
|
||
```yaml
|
||
when:
|
||
all:
|
||
- uncertaintyCodesAny: ["U1"]
|
||
- maxEntropyGte: 0.7
|
||
```
|
||
|
||
Excitors can suggest remediation actions (upload PDBs, add lockfiles, fetch signed CSAF) based on state codes.
|
||
|
||
---
|
||
|
||
## 5. UI guidelines
|
||
|
||
* Display chips `U1`, `U2`, … on each finding. Tooltip: entropy level + evidence bullets (“AnalyzerProbe/dotnet.symbolizer: …”).
|
||
* Provide “How to reduce entropy” hints: symbol uploads, EventPipe probes, purl overrides, advisory verification.
|
||
* Show entropy in filters (e.g., “entropy ≥ 0.5”) so teams can prioritise closing uncertainty gaps.
|
||
|
||
See `components/UncertaintyChipStack` (planned) for a reference implementation.
|
||
|
||
---
|
||
|
||
## 6. Event sourcing / audit
|
||
|
||
Emit `FindingUncertaintyUpdated` events whenever the set changes:
|
||
|
||
```json
|
||
{
|
||
"type": "FindingUncertaintyUpdated",
|
||
"findingId": "finding:service:prod:CVE-2023-12345",
|
||
"updatedAt": "2025-11-12T14:21:33Z",
|
||
"uncertainty": [ ...states... ]
|
||
}
|
||
```
|
||
|
||
Projections recompute `riskScore` deterministically, and the event log provides an audit trail showing when/why entropy changed.
|
||
|
||
---
|
||
|
||
## 7. Action hints (per state)
|
||
|
||
| Code | Suggested remediation |
|
||
|------|-----------------------|
|
||
| `U1` | Upload PDBs/dSYM files, enable symbolizer connectors, attach runtime probes (EventPipe/JFR). |
|
||
| `U2` | Provide package overrides, ingest lockfiles, fix SBOM generator metadata. |
|
||
| `U3` | Obtain signed CSAF/OSV evidence, verify via Excitors connectors, or mark trust overrides in policy. |
|
||
|
||
### 8. Unknowns registry tie-in
|
||
|
||
Unresolved identities and missing edges should be recorded as Unknowns (see `docs/signals/unknowns-registry.md`). Signals scoring may add an `unknowns_pressure` term when density of unresolved items is high near entrypoints; Policy and UI should surface these records so operators can close the gaps rather than hiding the uncertainty.
|
||
|
||
Keep this file updated as new states (U4+) or tooling hooks land. Link additional guides (symbol upload, purl overrides) once available.
|