Add property-based tests for SBOM/VEX document ordering and Unicode normalization determinism
- Implement `SbomVexOrderingDeterminismProperties` for testing component list and vulnerability metadata hash consistency. - Create `UnicodeNormalizationDeterminismProperties` to validate NFC normalization and Unicode string handling. - Add project file for `StellaOps.Testing.Determinism.Properties` with necessary dependencies. - Introduce CI/CD template validation tests including YAML syntax checks and documentation content verification. - Create validation script for CI/CD templates ensuring all required files and structures are present.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# AI Surfacing UX Patterns Advisory
|
||||
|
||||
**Status:** ANALYZED - Sprint Created
|
||||
**Date:** 2025-12-26
|
||||
**Type:** UX/Design Advisory
|
||||
**Implementation Sprint:** SPRINT_20251226_020_FE_ai_ux_patterns
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This advisory defines how AI results should surface in Stella Ops without becoming obtrusive. The core principle: **AI must behave like a high-quality staff officer—present when needed, silent when not, and always subordinate to evidence and policy.**
|
||||
|
||||
## Core Design Principles
|
||||
|
||||
### 1. Deterministic Verdict First, AI Second
|
||||
|
||||
**Non-negotiable UI ordering:**
|
||||
1. Deterministic verdict (authoritative): severity, policy state, exploitability, SLA, delta
|
||||
2. Evidence summary (authoritative): minimal proof set that drove the verdict
|
||||
3. AI assist (non-authoritative unless evidence-backed): explanation, remediation, suggestions
|
||||
|
||||
### 2. Progressive Disclosure UX
|
||||
|
||||
AI should not add new screens or workflows. It appears as small, optional expansions:
|
||||
- **AI Chips**: Short (3-5 words), action-oriented, clickable
|
||||
- **"Explain" drawer**: Opens on click, not by default
|
||||
|
||||
Chip examples:
|
||||
- "Likely Not Exploitable"
|
||||
- "Reachable Path Found"
|
||||
- "Fix Available: 1-step"
|
||||
- "Needs Evidence: runtime"
|
||||
- "VEX candidate"
|
||||
|
||||
### 3. The "3-Line Doctrine"
|
||||
|
||||
AI output constrained to 3 lines by default:
|
||||
- Line 1: What changed / why you're seeing this now
|
||||
- Line 2: Why it matters in this service
|
||||
- Line 3: Next best action (single step)
|
||||
|
||||
Everything else behind "Show details" / "Show evidence" / "Show alternative fixes"
|
||||
|
||||
### 4. Surface-by-Surface Guidance
|
||||
|
||||
| Surface | AI Behavior |
|
||||
|---------|-------------|
|
||||
| Findings list | 1-2 AI chips max per row; no paragraphs in list view |
|
||||
| Finding detail | 3-panel layout: Verdict → Evidence → AI (subordinate) |
|
||||
| CI/CD output | Opt-in only (`--ai-summary`); max 1 paragraph |
|
||||
| PR comments | Only on state change + actionable fix; no repeated comments |
|
||||
| Notifications | Only on state changes; never "still the same" |
|
||||
| Executive dashboards | No generative narrative; "Top 3 drivers" with evidence links |
|
||||
|
||||
### 5. Contextual Command Bar ("Ask Stella")
|
||||
|
||||
Not a persistent chatbot; a scoped command bar:
|
||||
- Auto-scoped to current context (finding/build/service/release)
|
||||
- Suggested prompts as buttons: "Explain why exploitable", "How to fix?"
|
||||
- Freeform input as secondary option
|
||||
|
||||
### 6. Clear Authority Labels
|
||||
|
||||
Every AI output labeled:
|
||||
- **Evidence-backed**: Links to evidence nodes, citations valid
|
||||
- **Suggestion**: No evidence; user decision required
|
||||
|
||||
### 7. User Controls
|
||||
|
||||
- AI verbosity: Minimal / Standard / Detailed
|
||||
- AI surfaces: Toggle per surface (PR comments, CI logs, UI)
|
||||
- Notifications: Default off; per-team opt-in
|
||||
|
||||
## Implementation Status
|
||||
|
||||
### Created Sprint
|
||||
|
||||
**SPRINT_20251226_020_FE_ai_ux_patterns** (44 tasks):
|
||||
- Phase 1: Core AI Chip Components (7 tasks)
|
||||
- Phase 2: 3-Line AI Summary Component (5 tasks)
|
||||
- Phase 3: AI Panel in Finding Detail (6 tasks)
|
||||
- Phase 4: Contextual Command Bar (6 tasks)
|
||||
- Phase 5: Findings List AI Integration (5 tasks)
|
||||
- Phase 6: User Controls & Preferences (5 tasks)
|
||||
- Phase 7: Dashboard AI Integration (4 tasks)
|
||||
- Phase 8: Testing & Documentation (6 tasks)
|
||||
|
||||
### Dependency Updates
|
||||
|
||||
This sprint is a dependency for:
|
||||
- **SPRINT_20251226_015_AI_zastava_companion**: ZASTAVA-15/16/17/18 (FE tasks)
|
||||
- **SPRINT_20251226_013_FE_triage_canvas**: TRIAGE-14/15/16/17 (AI panel tasks)
|
||||
- **SPRINT_20251226_016_AI_remedy_autopilot**: REMEDY-22/23/24 (FE tasks)
|
||||
|
||||
### Existing Components to Extend
|
||||
|
||||
| Component | Pattern Alignment | Extension Needed |
|
||||
|-----------|-------------------|------------------|
|
||||
| `ReachabilityChipComponent` | ✓ Compact chip | None |
|
||||
| `VexStatusChipComponent` | ✓ Compact chip | None |
|
||||
| `EvidenceDrawerComponent` | ✓ Progressive disclosure | Add AI tab |
|
||||
| `FindingsListComponent` | Partial | Add AI chip slots |
|
||||
| `ConfidenceTierBadgeComponent` | ✓ Authority indicator | Extend for AI |
|
||||
|
||||
## Key Constraints
|
||||
|
||||
1. **No AI text on list views** - chips only
|
||||
2. **3-line default AI** - expandable for more
|
||||
3. **No AI in CI logs unless opt-in** - `--ai-summary` flag
|
||||
4. **PR comments only on state change + actionable fix**
|
||||
5. **AI always subordinate to evidence + deterministic policy**
|
||||
6. **AI must never auto-change enforcement** - no silent downgrades, waivers, or overrides
|
||||
|
||||
## Advisory Content
|
||||
|
||||
[Full advisory content preserved in sprint documentation]
|
||||
@@ -0,0 +1,567 @@
|
||||
# Consolidated Advisory: Deterministic Evidence and Verdict Architecture
|
||||
|
||||
> **Status:** PLANNED — Implementation ~85% complete
|
||||
> **Created:** 2025-12-26
|
||||
> **Consolidated From:**
|
||||
> - `25-Dec-2025 - Building a Deterministic Verdict Engine.md` (original)
|
||||
> - `25-Dec-2025 - Enforcing Canonical JSON for Stable Verdicts.md` (superseded)
|
||||
> - `25-Dec-2025 - Planning Keyless Signing for Verdicts.md` (original)
|
||||
> - `26-Dec-2026 - Smart‑Diff as a Core Evidence Primitive.md` (archived)
|
||||
> - `26-Dec-2026 - Reachability as Cryptographic Proof.md` (archived)
|
||||
> **Technical Specification:** [`docs/technical/architecture/determinism-specification.md`](../technical/architecture/determinism-specification.md)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document consolidates StellaOps guidance on **deterministic verdict computation**, **canonical serialization**, **keyless signing**, and **proof-carrying reachability** into a single authoritative reference. The core proposition:
|
||||
|
||||
**Same SBOM + VEX + reachability subgraph ⇒ exact same, replayable verdict every time—with auditor-grade trails and signed evidence.**
|
||||
|
||||
### Key Capabilities
|
||||
|
||||
1. **Deterministic Evaluation**: Pure functions with no wall-clock, RNG, or network during evaluation
|
||||
2. **Canonical Serialization**: RFC 8785 JCS + Unicode NFC for stable hashes
|
||||
3. **Content-Addressed Storage**: Every input identified by cryptographic hash
|
||||
4. **Keyless Signing**: Sigstore/Fulcio for short-lived certificates with Rekor transparency
|
||||
5. **Proof-Carrying Reachability**: Minimal, reproducible chains showing why vulns can/cannot hit runtime
|
||||
6. **Delta Verdicts**: Signed diffs between evaluation states for CI/CD gates
|
||||
|
||||
### Implementation Status
|
||||
|
||||
| Component | Status | Location |
|
||||
|-----------|--------|----------|
|
||||
| Canonical JSON (JCS) | ✅ COMPLETE | `StellaOps.Canonical.Json` |
|
||||
| NFC String Normalization | ✅ COMPLETE | `StellaOps.Resolver.NfcStringNormalizer` |
|
||||
| Content-Addressed IDs | ✅ COMPLETE | `Attestor.ProofChain/Identifiers/` |
|
||||
| DSSE Signing | ✅ COMPLETE | `Signer/`, `Attestor/` |
|
||||
| Delta Verdict | ✅ COMPLETE | `Policy/Deltas/DeltaVerdict.cs` |
|
||||
| Merkle Trees | ✅ COMPLETE | `ProofChain/Merkle/` |
|
||||
| Determinism Guards | ✅ COMPLETE | `Policy.Engine/DeterminismGuard/` |
|
||||
| Replay Manifest | ✅ COMPLETE | `StellaOps.Replay.Core` |
|
||||
| Feed Snapshot Coordinator | 🔄 TODO | SPRINT_20251226_007 |
|
||||
| Keyless Signing (Fulcio) | 🔄 TODO | SPRINT_20251226_001 |
|
||||
| Cross-Platform Testing | 🔄 TODO | SPRINT_20251226_007 |
|
||||
|
||||
**Overall Progress:** ~85% complete
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Why Determinism Matters](#1-why-determinism-matters)
|
||||
2. [Core Principles](#2-core-principles)
|
||||
3. [Canonical Serialization](#3-canonical-serialization)
|
||||
4. [Data Artifacts](#4-data-artifacts)
|
||||
5. [Signing & Attestation](#5-signing--attestation)
|
||||
6. [Proof-Carrying Reachability](#6-proof-carrying-reachability)
|
||||
7. [Delta Verdicts](#7-delta-verdicts)
|
||||
8. [Engine Architecture](#8-engine-architecture)
|
||||
9. [Testing Strategy](#9-testing-strategy)
|
||||
10. [APIs & Integration](#10-apis--integration)
|
||||
11. [Implementation Status Matrix](#11-implementation-status-matrix)
|
||||
|
||||
---
|
||||
|
||||
## 1. Why Determinism Matters
|
||||
|
||||
### Reproducibility for Auditors
|
||||
Auditors can replay any scan and get identical results. No "it worked on my machine" scenarios—verdicts are cryptographically verifiable.
|
||||
|
||||
### Content-Addressed Caching
|
||||
Hash-based storage enables:
|
||||
- Deduplication across scans
|
||||
- Cache hits on unchanged inputs
|
||||
- Efficient delta computation
|
||||
|
||||
### Cross-Agent Consensus
|
||||
Multiple evaluation engines can independently produce the same verdict for the same manifest, enabling:
|
||||
- Distributed verification
|
||||
- Multi-party attestations
|
||||
- Trust without centralization
|
||||
|
||||
### Operational Clarity
|
||||
Diffs between builds become crisp, machine-verifiable artifacts. When a verdict changes, you know exactly why.
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Principles
|
||||
|
||||
### 2.1 No Wall-Clock Time
|
||||
Evaluation functions never read current time. All timestamps come from input manifests.
|
||||
|
||||
### 2.2 No Random Iteration
|
||||
All collections use deterministic ordering:
|
||||
- Objects: keys sorted lexicographically (Ordinal)
|
||||
- Arrays: preserve input order or sort by stable key
|
||||
- Sets: sort by content hash
|
||||
|
||||
### 2.3 No Network During Evaluation
|
||||
All external data is pre-fetched and pinned by hash before evaluation begins.
|
||||
|
||||
### 2.4 Content-Addressing All Inputs
|
||||
Every input is identified by its cryptographic hash:
|
||||
- `sbom_sha256` - SBOM graph hash
|
||||
- `vex_set_sha256[]` - VEX document hashes
|
||||
- `reach_subgraph_sha256` - Reachability graph hash
|
||||
- `feeds_snapshot_sha256` - Feed snapshot hash
|
||||
- `policy_bundle_sha256` - Policy/rules hash
|
||||
|
||||
### 2.5 Pure Evaluation Functions
|
||||
The verdict function is referentially transparent:
|
||||
```
|
||||
Verdict = f(Manifest)
|
||||
```
|
||||
Given the same manifest, the function always returns the same verdict.
|
||||
|
||||
---
|
||||
|
||||
## 3. Canonical Serialization
|
||||
|
||||
### 3.1 The Rule
|
||||
**Adopt one canonicalization spec and apply it everywhere at ingress/egress of your resolver:**
|
||||
|
||||
- **Strings:** normalize to **UTF-8, Unicode NFC** (Normalization Form C)
|
||||
- **JSON:** canonicalize with **RFC 8785 JCS**: sorted keys, no insignificant whitespace, exact number formatting
|
||||
- **Binary for hashing/signing:** always hash **the canonical bytes**, never ad-hoc serializer output
|
||||
|
||||
### 3.2 Implementation
|
||||
|
||||
```csharp
|
||||
// Canonical JSON with version markers
|
||||
using StellaOps.Canonical.Json;
|
||||
|
||||
var canonical = CanonJson.Canonicalize(myObject);
|
||||
var hash = CanonJson.Hash(myObject);
|
||||
var versionedHash = CanonJson.HashVersioned(myObject, CanonVersion.V1);
|
||||
|
||||
// NFC normalization
|
||||
using StellaOps.Resolver;
|
||||
|
||||
var normalizer = NfcStringNormalizer.Instance;
|
||||
var nfcString = normalizer.Normalize(input);
|
||||
|
||||
// RFC 8785 JCS for raw JSON bytes
|
||||
using StellaOps.Attestor.ProofChain.Json;
|
||||
|
||||
var canonicalizer = new Rfc8785JsonCanonicalizer();
|
||||
var canonicalBytes = canonicalizer.Canonicalize(utf8JsonBytes);
|
||||
```
|
||||
|
||||
### 3.3 Canonicalization Rules
|
||||
|
||||
1. **Object keys** sorted lexicographically (Ordinal comparison)
|
||||
2. **No whitespace** or formatting variations
|
||||
3. **UTF-8 encoding** without BOM
|
||||
4. **IEEE 754 number formatting** (no trailing zeros, no exponent for small integers)
|
||||
5. **Version markers** for migration safety: `_canonVersion: "stella:canon:v1"`
|
||||
|
||||
### 3.4 Contract
|
||||
|
||||
1. Inputs may arrive in any well-formed JSON
|
||||
2. Resolver **normalizes strings (NFC)** and **re-emits JSON in JCS**
|
||||
3. **Content hash** is computed from **JCS-canonical UTF-8 bytes** only
|
||||
4. Any signature/attestation (DSSE/OCI) MUST cover those same bytes
|
||||
5. Any module that can't speak JCS must pass raw data to the resolver
|
||||
|
||||
---
|
||||
|
||||
## 4. Data Artifacts
|
||||
|
||||
### 4.1 Scan Manifest
|
||||
|
||||
The manifest lists all input hashes plus engine version:
|
||||
|
||||
```json
|
||||
{
|
||||
"sbom_sha256": "sha256:a1b2c3...",
|
||||
"vex_set_sha256": ["sha256:d4e5f6...", "sha256:g7h8i9..."],
|
||||
"reach_subgraph_sha256": "sha256:j0k1l2...",
|
||||
"feeds_snapshot_sha256": "sha256:m3n4o5...",
|
||||
"policy_bundle_sha256": "sha256:p6q7r8...",
|
||||
"engine_version": "1.0.0",
|
||||
"policy_semver": "2025.12",
|
||||
"options_hash": "sha256:s9t0u1..."
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Verdict
|
||||
|
||||
Canonical JSON with stable key order:
|
||||
|
||||
```json
|
||||
{
|
||||
"risk_score": 42,
|
||||
"status": "warn",
|
||||
"unknowns_count": 3,
|
||||
"evidence_refs": [
|
||||
"sha256:...",
|
||||
"sha256:..."
|
||||
],
|
||||
"explanations": [
|
||||
{
|
||||
"template": "CVE-{cve} suppressed by VEX claim from {source}",
|
||||
"params": {"cve": "2025-1234", "source": "vendor"},
|
||||
"machine_reason": "VEX_NOT_AFFECTED"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Delta Verdict
|
||||
|
||||
Computed between two manifests/verdicts:
|
||||
|
||||
```json
|
||||
{
|
||||
"base_manifest_sha": "sha256:...",
|
||||
"head_manifest_sha": "sha256:...",
|
||||
"added_findings": [...],
|
||||
"removed_findings": [...],
|
||||
"severity_shift": [...],
|
||||
"unknowns_delta": -2,
|
||||
"policy_effects": [...],
|
||||
"timestamp": "2025-12-26T00:00:00Z",
|
||||
"signature": "..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Signing & Attestation
|
||||
|
||||
### 5.1 Keyless Signing with Sigstore
|
||||
|
||||
Use **keyless** signing in CI pipelines:
|
||||
- Obtain an OIDC token from your CI runner
|
||||
- **Fulcio** issues a short-lived X.509 cert (~10 minutes)
|
||||
- Sign with the ephemeral key
|
||||
- Cert + signature logged to **Rekor**
|
||||
|
||||
**Why:** No key escrow in CI, nothing persistent to steal, every signature is time-bound + transparency-logged.
|
||||
|
||||
### 5.2 Hardware-Backed Org Key
|
||||
|
||||
Reserve a physical HSM/YubiKey (or KMS) key for:
|
||||
- Re-signing monthly bundles
|
||||
- Offline/air-gapped verification workflows
|
||||
|
||||
### 5.3 OCI Attestations
|
||||
|
||||
Emit DSSE/attestations as OCI-attached artifacts:
|
||||
- SBOM deltas
|
||||
- Reachability graphs
|
||||
- Policy results
|
||||
- Verdicts
|
||||
|
||||
### 5.4 Bundle Rotation Policy
|
||||
|
||||
Every month:
|
||||
1. Collect older attestations
|
||||
2. Re-sign into a long-lived "bundle" (plus timestamps) using the org key
|
||||
3. Bundle contains: cert chain, Rekor inclusion proof, timestamps
|
||||
|
||||
**Suggested SLOs:**
|
||||
- CI keyless cert TTL: 10 minutes (Fulcio default)
|
||||
- Bundle cadence: monthly (or per release)
|
||||
- Retention: N=24 months
|
||||
|
||||
### 5.5 Offline Verification
|
||||
|
||||
Mirror the image + attestation + Rekor proof (or bundle) into the disconnected registry. Verify with `cosign verify` using mirrored materials—no internet needed.
|
||||
|
||||
### 5.6 Implementation Sprints
|
||||
|
||||
| Sprint | Module | Topic |
|
||||
|--------|--------|-------|
|
||||
| SPRINT_20251226_001 | Signer | Fulcio keyless signing client |
|
||||
| SPRINT_20251226_002 | Attestor | Monthly bundle rotation |
|
||||
| SPRINT_20251226_003 | Attestor | Offline/air-gap verification |
|
||||
| SPRINT_20251226_004 | Backend | CI/CD integration templates |
|
||||
|
||||
---
|
||||
|
||||
## 6. Proof-Carrying Reachability
|
||||
|
||||
### 6.1 The Concept
|
||||
|
||||
**Reachability** asks: "Could data flow from an attacker to the vulnerable code path during real execution?"
|
||||
|
||||
**Proof-carrying reachability** says: "Don't just say yes/no—hand me a *proof chain* I can re-run."
|
||||
|
||||
### 6.2 Proof Structure
|
||||
|
||||
1. **Scope hash**: content digests for artifact(s) (image layers, SBOM nodes, commit IDs, compiler flags)
|
||||
2. **Policy hash**: the decision rules used
|
||||
3. **Graph snippet**: the *minimal subgraph* connecting entrypoints → sources → validators → sinks
|
||||
4. **Conditions**: feature flags, env vars, platform guards, version ranges, eBPF-observed edges
|
||||
5. **Verdict** (signed): A → {Affected | Not Affected | Under-Constrained} with reason codes
|
||||
6. **Replay manifest**: the inputs needed to recompute the same verdict
|
||||
|
||||
### 6.3 Example Proof
|
||||
|
||||
```
|
||||
Artifact: svc.payments:1.4.7 (image digest sha256:...)
|
||||
CVE: CVE-2024-XYZ in libyaml 0.2.5
|
||||
Entry: POST /import, body → YamlDeserializer.Parse
|
||||
Guards: none (no schema/whitelist prior to parse)
|
||||
Edge chain: HttpBody → Parse(bytes) → LoadNode() → vulnerable_path()
|
||||
Condition: feature flag BULK_IMPORT=true
|
||||
Verdict: AFFECTED
|
||||
Signed: DSSE envelope over {scope hash, policy hash, graph snippet, conditions, verdict}
|
||||
```
|
||||
|
||||
### 6.4 Operating Modes
|
||||
|
||||
| Mode | Unknowns Policy | Proofs |
|
||||
|------|-----------------|--------|
|
||||
| **Strict** (prod) | Fail-closed | Required for Not Affected |
|
||||
| **Lenient** (dev) | Tolerated | Optional but encouraged |
|
||||
|
||||
### 6.5 What to Measure
|
||||
|
||||
- Proof generation rate
|
||||
- Median proof size (KB)
|
||||
- Replay success %
|
||||
- Proof dedup ratio
|
||||
- "Unknowns" burn-down
|
||||
|
||||
---
|
||||
|
||||
## 7. Delta Verdicts
|
||||
|
||||
### 7.1 Evidence Model
|
||||
|
||||
A **semantic delta** captures meaningful differences between two states:
|
||||
|
||||
```json
|
||||
{
|
||||
"subject": {"ociDigest": "sha256:..."},
|
||||
"inputs": {
|
||||
"feeds": [{"type":"cve","digest":"sha256:..."}],
|
||||
"tools": {"sbomer":"1.6.3","reach":"0.9.0","policy":"lattice-2025.12"},
|
||||
"baseline": {"sbomG":"sha256:...","vexSet":"sha256:..."}
|
||||
},
|
||||
"delta": {
|
||||
"components": {"added":[...],"removed":[...],"updated":[...]},
|
||||
"reachability": {"edgesAdded":[...],"edgesRemoved":[...]},
|
||||
"settings": {"changed":[...]},
|
||||
"vex": [{"cve":"CVE-2025-1234","from":"affected","to":"not_affected",
|
||||
"reason":"config_flag_off","evidenceRef":"att#cfg-42"}],
|
||||
"attestations": {"changed":[...]}
|
||||
},
|
||||
"verdict": {
|
||||
"decision": "allow",
|
||||
"riskBudgetUsed": 2,
|
||||
"policyId": "lattice-2025.12",
|
||||
"explanationRefs": ["vex[0]","reachability.edgesRemoved[3]"]
|
||||
},
|
||||
"signing": {"dsse":"...","signer":"stella-authority"}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 Merge Semantics
|
||||
|
||||
Define a policy-controlled lattice for claims:
|
||||
- **Orderings:** `exploit_observed > affected > under_investigation > fixed > not_affected`
|
||||
- **Source weights:** vendor, distro, internal SCA, runtime sensor, pentest
|
||||
- **Conflict rules:** tie-breaks, quorum, freshness windows, required evidence hooks
|
||||
|
||||
### 7.3 OCI Attachment
|
||||
|
||||
Publish delta verdicts as OCI-attached attestations:
|
||||
- Media type: `application/vnd.stella.delta-verdict+json`
|
||||
- Attached alongside SBOM + VEX
|
||||
|
||||
---
|
||||
|
||||
## 8. Engine Architecture
|
||||
|
||||
### 8.1 Evaluation Pipeline
|
||||
|
||||
1. **Normalize inputs**
|
||||
- SBOM: sort by `packageUrl`/`name@version`; resolve aliases
|
||||
- VEX: normalize provider → `vex_id`, `product_ref`, `status`
|
||||
- Reachability: adjacency lists sorted by node ID; hash after topological ordering
|
||||
- Feeds: lock to snapshot (timestamp + commit/hash); no live calls
|
||||
|
||||
2. **Policy bundle**
|
||||
- Declarative rules compiled to canonical IR
|
||||
- Explicit merge precedence (lattice-merge table)
|
||||
- Unknowns policy baked in
|
||||
|
||||
3. **Evaluation**
|
||||
- Build finding set: `(component, vuln, context)` tuples with deterministic IDs
|
||||
- Apply lattice-based VEX merge with evidence pointers
|
||||
- Compute `status` and `risk_score` using fixed-precision math
|
||||
|
||||
4. **Emit**
|
||||
- Canonicalize verdict JSON (RFC 8785 JCS)
|
||||
- Sign verdict (DSSE/COSE/JWS)
|
||||
- Attach as OCI attestation
|
||||
|
||||
### 8.2 Storage & Indexing
|
||||
|
||||
- **CAS (content-addressable store):** `/evidence/<sha256>` for SBOM/VEX/graphs/feeds/policies
|
||||
- **Verdict registry:** keyed by `(image_digest, manifest_sha, engine_version)`
|
||||
- **Delta ledger:** append-only, signed; supports cross-agent consensus
|
||||
|
||||
---
|
||||
|
||||
## 9. Testing Strategy
|
||||
|
||||
### 9.1 Golden Tests
|
||||
|
||||
Fixtures of manifests → frozen verdict JSONs (byte-for-byte comparison).
|
||||
|
||||
```csharp
|
||||
[Theory]
|
||||
[MemberData(nameof(GoldenTestCases))]
|
||||
public async Task Verdict_MatchesGoldenOutput(string manifestPath, string expectedVerdictPath)
|
||||
{
|
||||
var manifest = await LoadManifest(manifestPath);
|
||||
var actual = await _engine.Evaluate(manifest);
|
||||
var expected = await File.ReadAllBytesAsync(expectedVerdictPath);
|
||||
|
||||
Assert.Equal(expected, CanonJson.Canonicalize(actual));
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 Chaos Determinism Tests
|
||||
|
||||
Vary thread counts, env vars, map iteration seeds; assert identical verdicts.
|
||||
|
||||
```csharp
|
||||
[Fact]
|
||||
public async Task Verdict_IsDeterministic_AcrossThreadCounts()
|
||||
{
|
||||
var manifest = CreateTestManifest();
|
||||
var verdicts = new List<byte[]>();
|
||||
|
||||
for (int threads = 1; threads <= 16; threads++)
|
||||
{
|
||||
var verdict = await EvaluateWithThreads(manifest, threads);
|
||||
verdicts.Add(CanonJson.Canonicalize(verdict));
|
||||
}
|
||||
|
||||
Assert.All(verdicts, v => Assert.Equal(verdicts[0], v));
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 Cross-Engine Round-Trips
|
||||
|
||||
Two independent builds of the engine produce the same verdict for the same manifest.
|
||||
|
||||
### 9.4 Time-Travel Tests
|
||||
|
||||
Replay older feed snapshots to ensure stability.
|
||||
|
||||
---
|
||||
|
||||
## 10. APIs & Integration
|
||||
|
||||
### 10.1 API Endpoints
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `POST /evaluate` | Returns `verdict.json` + attestation |
|
||||
| `POST /delta` | Returns `delta.json` (signed) |
|
||||
| `GET /replay?manifest_sha=` | Re-executes with cached snapshots |
|
||||
| `GET /evidence/:cid` | Fetches immutable evidence blobs |
|
||||
|
||||
### 10.2 CLI Commands
|
||||
|
||||
```bash
|
||||
# Evaluate an image
|
||||
stella evaluate --subject sha256:... --policy prod.json
|
||||
|
||||
# Verify delta between versions
|
||||
stella verify delta --from abc123 --to def456 --print-proofs
|
||||
|
||||
# Replay a verdict
|
||||
stella replay --manifest-sha sha256:... --assert-identical
|
||||
```
|
||||
|
||||
### 10.3 UI Integration
|
||||
|
||||
- **Run details → "Verdict" tab:** status, risk score, unknowns, top evidence links
|
||||
- **"Diff" tab:** render Delta Verdict (added/removed/changed) with drill-down to proofs
|
||||
- **"Replay" button:** shows exact manifest & engine version; one-click re-evaluation
|
||||
- **Audit export:** zip of manifest, verdict, delta (if any), attestation, referenced evidence
|
||||
|
||||
---
|
||||
|
||||
## 11. Implementation Status Matrix
|
||||
|
||||
### 11.1 Complete (✅)
|
||||
|
||||
| Component | Location | Notes |
|
||||
|-----------|----------|-------|
|
||||
| Canonical JSON (JCS) | `StellaOps.Canonical.Json` | RFC 8785 compliant |
|
||||
| NFC Normalization | `StellaOps.Resolver.NfcStringNormalizer` | Unicode NFC |
|
||||
| Content-Addressed IDs | `Attestor.ProofChain/Identifiers/` | VerdictId, EvidenceId, GraphRevisionId |
|
||||
| DSSE Signing | `Signer/`, `Attestor/` | Multiple algorithm support |
|
||||
| Delta Verdict | `Policy/Deltas/DeltaVerdict.cs` | Full delta computation |
|
||||
| Merkle Trees | `ProofChain/Merkle/` | Evidence chain verification |
|
||||
| Determinism Guards | `Policy.Engine/DeterminismGuard/` | Runtime enforcement |
|
||||
| Replay Manifest | `StellaOps.Replay.Core` | Full manifest serialization |
|
||||
|
||||
### 11.2 In Progress (🔄)
|
||||
|
||||
| Component | Sprint | Priority |
|
||||
|-----------|--------|----------|
|
||||
| Feed Snapshot Coordinator | SPRINT_20251226_007 (DET-GAP-01..04) | P0 |
|
||||
| Keyless Signing (Fulcio) | SPRINT_20251226_001 | P0 |
|
||||
| Monthly Bundle Rotation | SPRINT_20251226_002 | P1 |
|
||||
| Offline Verification | SPRINT_20251226_003 | P2 |
|
||||
| Cross-Platform Testing | SPRINT_20251226_007 (DET-GAP-11..13) | P1 |
|
||||
|
||||
### 11.3 Planned (📋)
|
||||
|
||||
| Component | Target | Notes |
|
||||
|-----------|--------|-------|
|
||||
| Roslyn Analyzer for Resolver Boundary | Q1 2026 | Compile-time enforcement |
|
||||
| Pre-canonical Hash Debug Logging | Q1 2026 | Audit trail |
|
||||
| Consensus Mode | Q2 2026 | Multi-agent verification |
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Rollout Plan
|
||||
|
||||
### Phase 1: Shadow Mode
|
||||
Introduce Manifest + canonical verdict format alongside existing policy engine.
|
||||
|
||||
### Phase 2: First-Class Verdicts
|
||||
Make verdicts the first-class artifact (OCI-attached); ship UI "Verdict/Diff".
|
||||
|
||||
### Phase 3: Delta Gates
|
||||
Enforce delta-gates in CI/CD (risk budgets + exception packs referenceable by content ID).
|
||||
|
||||
### Phase 4: Consensus Mode
|
||||
Accept externally signed identical delta verdicts to strengthen trust.
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: Archive References
|
||||
|
||||
The following advisories were consolidated into this document:
|
||||
|
||||
| Original File | Archive Location |
|
||||
|--------------|------------------|
|
||||
| `25-Dec-2025 - Building a Deterministic Verdict Engine.md` | (kept in place - primary reference) |
|
||||
| `25-Dec-2025 - Enforcing Canonical JSON for Stable Verdicts.md` | (kept in place - marked superseded) |
|
||||
| `25-Dec-2025 - Planning Keyless Signing for Verdicts.md` | (kept in place - primary reference) |
|
||||
| `26-Dec-2026 - Smart‑Diff as a Core Evidence Primitive.md` | `archived/2025-12-26-superseded/` |
|
||||
| `26-Dec-2026 - Reachability as Cryptographic Proof.md` | `archived/2025-12-26-superseded/` |
|
||||
|
||||
---
|
||||
|
||||
## Appendix C: Related Documents
|
||||
|
||||
| Document | Relationship |
|
||||
|----------|--------------|
|
||||
| [`docs/modules/policy/architecture.md`](../modules/policy/architecture.md) | Policy Engine implementation |
|
||||
| [`docs/modules/policy/design/deterministic-evaluator.md`](../modules/policy/design/deterministic-evaluator.md) | Evaluator design |
|
||||
| [`docs/modules/policy/design/policy-determinism-tests.md`](../modules/policy/design/policy-determinism-tests.md) | Test strategy |
|
||||
| [`docs/modules/scanner/deterministic-execution.md`](../modules/scanner/deterministic-execution.md) | Scanner determinism |
|
||||
| [`docs/technical/architecture/determinism-specification.md`](../technical/architecture/determinism-specification.md) | Technical specification |
|
||||
@@ -0,0 +1,737 @@
|
||||
# Consolidated Advisory: Diff-Aware Release Gates and Risk Budgets
|
||||
|
||||
> **Status:** PLANNED — Consolidated reference document
|
||||
> **Created:** 2025-12-26
|
||||
> **Consolidated From:**
|
||||
> - `25-Dec-2025 - Building a Deterministic Verdict Engine.md` (original)
|
||||
> - `26-Dec-2026 - Diff‑Aware Releases and Auditable Exceptions.md` (archived)
|
||||
> - `26-Dec-2026 - Smart‑Diff as a Core Evidence Primitive.md` (archived)
|
||||
> - `25-Dec-2025 - Visual Diffs for Explainable Triage.md` (archived)
|
||||
> - `26-Dec-2026 - Visualizing the Risk Budget.md` (archived)
|
||||
> - `26-Dec-2026 - Weighted Confidence for VEX Sources.md` (archived)
|
||||
> **Technical References:**
|
||||
> - `archived/2025-12-21-moat-gap-closure/14-Dec-2025 - Smart-Diff Technical Reference.md`
|
||||
> - `archived/2025-12-21-moat-phase2/20-Dec-2025 - Moat Explanation - Risk Budgets and Diff-Aware Release Gates.md`
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document consolidates StellaOps guidance on **diff-aware release gates**, **risk budgets**, **delta verdicts**, and **VEX trust scoring** into a single authoritative reference. The core proposition:
|
||||
|
||||
**Ship fast on low-risk diffs, slow down only when the change warrants it—with deterministic, auditable, replayable evidence at every step.**
|
||||
|
||||
### Key Capabilities
|
||||
|
||||
1. **Risk Budgets**: Quantitative "capacity to take risk" per service tier, preventing reliability degradation
|
||||
2. **Diff-Aware Gates**: Release strictness scales with *what changed*, not generic process
|
||||
3. **Delta Verdicts**: Signed, replayable verdicts comparing before/after states
|
||||
4. **VEX Trust Scoring**: Lattice-based merge of conflicting vulnerability evidence
|
||||
5. **Exception Workflow**: Auditable, evidence-backed, auto-expiring exceptions
|
||||
6. **Visual Diffs**: Explainable triage UI showing exactly what changed and why
|
||||
|
||||
### Implementation Status
|
||||
|
||||
| Component | Status | Location |
|
||||
|-----------|--------|----------|
|
||||
| Canonical JSON (JCS) | COMPLETE | `StellaOps.Canonical.Json` |
|
||||
| Delta Verdict Engine | COMPLETE | `StellaOps.DeltaVerdict.Engine` |
|
||||
| Smart-Diff UI | COMPLETE | `TriageWorkspaceComponent` |
|
||||
| Proof Tree Visualization | COMPLETE | `ProofTreeComponent` |
|
||||
| VEX Merge with Trust Scoring | COMPLETE | `Policy.Engine/VexMerge/` |
|
||||
| Exception Entity Model | COMPLETE | `Policy.Engine/Exceptions/` |
|
||||
| Risk Budget Dashboard | TODO | Sprint 2025Q1 |
|
||||
| Feed Snapshot Coordinator | TODO | SPRINT_20251226_007 |
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Core Concepts](#1-core-concepts)
|
||||
2. [Risk Budget Model](#2-risk-budget-model)
|
||||
3. [Release Gate Levels](#3-release-gate-levels)
|
||||
4. [Delta Verdict Engine](#4-delta-verdict-engine)
|
||||
5. [Smart-Diff Algorithm](#5-smart-diff-algorithm)
|
||||
6. [Exception Workflow](#6-exception-workflow)
|
||||
7. [VEX Trust Scoring](#7-vex-trust-scoring)
|
||||
8. [UI/UX Patterns](#8-uiux-patterns)
|
||||
9. [CI/CD Integration](#9-cicd-integration)
|
||||
10. [Data Models](#10-data-models)
|
||||
|
||||
---
|
||||
|
||||
## 1. Core Concepts
|
||||
|
||||
### 1.1 SBOM, VEX, and Reachability
|
||||
|
||||
- **SBOM (Software Bill of Materials)**: Complete inventory of components (CycloneDX 1.6 / SPDX 3.0.1)
|
||||
- **VEX (Vulnerability Exploitability eXchange)**: Claims about whether vulnerabilities affect a specific product
|
||||
- **Reachability**: Analysis of whether vulnerable code paths are actually exercised at runtime
|
||||
|
||||
### 1.2 Semantic Delta
|
||||
|
||||
A **semantic delta** captures *meaningful* differences between two states:
|
||||
|
||||
- Components added/removed/updated
|
||||
- Reachability edges added/removed
|
||||
- VEX claim transitions (affected → not_affected)
|
||||
- Configuration/feature flag changes
|
||||
- Attestation/provenance changes
|
||||
|
||||
### 1.3 Determinism-First Principles
|
||||
|
||||
All verdict computations must be:
|
||||
|
||||
- **Reproducible**: Same inputs → identical outputs, always
|
||||
- **Content-addressed**: Every input identified by cryptographic hash
|
||||
- **Declarative**: Compact manifest lists all input hashes + engine version
|
||||
- **Pure**: No wall-clock time, no random iteration, no network during evaluation
|
||||
|
||||
---
|
||||
|
||||
## 2. Risk Budget Model
|
||||
|
||||
### 2.1 Service Tiers
|
||||
|
||||
Each service/product component must be assigned a **Criticality Tier**:
|
||||
|
||||
| Tier | Description | Monthly Budget (RP) |
|
||||
|------|-------------|---------------------|
|
||||
| **Tier 0** | Internal only, low business impact | 300 |
|
||||
| **Tier 1** | Customer-facing non-critical | 200 |
|
||||
| **Tier 2** | Customer-facing critical | 120 |
|
||||
| **Tier 3** | Safety/financial/data-critical | 80 |
|
||||
|
||||
### 2.2 Risk Point Scoring
|
||||
|
||||
**Release Risk Score (RRS) = Base + Diff Risk + Operational Context − Mitigations**
|
||||
|
||||
**Base (by criticality):**
|
||||
- Tier 0: +1
|
||||
- Tier 1: +3
|
||||
- Tier 2: +6
|
||||
- Tier 3: +10
|
||||
|
||||
**Diff Risk (additive):**
|
||||
| Change Type | Points |
|
||||
|-------------|--------|
|
||||
| Docs, comments, non-executed code | +1 |
|
||||
| UI changes, refactors with high coverage | +3 |
|
||||
| API contract changes, dependency upgrades | +6 |
|
||||
| Database schema migrations, auth logic | +10 |
|
||||
| Infra/networking, encryption, payment flows | +15 |
|
||||
|
||||
**Operational Context (additive):**
|
||||
| Condition | Points |
|
||||
|-----------|--------|
|
||||
| Active incident or recent Sev1/Sev2 | +5 |
|
||||
| Error budget < 50% remaining | +3 |
|
||||
| High on-call load | +2 |
|
||||
| Release during freeze window | +5 |
|
||||
|
||||
**Mitigations (subtract):**
|
||||
| Control | Points |
|
||||
|---------|--------|
|
||||
| Feature flag with staged rollout + kill switch | −3 |
|
||||
| Canary + automated health gates + tested rollback | −3 |
|
||||
| High-confidence integration coverage | −2 |
|
||||
| Backward-compatible migration with proven rollback | −2 |
|
||||
| Change isolated behind permission boundary | −2 |
|
||||
|
||||
### 2.3 Budget Thresholds
|
||||
|
||||
| Status | Remaining | Action |
|
||||
|--------|-----------|--------|
|
||||
| **Green** | ≥60% | Normal operation |
|
||||
| **Yellow** | 30–59% | Gates tighten by 1 level for medium/high-risk diffs |
|
||||
| **Red** | <30% | Freeze high-risk diffs; allow only low-risk or reliability work |
|
||||
| **Exhausted** | ≤0% | Incident/security fixes only with explicit sign-off |
|
||||
|
||||
### 2.4 Risk Budget Visualization
|
||||
|
||||
The **Risk Budget Burn-Up Chart** is the key PM dashboard:
|
||||
|
||||
- **X-axis**: Calendar dates up to code freeze
|
||||
- **Y-axis**: Risk points
|
||||
- **Budget line**: Allowable risk over time (flat or stepped)
|
||||
- **Actual Risk line**: Cumulative unknowns + knowns − mitigations
|
||||
- **Shaded area**: Headroom (green) or Overrun (red)
|
||||
- **Vertical markers**: Feature freeze, pen-test start, dependency bumps
|
||||
- **Burn targets**: Dotted lines showing required pace
|
||||
|
||||
**Dashboard KPIs:**
|
||||
- "Headroom: 28 pts (green)"
|
||||
- "Unknowns↑ +6 (24h)", "Risk retired −18 (7d)"
|
||||
- "Exceptions expiring: 3"
|
||||
- "At current burn, overrun in 5 days"
|
||||
|
||||
---
|
||||
|
||||
## 3. Release Gate Levels
|
||||
|
||||
### 3.1 Gate Definitions
|
||||
|
||||
#### G0 — No-risk / Administrative
|
||||
**Use for:** docs-only, comments-only, non-functional metadata
|
||||
|
||||
**Requirements:**
|
||||
- Lint/format checks
|
||||
- Basic CI pass (build)
|
||||
|
||||
#### G1 — Low Risk
|
||||
**Use for:** small localized changes with strong unit coverage, non-core UI, telemetry additions
|
||||
|
||||
**Requirements:**
|
||||
- All automated unit tests
|
||||
- Static analysis/linting
|
||||
- 1 peer review
|
||||
- Automated deploy to staging
|
||||
- Post-deploy smoke checks
|
||||
|
||||
#### G2 — Moderate Risk
|
||||
**Use for:** moderate logic changes in customer-facing paths, dependency upgrades, backward-compatible API changes
|
||||
|
||||
**Requirements:**
|
||||
- G1 +
|
||||
- Integration tests for impacted modules
|
||||
- Code owner review
|
||||
- Feature flag required if customer impact possible
|
||||
- Staged rollout: canary or small cohort
|
||||
- Rollback plan documented in PR
|
||||
|
||||
#### G3 — High Risk
|
||||
**Use for:** schema migrations, auth/permission changes, core business logic, infra changes
|
||||
|
||||
**Requirements:**
|
||||
- G2 +
|
||||
- Security scan + dependency audit
|
||||
- Migration plan (forward + rollback) reviewed
|
||||
- Load/performance checks if in hot path
|
||||
- New/updated dashboards/alerts
|
||||
- Release captain sign-off
|
||||
- Progressive delivery with automatic health gates
|
||||
|
||||
#### G4 — Very High Risk / Safety-Critical
|
||||
**Use for:** Tier 3 systems with low budget, freeze window exceptions, broad blast radius, post-incident remediation
|
||||
|
||||
**Requirements:**
|
||||
- G3 +
|
||||
- Formal risk review (PM+DM+Security/SRE) in writing
|
||||
- Explicit rollback rehearsal
|
||||
- Extended canary with success/abort criteria
|
||||
- Customer comms plan if impact plausible
|
||||
- Post-release verification checklist executed
|
||||
|
||||
### 3.2 Gate Selection Logic
|
||||
|
||||
1. Compute **RRS** from diff + context
|
||||
2. Map RRS to default gate:
|
||||
- 1–5 RP → G1
|
||||
- 6–12 RP → G2
|
||||
- 13–20 RP → G3
|
||||
- 21+ RP → G4
|
||||
3. Apply modifiers:
|
||||
- Budget Yellow → escalate one gate for ≥G2
|
||||
- Budget Red → escalate one gate for ≥G1, block high-risk unless exception
|
||||
- Active incident → block non-fix releases by default
|
||||
|
||||
---
|
||||
|
||||
## 4. Delta Verdict Engine
|
||||
|
||||
### 4.1 Core Architecture
|
||||
|
||||
The delta verdict engine computes **deterministic, signed verdicts** comparing two states:
|
||||
|
||||
```
|
||||
Verdict = f(Manifest)
|
||||
```
|
||||
|
||||
Where `Manifest` contains:
|
||||
- `sbom_sha256` - SBOM graph hash
|
||||
- `vex_set_sha256[]` - VEX document hashes
|
||||
- `reach_subgraph_sha256` - Reachability graph hash
|
||||
- `feeds_snapshot_sha256` - Feed snapshot hash
|
||||
- `policy_bundle_sha256` - Policy/rules hash
|
||||
- `engine_version` - Engine version for reproducibility
|
||||
|
||||
### 4.2 Evaluation Pipeline
|
||||
|
||||
1. **Normalize inputs**
|
||||
- SBOM: sort by `packageUrl`/`name@version`; resolve aliases
|
||||
- VEX: normalize provider → `vex_id`, `product_ref`, `status`
|
||||
- Reachability: adjacency lists sorted by node ID; hash after topological ordering
|
||||
- Feeds: lock to snapshot (timestamp + commit/hash); no live calls
|
||||
|
||||
2. **Policy bundle**
|
||||
- Declarative rules compiled to canonical IR
|
||||
- Explicit merge precedence (lattice-merge table)
|
||||
- Unknowns policy baked in: e.g., `fail_if_unknowns > N in prod`
|
||||
|
||||
3. **Evaluation**
|
||||
- Build finding set: `(component, vuln, context)` tuples with deterministic IDs
|
||||
- Apply lattice-based VEX merge with evidence pointers
|
||||
- Compute `status` and `risk_score` using fixed-precision math
|
||||
|
||||
4. **Emit**
|
||||
- Canonicalize verdict JSON (RFC 8785 JCS)
|
||||
- Sign verdict (DSSE/COSE/JWS)
|
||||
- Attach as OCI attestation to image/digest
|
||||
|
||||
### 4.3 Delta Verdict Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"subject": {"ociDigest": "sha256:..."},
|
||||
"inputs": {
|
||||
"feeds": [{"type":"cve","digest":"sha256:..."}],
|
||||
"tools": {"sbomer":"1.6.3","reach":"0.9.0","policy":"lattice-2025.12"},
|
||||
"baseline": {"sbomG":"sha256:...","vexSet":"sha256:..."}
|
||||
},
|
||||
"delta": {
|
||||
"components": {"added":[...],"removed":[...],"updated":[...]},
|
||||
"reachability": {"edgesAdded":[...],"edgesRemoved":[...]},
|
||||
"settings": {"changed":[...]},
|
||||
"vex": [{"cve":"CVE-2025-1234","from":"affected","to":"not_affected",
|
||||
"reason":"config_flag_off","evidenceRef":"att#cfg-42"}],
|
||||
"attestations": {"changed":[...]}
|
||||
},
|
||||
"verdict": {
|
||||
"decision": "allow",
|
||||
"riskBudgetUsed": 2,
|
||||
"policyId": "lattice-2025.12",
|
||||
"explanationRefs": ["vex[0]","reachability.edgesRemoved[3]"]
|
||||
},
|
||||
"signing": {"dsse":"...","signer":"stella-authority"}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 Replay Contract
|
||||
|
||||
For deterministic replay, pin and record:
|
||||
- Feed snapshots + hashes
|
||||
- Scanner versions + rule packs + lattice/policy version
|
||||
- SBOM generator version + mode
|
||||
- Reachability engine settings
|
||||
- Merge semantics ID
|
||||
|
||||
**Replayer re-hydrates exact inputs and must reproduce the same verdict bit-for-bit.**
|
||||
|
||||
---
|
||||
|
||||
## 5. Smart-Diff Algorithm
|
||||
|
||||
### 5.1 Material Risk Change Detection
|
||||
|
||||
**FindingKey:** `(component_purl, component_version, cve_id)`
|
||||
|
||||
**RiskState Fields:**
|
||||
- `reachable: bool | unknown`
|
||||
- `vex_status: enum` (AFFECTED | NOT_AFFECTED | FIXED | UNDER_INVESTIGATION | UNKNOWN)
|
||||
- `in_affected_range: bool | unknown`
|
||||
- `kev: bool`
|
||||
- `epss_score: float | null`
|
||||
- `policy_flags: set<string>`
|
||||
- `evidence_links: list<EvidenceLink>`
|
||||
|
||||
### 5.2 Change Detection Rules
|
||||
|
||||
**Rule R1: Reachability Flip**
|
||||
- `reachable` changes: `false → true` (risk ↑) or `true → false` (risk ↓)
|
||||
|
||||
**Rule R2: VEX Status Flip**
|
||||
- Meaningful changes: `AFFECTED ↔ NOT_AFFECTED`, `UNDER_INVESTIGATION → NOT_AFFECTED`
|
||||
|
||||
**Rule R3: Affected Range Boundary**
|
||||
- `in_affected_range` flips: `false → true` or `true → false`
|
||||
|
||||
**Rule R4: Intelligence/Policy Flip**
|
||||
- `kev` changes `false → true`
|
||||
- `epss_score` crosses configured threshold
|
||||
- `policy_flag` changes severity (warn → block)
|
||||
|
||||
### 5.3 Suppression Rules
|
||||
|
||||
**All must apply for suppression:**
|
||||
1. `reachable == false`
|
||||
2. `vex_status == NOT_AFFECTED`
|
||||
3. `kev == false`
|
||||
4. No policy override
|
||||
|
||||
**Patch Churn Suppression:**
|
||||
- If version changes AND `in_affected_range` remains false in both AND no KEV/policy flip → suppress
|
||||
|
||||
### 5.4 Priority Score Formula
|
||||
|
||||
```
|
||||
score =
|
||||
+ 1000 if new.kev
|
||||
+ 500 if new.reachable
|
||||
+ 200 if reason includes RANGE_FLIP to affected
|
||||
+ 150 if VEX_FLIP to AFFECTED
|
||||
+ 0..100 based on EPSS (epss * 100)
|
||||
+ policy weight: +300 if decision BLOCK, +100 if WARN
|
||||
```
|
||||
|
||||
### 5.5 Reachability Gate (3-Bit Severity)
|
||||
|
||||
```csharp
|
||||
public sealed record ReachabilityGate(
|
||||
bool? Reachable, // true / false / null for unknown
|
||||
bool? ConfigActivated,
|
||||
bool? RunningUser,
|
||||
int Class, // 0..7 derived from the bits when all known
|
||||
string Rationale
|
||||
);
|
||||
```
|
||||
|
||||
**Class Computation:** 0-7 based on 3 binary gates (reachable, config-activated, running user)
|
||||
|
||||
**Unknown Handling:** Never silently treat `null` as `false` or `true`. If any bit is `null`, set `Class = -1` or compute from known bits only.
|
||||
|
||||
---
|
||||
|
||||
## 6. Exception Workflow
|
||||
|
||||
### 6.1 Exception Entity Model
|
||||
|
||||
```csharp
|
||||
public record Exception(
|
||||
string Id,
|
||||
string Scope, // image:repo/app:tag, component:pkg@ver
|
||||
string Subject, // CVE-2025-1234, package name
|
||||
string Reason, // Human-readable justification
|
||||
List<string> EvidenceRefs, // att:sha256:..., vex:sha256:...
|
||||
string CreatedBy,
|
||||
DateTime CreatedAt,
|
||||
DateTime? ExpiresAt,
|
||||
string PolicyBinding,
|
||||
string Signature
|
||||
);
|
||||
```
|
||||
|
||||
### 6.2 Exception Requirements
|
||||
|
||||
- **Signed rationale + evidence**: Justification with linked proofs (attestation IDs, VEX note, reachability subgraph slice)
|
||||
- **Auto-expiry & revalidation**: Scheduler re-tests on expiry or when feeds mark "fix available / EPSS ↑ / reachability ↑"
|
||||
- **Audit view**: Timeline of exception lifecycle (who/why, evidence, re-checks)
|
||||
- **Policy hooks**: "allow only if: reason ∧ evidence present ∧ max TTL ≤ X ∧ owner = team-Y"
|
||||
- **Inheritance**: repo→image→env scoping with explicit shadowing
|
||||
|
||||
### 6.3 Exception CLI
|
||||
|
||||
```bash
|
||||
stella exception create \
|
||||
--cve CVE-2025-1234 \
|
||||
--scope image:repo/app:tag \
|
||||
--reason "Feature disabled" \
|
||||
--evidence att:sha256:... \
|
||||
--ttl 30d
|
||||
```
|
||||
|
||||
### 6.4 Break-Glass Policy
|
||||
|
||||
Exceptions permitted only for:
|
||||
- Incident mitigation or customer harm prevention
|
||||
- Urgent security fix (actively exploited or high severity)
|
||||
- Legal/compliance deadline
|
||||
|
||||
**Requirements:**
|
||||
- Recorded rationale in PR/release ticket
|
||||
- Named approvers: DM + on-call owner; PM for customer-impacting risk
|
||||
- Mandatory follow-up within 5 business days
|
||||
- **Budget penalty:** +50% of change's RRS
|
||||
|
||||
---
|
||||
|
||||
## 7. VEX Trust Scoring
|
||||
|
||||
### 7.1 Evidence Atoms
|
||||
|
||||
For every VEX statement, extract:
|
||||
- **scope**: package@version, image@digest, file hash
|
||||
- **claim**: affected, not_affected, under_investigation, fixed
|
||||
- **reason**: reachable?, feature flag off, vulnerable code not present
|
||||
- **provenance**: who said it, how it's signed
|
||||
- **when**: issued_at, observed_at, expires_at
|
||||
- **supporting artifacts**: SBOM ref, in-toto link, CVE IDs
|
||||
|
||||
### 7.2 Confidence Score (C: 0–1)
|
||||
|
||||
Multiply factors, cap at 1:
|
||||
|
||||
| Factor | Weight |
|
||||
|--------|--------|
|
||||
| DSSE + Sigstore/Rekor inclusion | 0.35 |
|
||||
| Hardware-backed key or org OIDC | 0.15 |
|
||||
| NVD source | 0.20 |
|
||||
| Major distro PSIRT | 0.20 |
|
||||
| Upstream vendor | 0.20 |
|
||||
| Reputable CERT | 0.15 |
|
||||
| Small vendor | 0.10 |
|
||||
| Reachability proof/test | 0.25 |
|
||||
| Code diff linking | 0.20 |
|
||||
| Deterministic build link | 0.15 |
|
||||
| "Reason" present | 0.10 |
|
||||
| ≥2 independent concurring sources | +0.10 |
|
||||
|
||||
### 7.3 Freshness Score (F: 0–1)
|
||||
|
||||
```
|
||||
F = exp(−Δdays / τ)
|
||||
```
|
||||
|
||||
**τ values by source class:**
|
||||
- Vendor VEX: τ = 30
|
||||
- NVD: τ = 90
|
||||
- Exploit-active feeds: τ = 14
|
||||
|
||||
**Update reset:** New attestation with same subject resets Δdays.
|
||||
**Expiry clamp:** If `now > expires_at`, set F = 0.
|
||||
|
||||
### 7.4 Claim Strength (S_claim)
|
||||
|
||||
| Claim | Base Weight |
|
||||
|-------|-------------|
|
||||
| not_affected | 0.9 |
|
||||
| fixed | 0.8 |
|
||||
| affected | 0.7 |
|
||||
| under_investigation | 0.4 |
|
||||
|
||||
**Reason multipliers:**
|
||||
- reachable? → +0.15 to "affected"
|
||||
- "feature flag off" → +0.10 to "not_affected"
|
||||
- platform mismatch → +0.10
|
||||
- backport patch note (with commit hash) → +0.10
|
||||
|
||||
### 7.5 Lattice Merge
|
||||
|
||||
Per evidence `e`:
|
||||
```
|
||||
Score(e) = C(e) × F(e) × S_claim(e)
|
||||
```
|
||||
|
||||
Merge in distributive lattice ordered by:
|
||||
1. **Claim precedence**: not_affected > fixed > affected > under_investigation
|
||||
2. Break ties by **Score(e)**
|
||||
3. If competing top claims within ε (0.05), **escalate to "disputed"** and surface both with proofs
|
||||
|
||||
### 7.6 Worked Example
|
||||
|
||||
**Small vendor Sigstore VEX (signed, reason: code path unreachable, issued 7 days ago):**
|
||||
- C ≈ 0.35 + 0.10 + 0.10 + 0.25 = 0.70
|
||||
- F = exp(−7/30) ≈ 0.79
|
||||
- S_claim = 0.9 + 0.10 = 1.0 (capped)
|
||||
- **Score ≈ 0.70 × 0.79 × 1.0 = 0.55**
|
||||
|
||||
**NVD entry (affected, no reasoning, 180 days old):**
|
||||
- C ≈ 0.20
|
||||
- F = exp(−180/90) ≈ 0.14
|
||||
- S_claim = 0.7
|
||||
- **Score ≈ 0.20 × 0.14 × 0.7 = 0.02**
|
||||
|
||||
**Outcome:** Vendor VEX wins → **not_affected** with linked proofs.
|
||||
|
||||
---
|
||||
|
||||
## 8. UI/UX Patterns
|
||||
|
||||
### 8.1 Three-Pane Layout
|
||||
|
||||
1. **Categories Pane**: Filterable list of change categories
|
||||
2. **Items Pane**: Delta items within selected category
|
||||
3. **Proof Pane**: Evidence details for selected item
|
||||
|
||||
### 8.2 Visual Diff Components
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `DeltaSummaryStripComponent` | Risk delta header: "Risk ↓ Medium → Low" |
|
||||
| `ProofPaneComponent` | Evidence rail with witness paths |
|
||||
| `VexMergeExplanationComponent` | Trust algebra visualization |
|
||||
| `CompareViewComponent` | Side-by-side before/after |
|
||||
| `TriageShortcutsService` | Keyboard navigation |
|
||||
|
||||
### 8.3 Micro-interactions
|
||||
|
||||
- **Hover changed node** → inline badge explaining *why it changed*
|
||||
- **Click rule change** → spotlight the exact subgraph it affected
|
||||
- **"Explain like I'm new" toggle** → expand jargon into plain language
|
||||
- **"Copy audit bundle"** → export delta + evidence as attachment
|
||||
|
||||
### 8.4 Hotkeys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `1` | Focus changes only |
|
||||
| `2` | Show full graph |
|
||||
| `E` | Expand evidence |
|
||||
| `A` | Export audit |
|
||||
|
||||
### 8.5 Empty States
|
||||
|
||||
- **Incomplete evidence**: Yellow "Unknowns present" ribbon with count and collection button
|
||||
- **Huge graphs**: Default to "changed neighborhood only" with mini-map
|
||||
|
||||
---
|
||||
|
||||
## 9. CI/CD Integration
|
||||
|
||||
### 9.1 API Endpoints
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `POST /evaluate` | Returns `verdict.json` + attestation |
|
||||
| `POST /delta` | Returns `delta.json` (signed) |
|
||||
| `GET /replay?manifest_sha=` | Re-executes with cached snapshots |
|
||||
| `GET /evidence/:cid` | Fetches immutable evidence blobs |
|
||||
|
||||
### 9.2 CLI Commands
|
||||
|
||||
```bash
|
||||
# Verify delta between two versions
|
||||
stella verify delta \
|
||||
--from abc123 \
|
||||
--to def456 \
|
||||
--policy prod.json \
|
||||
--print-proofs
|
||||
|
||||
# Create exception
|
||||
stella exception create \
|
||||
--cve CVE-2025-1234 \
|
||||
--scope image:repo/app:tag \
|
||||
--reason "Feature disabled" \
|
||||
--evidence att:sha256:... \
|
||||
--ttl 30d
|
||||
|
||||
# Replay a verdict
|
||||
stella replay \
|
||||
--manifest-sha sha256:... \
|
||||
--assert-identical
|
||||
```
|
||||
|
||||
### 9.3 Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | PASS - Release allowed |
|
||||
| 1 | FAIL - Gate blocked |
|
||||
| 2 | WARN - Proceed with caution |
|
||||
| 3 | ERROR - Evaluation failed |
|
||||
|
||||
### 9.4 Pipeline Recipe
|
||||
|
||||
```yaml
|
||||
release-gate:
|
||||
script:
|
||||
- stella evaluate --subject $IMAGE_DIGEST --policy $GATE_POLICY
|
||||
- |
|
||||
if [ $? -eq 1 ]; then
|
||||
echo "Gate blocked - risk budget exceeded or policy violation"
|
||||
exit 1
|
||||
fi
|
||||
- stella delta --from $BASELINE --to $IMAGE_DIGEST --export audit-bundle.zip
|
||||
artifacts:
|
||||
paths:
|
||||
- audit-bundle.zip
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Data Models
|
||||
|
||||
### 10.1 Scan Manifest
|
||||
|
||||
```json
|
||||
{
|
||||
"sbom_sha256": "sha256:...",
|
||||
"vex_set_sha256": ["sha256:..."],
|
||||
"reach_subgraph_sha256": "sha256:...",
|
||||
"feeds_snapshot_sha256": "sha256:...",
|
||||
"policy_bundle_sha256": "sha256:...",
|
||||
"engine_version": "1.0.0",
|
||||
"policy_semver": "2025.12",
|
||||
"options_hash": "sha256:..."
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 Verdict
|
||||
|
||||
```json
|
||||
{
|
||||
"risk_score": 42,
|
||||
"status": "pass|warn|fail",
|
||||
"unknowns_count": 3,
|
||||
"evidence_refs": ["sha256:...", "sha256:..."],
|
||||
"explanations": [
|
||||
{"template": "CVE-{cve} suppressed by VEX claim from {source}",
|
||||
"params": {"cve": "2025-1234", "source": "vendor"}}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 10.3 Smart-Diff Predicate
|
||||
|
||||
```json
|
||||
{
|
||||
"predicateType": "stellaops.dev/predicates/smart-diff@v1",
|
||||
"predicate": {
|
||||
"baseImage": {"name":"...", "digest":"sha256:..."},
|
||||
"targetImage": {"name":"...", "digest":"sha256:..."},
|
||||
"diff": {
|
||||
"filesAdded": [...],
|
||||
"filesRemoved": [...],
|
||||
"filesChanged": [{"path":"...", "hunks":[...]}],
|
||||
"packagesChanged": [{"name":"openssl","from":"1.1.1u","to":"3.0.14"}]
|
||||
},
|
||||
"context": {
|
||||
"entrypoint":["/app/start"],
|
||||
"env":{"FEATURE_X":"true"},
|
||||
"user":{"uid":1001,"caps":["NET_BIND_SERVICE"]}
|
||||
},
|
||||
"reachabilityGate": {"reachable":true,"configActivated":true,"runningUser":false,"class":6}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Success Metrics
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| **Mean Time to Explain (MTTE)** | Time from "why did this change?" to "Understood" |
|
||||
| **Change Failure Rate** | % of releases causing incidents |
|
||||
| **MTTR** | Mean time to recovery |
|
||||
| **Gate Compliance Rate** | % of releases following required gates |
|
||||
| **Budget Utilization** | Actual RP consumed vs. allocated |
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: Related Documents
|
||||
|
||||
| Document | Relationship |
|
||||
|----------|--------------|
|
||||
| [`docs/modules/policy/architecture.md`](../modules/policy/architecture.md) | Policy Engine implementation |
|
||||
| [`docs/modules/scanner/architecture.md`](../modules/scanner/architecture.md) | Scanner/Reachability implementation |
|
||||
| [`docs/modules/web/smart-diff-ui-architecture.md`](../modules/web/smart-diff-ui-architecture.md) | UI component specifications |
|
||||
| [`SPRINT_20251226_007_BE_determinism_gaps.md`](../implplan/SPRINT_20251226_007_BE_determinism_gaps.md) | Determinism implementation sprint |
|
||||
|
||||
---
|
||||
|
||||
## Appendix C: Archive References
|
||||
|
||||
The following advisories were consolidated into this document:
|
||||
|
||||
| Original File | Archive Location |
|
||||
|--------------|------------------|
|
||||
| `25-Dec-2025 - Building a Deterministic Verdict Engine.md` | (kept in place - primary reference) |
|
||||
| `26-Dec-2026 - Diff‑Aware Releases and Auditable Exceptions.md` | `archived/2025-12-26-superseded/` |
|
||||
| `26-Dec-2026 - Smart‑Diff as a Core Evidence Primitive.md` | `archived/2025-12-26-superseded/` |
|
||||
| `25-Dec-2025 - Visual Diffs for Explainable Triage.md` | `archived/2025-12-26-triage-advisories/` |
|
||||
| `26-Dec-2026 - Visualizing the Risk Budget.md` | `archived/2025-12-26-triage-advisories/` |
|
||||
| `26-Dec-2026 - Weighted Confidence for VEX Sources.md` | `archived/2025-12-26-vex-scoring/` |
|
||||
|
||||
**Technical References (not moved):**
|
||||
- `archived/2025-12-21-moat-gap-closure/14-Dec-2025 - Smart-Diff Technical Reference.md`
|
||||
- `archived/2025-12-21-moat-phase2/20-Dec-2025 - Moat Explanation - Risk Budgets and Diff-Aware Release Gates.md`
|
||||
Reference in New Issue
Block a user