sprints completion. new product advisories prepared

This commit is contained in:
master
2026-01-16 16:30:03 +02:00
parent a927d924e3
commit 4ca3ce8fb4
255 changed files with 42434 additions and 1020 deletions

View File

@@ -945,19 +945,239 @@ Binary extraction and fingerprint generation MUST run with:
### 7.3 Ops Endpoints
> **Sprint:** SPRINT_20260112_007_BINIDX_binaryindex_user_config
BinaryIndex exposes read-only ops endpoints for health, bench, cache, and effective configuration:
- GET `/api/v1/ops/binaryindex/health` -> BinaryIndexOpsHealthResponse
- POST `/api/v1/ops/binaryindex/bench/run` -> BinaryIndexBenchResponse
- GET `/api/v1/ops/binaryindex/cache` -> BinaryIndexFunctionCacheStats
- GET `/api/v1/ops/binaryindex/config` -> BinaryIndexEffectiveConfig
| Endpoint | Method | Response Schema | Description |
|----------|--------|-----------------|-------------|
| `/api/v1/ops/binaryindex/health` | GET | `BinaryIndexOpsHealthResponse` | Health status, lifter warmness per ISA, cache availability |
| `/api/v1/ops/binaryindex/bench/run` | POST | `BinaryIndexBenchResponse` | Run latency benchmark, return min/max/mean/p50/p95/p99 stats |
| `/api/v1/ops/binaryindex/cache` | GET | `BinaryIndexFunctionCacheStats` | Function cache hit/miss/eviction statistics |
| `/api/v1/ops/binaryindex/config` | GET | `BinaryIndexEffectiveConfig` | Effective configuration with secrets redacted |
#### 7.3.1 Response Schemas
**BinaryIndexOpsHealthResponse:**
```json
{
"status": "healthy",
"timestamp": "2026-01-16T12:00:00Z",
"components": {
"lifterPool": { "status": "healthy", "message": null },
"functionCache": { "status": "healthy", "message": null },
"persistence": { "status": "healthy", "message": null }
},
"lifterWarmness": {
"intel-64": { "isa": "intel-64", "warm": true, "poolSize": 4, "acquireTimeMs": 12 },
"armv8-64": { "isa": "armv8-64", "warm": true, "poolSize": 2, "acquireTimeMs": 8 }
}
}
```
**BinaryIndexBenchResponse:**
```json
{
"timestamp": "2026-01-16T12:00:00Z",
"sampleSize": 100,
"latencySummary": {
"minMs": 5.2,
"maxMs": 142.8,
"meanMs": 28.4,
"p50Ms": 22.1,
"p95Ms": 78.3,
"p99Ms": 121.5
},
"operations": [
{ "operation": "lifterAcquire", "samples": 100, "meanMs": 12.4 },
{ "operation": "irNormalization", "samples": 100, "meanMs": 8.7 },
{ "operation": "cacheLookup", "samples": 100, "meanMs": 1.2 }
]
}
```
**BinaryIndexFunctionCacheStats:**
```json
{
"enabled": true,
"backend": "valkey",
"hits": 15234,
"misses": 892,
"evictions": 45,
"hitRate": 0.944,
"keyPrefix": "stellaops:binidx:funccache:",
"cacheTtlSeconds": 14400,
"estimatedEntries": 12500,
"estimatedMemoryBytes": 52428800
}
```
**BinaryIndexEffectiveConfig:**
```json
{
"b2r2Pool": {
"maxPoolSizePerIsa": 4,
"warmPreload": ["intel-64", "armv8-64"],
"acquireTimeoutMs": 5000,
"enableMetrics": true
},
"semanticLifting": {
"b2r2Version": "1.5.0",
"normalizationRecipeVersion": "2024.1",
"maxInstructionsPerFunction": 10000,
"maxFunctionsPerBinary": 5000,
"functionLiftTimeoutMs": 30000,
"enableDeduplication": true
},
"functionCache": {
"connectionString": "********",
"keyPrefix": "stellaops:binidx:funccache:",
"cacheTtlSeconds": 14400,
"maxTtlSeconds": 86400,
"earlyExpiryPercent": 0.1,
"maxEntrySizeBytes": 1048576
},
"persistence": {
"schema": "binaries",
"minPoolSize": 5,
"maxPoolSize": 20,
"commandTimeoutSeconds": 30,
"retryOnFailure": true,
"batchSize": 100
},
"backendVersions": {
"b2r2": "1.5.0",
"valkey": "7.2.0",
"postgres": "15.4"
}
}
```
#### 7.3.2 Rate Limiting
The `/bench/run` endpoint is rate-limited to prevent load spikes:
- Default: 5 requests per minute per tenant
- Configurable via `BinaryIndex:Ops:BenchRateLimitPerMinute`
#### 7.3.3 Secret Redaction
The config endpoint automatically redacts sensitive keys:
| Redacted Keys | Pattern |
|---------------|---------|
| `connectionString` | Replaced with `********` |
| `password` | Replaced with `********` |
| `secret*` | Any key starting with "secret" |
| `apiKey` | Replaced with `********` |
| `token` | Replaced with `********` |
Redaction is applied recursively to nested objects.
---
## 8. Configuration
> **Sprint:** SPRINT_20260112_007_BINIDX_binaryindex_user_config
### 8.1 Configuration Sections
All configuration is under the `BinaryIndex` section in `appsettings.yaml` or environment variables with `BINARYINDEX__` prefix.
#### 8.1.1 B2R2 Lifter Pool (`BinaryIndex:B2R2Pool`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `MaxPoolSizePerIsa` | int | 4 | Maximum lifter instances per ISA |
| `WarmPreload` | string[] | ["intel-64", "armv8-64"] | ISAs to warm on startup |
| `AcquireTimeoutMs` | int | 5000 | Timeout for lifter acquisition |
| `EnableMetrics` | bool | true | Emit Prometheus metrics for pool |
```yaml
# binaryindex.yaml
BinaryIndex:
B2R2Pool:
MaxPoolSizePerIsa: 4
WarmPreload:
- intel-64
- armv8-64
AcquireTimeoutMs: 5000
EnableMetrics: true
```
#### 8.1.2 Semantic Lifting (`BinaryIndex:SemanticLifting`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `B2R2Version` | string | "1.5.0" | B2R2 disassembler version |
| `NormalizationRecipeVersion` | string | "2024.1" | IR normalization recipe version |
| `MaxInstructionsPerFunction` | int | 10000 | Max instructions to lift per function |
| `MaxFunctionsPerBinary` | int | 5000 | Max functions to process per binary |
| `FunctionLiftTimeoutMs` | int | 30000 | Timeout for lifting single function |
| `EnableDeduplication` | bool | true | Deduplicate IR before fingerprinting |
```yaml
BinaryIndex:
SemanticLifting:
MaxInstructionsPerFunction: 10000
MaxFunctionsPerBinary: 5000
FunctionLiftTimeoutMs: 30000
EnableDeduplication: true
```
#### 8.1.3 Function Cache (`BinaryIndex:FunctionCache`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `ConnectionString` | string | | Valkey connection string (secret) |
| `KeyPrefix` | string | "stellaops:binidx:funccache:" | Cache key prefix |
| `CacheTtlSeconds` | int | 14400 | Default cache TTL (4 hours) |
| `MaxTtlSeconds` | int | 86400 | Maximum TTL (24 hours) |
| `EarlyExpiryPercent` | decimal | 0.1 | Early expiry jitter (10%) |
| `MaxEntrySizeBytes` | int | 1048576 | Max entry size (1 MB) |
```yaml
BinaryIndex:
FunctionCache:
ConnectionString: ${VALKEY_CONNECTION} # from env
KeyPrefix: "stellaops:binidx:funccache:"
CacheTtlSeconds: 14400
MaxEntrySizeBytes: 1048576
```
#### 8.1.4 Persistence (`Postgres:BinaryIndex`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `Schema` | string | "binaries" | PostgreSQL schema name |
| `MinPoolSize` | int | 5 | Minimum connection pool size |
| `MaxPoolSize` | int | 20 | Maximum connection pool size |
| `CommandTimeoutSeconds` | int | 30 | Command execution timeout |
| `RetryOnFailure` | bool | true | Retry transient failures |
| `BatchSize` | int | 100 | Batch insert size |
```yaml
Postgres:
BinaryIndex:
Schema: binaries
MinPoolSize: 5
MaxPoolSize: 20
CommandTimeoutSeconds: 30
RetryOnFailure: true
BatchSize: 100
```
#### 8.1.5 Ops Configuration (`BinaryIndex:Ops`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `EnableHealthEndpoint` | bool | true | Enable /health endpoint |
| `EnableBenchEndpoint` | bool | true | Enable /bench/run endpoint |
| `BenchRateLimitPerMinute` | int | 5 | Rate limit for bench endpoint |
| `RedactedKeys` | string[] | See 7.3.3 | Keys to redact in config output |
### 8.2 Legacy Configuration
```yaml
# binaryindex.yaml (corpus configuration)
binaryindex:
enabled: true
@@ -995,12 +1215,6 @@ binaryindex:
rustfs_bucket: stellaops/binaryindex
```
Additional appsettings sections (case-insensitive):
- `BinaryIndex:B2R2Pool` - lifter pool sizing and warm ISA list.
- `BinaryIndex:SemanticLifting` - LowUIR enablement and deterministic controls.
- `BinaryIndex:FunctionCache` - Valkey function cache configuration.
- `Postgres:BinaryIndex` - persistence for canonical IR fingerprints.
---
## 9. Testing Strategy

View File

@@ -19,6 +19,131 @@ stella attest list --tenant default --issuer dev-kms --format table
stella attest show --id a1b2c3 --output json
```
---
## Verify Offline (Air-Gapped Environments)
Verify attestation bundles completely offline without network access.
### Synopsis
```bash
stella attest verify-offline --bundle <path.tar.gz> [options]
```
### Options
| Option | Alias | Description |
|--------|-------|-------------|
| `--bundle <path>` | `-b` | **Required.** Path to attestation bundle (tar.gz). |
| `--checkpoint <path>` | `-c` | Path to Rekor checkpoint signature file. |
| `--trust-root <dir>` | `-r` | Path to trust root directory containing CA certificates. |
| `--artifact <digest>` | `-a` | Expected artifact digest (sha256:...) to verify against. |
| `--predicate-type <type>` | `-p` | Expected predicate type (e.g., https://slsa.dev/provenance/v1). |
| `--output <file>` | `-o` | Write verification report to file instead of stdout. |
| `--format <fmt>` | `-f` | Output format: `json`, `summary` (default), or `html`. |
| `--strict` | | Fail if any optional verification step fails. |
| `--verbose` | | Show detailed verification progress. |
### Verification Checks
The command performs the following verification checks:
1. **DSSE Envelope Signature**: Validates the DSSE envelope structure and signatures.
2. **Merkle Inclusion Proof**: Verifies Rekor transparency log inclusion proof.
3. **Checkpoint Signature**: Validates checkpoint signature against trusted keys.
4. **Content Hash**: Ensures all file hashes match the manifest.
### Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Verification passed |
| 1 | Verification failed (one or more checks failed) |
| 2 | Error (file not found, parse error, etc.) |
### Examples
```bash
# Basic offline verification
stella attest verify-offline --bundle evidence.tar.gz
# Full verification with all options
stella attest verify-offline \
--bundle evidence.tar.gz \
--checkpoint checkpoint.sig \
--trust-root /path/to/roots/ \
--artifact sha256:abc123def456 \
--predicate-type https://slsa.dev/provenance/v1
# Generate JSON verification report
stella attest verify-offline \
--bundle evidence.tar.gz \
--format json \
--output report.json
# Strict mode (fail on optional check failures)
stella attest verify-offline --bundle evidence.tar.gz --strict
```
### Sample Output
```
Attestation Verification Report
================================
Bundle: evidence.tar.gz
Status: VERIFIED
Checks:
[PASS] DSSE envelope signature valid
[PASS] Merkle inclusion proof verified (log index: 12345)
[PASS] Checkpoint signature valid (origin: rekor.sigstore.dev)
[PASS] Content hash matches manifest
Artifact: sha256:abc123...
Signed by: identity@example.com
Timestamp: 2026-01-14T10:30:00Z
```
### Bundle Format
The attestation bundle should be a tar.gz archive containing:
```
evidence.tar.gz
├── attestation.dsse.json # DSSE envelope with signature
├── manifest.json # File inventory with SHA-256 hashes
├── metadata.json # Generation timestamp, tool versions
├── certs/
│ ├── signing-cert.pem # Signing certificate
│ └── fulcio-root.pem # Fulcio root CA (optional)
└── rekor-proof/ # Transparency log proof (optional)
├── inclusion-proof.json
└── checkpoint.sig
```
### Air-Gap Workflow
1. **Export bundle** on connected system:
```bash
stella evidence export --scan-id <id> --output bundle.tar.gz
```
2. **Transfer bundle** to air-gapped system via secure media.
3. **Verify offline** on air-gapped system:
```bash
stella attest verify-offline --bundle bundle.tar.gz --trust-root /roots/
```
### Cross-Platform Determinism
The verification output is deterministic across platforms:
- Line endings normalized to LF
- Hex digests always lowercase
- Timestamps in ISO 8601 UTC format
- Paths use forward slashes
## CI/CD Integration
### GitHub Actions

View File

@@ -4,6 +4,7 @@
- `stella sbom generate --image <ref> [--output sbom.spdx.json] [--offline]`
- `stella sbom compose --fragment <path> --output composition.json --offline`
- `stella sbom verify --file <sbom> --signature <sig> --key <keyfile>`
- `stella sbom verify --archive <path.tar.gz> [--offline] [--trust-root <dir>]` — Verify signed SBOM archive
## Flags (common)
- `--offline`: no network pulls; use local cache/OCI archive.
@@ -23,3 +24,114 @@
## Offline/air-gap notes
- With `--offline`, image sources must already be cached (tar/OCI archive); command fails with exit code 5 if it would fetch remotely.
- Verification uses local trust roots; no remote key fetch.
---
## stella sbom verify — Signed Archive Verification
### Synopsis
```bash
stella sbom verify --archive <path.tar.gz> [options]
```
Verify a signed SBOM archive (tar.gz) containing SBOM, DSSE envelope, manifest, and verification materials.
### Options
| Option | Alias | Description |
|--------|-------|-------------|
| `--archive <path>` | `-a` | **Required.** Path to signed SBOM archive (tar.gz). |
| `--offline` | | Perform offline verification using bundled certificates. |
| `--trust-root <dir>` | `-r` | Path to trust root directory containing CA certificates. |
| `--output <file>` | `-o` | Write verification report to file instead of stdout. |
| `--format <fmt>` | `-f` | Output format: `json`, `summary` (default), or `html`. |
| `--strict` | | Fail if any optional verification step fails. |
| `--verbose` | | Show detailed verification progress. |
### Verification Checks
The command performs the following verification checks:
1. **Archive Integrity**: Validates all file hashes against `manifest.json`.
2. **DSSE Envelope Signature**: Verifies the DSSE envelope structure and signatures.
3. **SBOM Schema**: Validates SBOM content against SPDX or CycloneDX schemas.
4. **Tool Version**: Verifies tool version metadata is present and valid.
5. **Timestamp Validity**: Checks generation timestamp is within acceptable window.
### Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Verification passed |
| 1 | Verification failed (one or more checks failed) |
| 2 | Error (file not found, parse error, etc.) |
### Examples
```bash
# Verify a signed SBOM archive with summary output
stella sbom verify --archive signed-sbom-sha256-abc123.tar.gz
# Verify offline with custom trust root
stella sbom verify --archive signed-sbom.tar.gz --offline --trust-root /path/to/roots/
# Generate JSON verification report
stella sbom verify --archive signed-sbom.tar.gz --format json --output report.json
# Generate HTML report for sharing
stella sbom verify --archive signed-sbom.tar.gz --format html --output report.html
# Strict mode (fail on optional check failures)
stella sbom verify --archive signed-sbom.tar.gz --strict
```
### Sample Output
```
SBOM Verification Report
========================
Archive: signed-sbom-sha256-abc123.tar.gz
Status: VERIFIED
Checks:
[PASS] Archive integrity (All 4 file hashes verified)
[PASS] DSSE envelope signature (Valid, 1 signature(s))
[PASS] SBOM schema (Valid, SPDX 2.3)
[PASS] Tool version (Suite: 2027.Q1, Scanner: 1.2.3)
[PASS] Timestamp validity (Within validity window, 2026-01-15)
SBOM Details:
Format: SPDX 2.3
Components: 142
Artifact: sha256:abc123def456
Generated: 2026-01-15T10:30:00Z
Tool: StellaOps Scanner v2027.Q1
```
### Archive Format
The signed SBOM archive follows the format defined in `SPRINT_20260112_016_SCANNER_signed_sbom_archive_spec`:
```
signed-sbom-{digest}-{timestamp}.tar.gz
├── sbom.spdx.json (or sbom.cdx.json)
├── sbom.dsse.json
├── manifest.json
├── metadata.json
├── certs/
│ ├── signing-cert.pem
│ └── fulcio-root.pem
├── rekor-proof/
│ ├── inclusion-proof.json
│ └── checkpoint.sig
├── schemas/
│ └── ...
└── VERIFY.md
```
### Related Commands
- `stella sbom generate` — Generate SBOM from container image
- `stella attest verify --offline` — Verify attestation bundles offline
- `stella evidence export` — Export evidence bundle with signed SBOM

View File

@@ -38,3 +38,113 @@ observability:
## Profiles (planned)
- Profiles will live under `profiles/<name>.yaml` and can be selected with `--profile <name>`; until shipped, stick to the single default config file.
---
## Config Inspection Commands
> **Sprint:** SPRINT_20260112_014_CLI_config_viewer
The CLI provides unified config inspection across all StellaOps modules.
### List All Config Paths
```bash
# List all supported config paths
stella config list
# Output:
# Path Alias Module
# ────────────────────────────────────────────────────────────────────────
# policy.determinization policy:determinization Policy
# policy.confidenceweights policy:weights Policy
# scanner scanner Scanner
# scanner.reachability.prgate scanner:prgate Scanner
# attestor.rekor attestor:rekor Attestor
# signals.evidenceweightedscore signals:ews Signals
# ...
# Filter by module
stella config list --module policy
# Output as JSON
stella config list --output json
```
### Show Effective Config
```bash
# Show effective config for a path
stella config policy.determinization show
# Output:
# Effective Determinization Config
# ─────────────────────────────────
# Source: Service (api/v1/policy/config/determinization)
#
# Reanalysis Triggers:
# epssDeltaThreshold: 0.2
# triggerOnThresholdCrossing: true
# triggerOnRekorEntry: true
# triggerOnVexStatusChange: true
# triggerOnRuntimeTelemetryChange: true
# triggerOnPatchProofAdded: true
# triggerOnDsseValidationChange: true
# triggerOnToolVersionChange: false
#
# Conflict Handling:
# vexReachabilityContradiction: RequireManualReview
# ...
# Use path alias
stella config policy:determinization show
# Output as JSON
stella config policy.determinization show --output json
# Show from config file (bypass service)
stella config policy.determinization show --config /etc/stella/config.yaml
```
### Config Path Normalization
Path matching is case-insensitive with flexible separators:
| Input | Normalized | Valid |
|-------|------------|-------|
| `policy.determinization` | `policy.determinization` | ✓ |
| `Policy:Determinization` | `policy.determinization` | ✓ |
| `POLICY.DETERMINIZATION` | `policy.determinization` | ✓ |
| `policy:determinization` | `policy.determinization` | ✓ |
### Secret Redaction
Secrets are automatically redacted in config output:
```bash
stella config database show
# Output:
# database:
# host: pg.stella.local
# port: 5432
# database: stella
# username: stella_app
# password: ******** # Redacted
# connectionString: ******** # Redacted
```
### Popular Config Paths
| Path | Description |
|------|-------------|
| `policy.determinization` | Determinization triggers and thresholds |
| `policy.confidenceweights` | Evidence confidence weight values |
| `scanner` | Core scanner settings |
| `attestor.rekor` | Rekor transparency log settings |
| `signals.evidenceweightedscore` | EWS calculation settings |
| `excititor.mirror` | VEX mirror configuration |
| `airgap.bundlesigning` | Offline kit bundle signing |
| `signer.keyless` | Sigstore keyless signing |
See the full config inventory in `docs/implplan/SPRINT_20260112_014_CLI_config_viewer.md`.

View File

@@ -394,6 +394,9 @@ public sealed record GateResult
| **SourceQuotaGate** | Prevent single-source dominance without corroboration | `gates.sourceQuota` |
| **ReachabilityRequirementGate** | Require reachability proof for critical CVEs | `gates.reachabilityRequirement` |
| **EvidenceFreshnessGate** | Reject stale evidence below freshness threshold | `gates.evidenceFreshness` |
| **CvssThresholdGate** | Block findings above CVSS score threshold | `gates.cvssThreshold` |
| **SbomPresenceGate** | Require valid SBOM for release artifacts | `gates.sbomPresence` |
| **SignatureRequiredGate** | Require signatures on specified evidence types | `gates.signatureRequired` |
#### MinimumConfidenceGate
@@ -466,6 +469,112 @@ gates:
- **Behavior**: Fails when CRITICAL/HIGH CVE marked `not_affected` lacks reachability proof (unless bypass reason applies).
#### CvssThresholdGate
> **Sprint:** SPRINT_20260112_017_POLICY_cvss_threshold_gate
Blocks findings above a configurable CVSS score threshold per environment:
```yaml
gates:
cvssThreshold:
enabled: true
priority: 15
defaultThreshold: 7.0
thresholds:
production: 7.0
staging: 8.0
development: 9.0
cvssVersionPreference: highest # v3.1, v4.0, or highest
failOnMissingCvss: false
requireAllVersionsPass: false
allowlist:
- CVE-2024-XXXXX # False positive
denylist:
- CVE-2024-YYYYY # Always block
```
- **Behavior**: Fails when CVSS base score exceeds environment threshold.
- **CVSS Versions**: Supports both CVSS v3.1 and v4.0; preference configurable.
- **Allowlist**: CVEs that bypass threshold enforcement.
- **Denylist**: CVEs that always fail regardless of score.
- **Offline**: Operates without external lookups; uses injected or metadata scores.
#### SbomPresenceGate
> **Sprint:** SPRINT_20260112_017_POLICY_sbom_presence_gate
Requires valid SBOM presence for release artifacts:
```yaml
gates:
sbomPresence:
enabled: true
priority: 5
enforcement:
production: required
staging: required
development: optional
acceptedFormats:
- spdx-2.3
- spdx-3.0.1
- cyclonedx-1.5
- cyclonedx-1.6
minimumComponents: 1
requireSignature: true
schemaValidation: true
requirePrimaryComponent: true
```
- **Enforcement Levels**: `required` (fail), `recommended` (warn), `optional` (pass).
- **Format Validation**: Validates SBOM format against accepted list; normalizes format names.
- **Schema Validation**: Validates SBOM against bundled JSON schemas.
- **Signature Requirement**: Optionally requires signed SBOM.
- **Minimum Components**: Ensures SBOM has meaningful inventory.
#### SignatureRequiredGate
> **Sprint:** SPRINT_20260112_017_POLICY_signature_required_gate
Requires cryptographic signatures on specified evidence types:
```yaml
gates:
signatureRequired:
enabled: true
priority: 3
evidenceTypes:
sbom:
required: true
trustedIssuers:
- "*@company.com"
- "build-service@ci.example.com"
acceptedAlgorithms:
- ES256
- RS256
vex:
required: true
trustedIssuers:
- "*@vendor.com"
attestation:
required: true
enableKeylessVerification: true
fulcioRoots: /etc/stella/trust/fulcio-roots.pem
requireTransparencyLogInclusion: true
environments:
development:
requiredOverride: false
skipEvidenceTypes:
- sbom
```
- **Per-Evidence-Type**: Configure requirements per evidence type (SBOM, VEX, attestation).
- **Issuer Constraints**: Wildcard support (`*@domain.com`) for email patterns.
- **Algorithm Enforcement**: Limit accepted signature algorithms.
- **Keyless (Fulcio)**: Support Sigstore keyless signatures with Fulcio certificate verification.
- **Transparency Log**: Optionally require Rekor inclusion proof.
- **Environment Overrides**: Relax requirements for non-production environments.
#### Gate Registry
Gates are registered via DI and evaluated in sequence:
@@ -496,6 +605,9 @@ public interface IPolicyGateRegistry
| SourceQuotaGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/SourceQuotaGate.cs` |
| ReachabilityRequirementGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/ReachabilityRequirementGate.cs` |
| EvidenceFreshnessGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/EvidenceFreshnessGate.cs` |
| CvssThresholdGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/CvssThresholdGate.cs` |
| SbomPresenceGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/SbomPresenceGate.cs` |
| SignatureRequiredGate | `src/Policy/__Libraries/StellaOps.Policy/Gates/SignatureRequiredGate.cs` |
See `etc/policy-gates.yaml.sample` for complete gate configuration options.

View File

@@ -216,3 +216,216 @@ services.AddPolicyEngine(); // Includes determinization
---
*Last updated: 2026-01-07 (Sprint 20260106_001_003)*
---
## 10. Unknown Mapping and Grey Queue Semantics
> **Sprint:** SPRINT_20260112_004_POLICY_unknowns_determinization_greyqueue
When evidence is incomplete or conflicting, the Determinization Gate produces outcomes that map to the "Grey Queue" for operator review.
### 10.1 Unknown State Mapping
The Grey Queue captures observations with uncertain status:
| Policy Verdict | Observation State | OpenVEX Mapping | Description |
|----------------|------------------|-----------------|-------------|
| `GuardedPass` | `PendingDeterminization` | `under_investigation` | Allowed with guardrails; monitoring required |
| `Deferred` | `PendingDeterminization` | `under_investigation` | Decision deferred; needs additional evidence |
| `Escalated` (conflict) | `Disputed` | `under_investigation` | Conflicting evidence; manual adjudication required |
### 10.2 Reanalysis Fingerprint
Each unknown is assigned a deterministic fingerprint enabling reproducible replays:
```json
{
"fingerprintId": "sha256:abc123...",
"dsseBundleDigest": "sha256:def456...",
"evidenceDigests": [
"sha256:111...",
"sha256:222..."
],
"toolVersions": {
"scanner": "2.1.0",
"reachability": "1.5.2"
},
"productVersion": "1.0.0",
"policyConfigHash": "sha256:789...",
"signalWeightsHash": "sha256:aaa...",
"computedAt": "2026-01-15T10:00:00Z",
"triggers": [
{
"type": "epss.updated@1",
"receivedAt": "2026-01-15T09:55:00Z",
"delta": 0.15
}
],
"nextActions": ["await_vex", "run_reachability"]
}
```
### 10.3 Conflict Detection and Routing
Conflicting evidence automatically routes to `Disputed` state:
| Conflict Type | Detection | Adjudication Path |
|---------------|-----------|-------------------|
| `VexReachabilityContradiction` | VEX not_affected + confirmed reachable | Manual review |
| `StaticRuntimeContradiction` | Static unreachable + runtime execution | Auto-escalate |
| `VexStatusConflict` | Multiple providers with conflicting status | Trust-weighted resolution or manual |
| `BackportStatusConflict` | Backport claimed + affected status | Manual review |
| `EpssRiskContradiction` | Low EPSS + KEV or high exploitation | Auto-escalate |
### 10.4 Trigger Events for Reanalysis
The Grey Queue tracks triggers that caused reanalysis:
| Event Type | Version | Delta Threshold | Description |
|------------|---------|-----------------|-------------|
| `epss.updated` | 1 | 0.1 | EPSS score changed significantly |
| `vex.updated` | 1 | N/A | VEX statement added/modified |
| `reachability.updated` | 1 | N/A | Reachability analysis completed |
| `runtime.updated` | 1 | N/A | Runtime observation recorded |
| `sbom.updated` | 1 | N/A | SBOM content changed |
| `dsse_validation.changed` | 1 | N/A | DSSE validation status changed |
| `rekor_entry.added` | 1 | N/A | New Rekor transparency entry |
### 10.5 Next Actions
Each unknown suggests next actions for resolution:
| Action | Description |
|--------|-------------|
| `await_vex` | Wait for vendor VEX statement |
| `run_reachability` | Execute reachability analysis |
| `enable_runtime` | Deploy runtime telemetry |
| `verify_backport` | Confirm backport availability |
| `manual_review` | Escalate to security team |
| `trust_resolution` | Resolve issuer trust conflict |
---
## 11. Related Documentation
- [Determinization Library](./determinization-architecture.md) - Core determinization models
- [Policy Engine Architecture](./architecture.md) - Overall policy engine design
- [Signal Snapshot Models](../../api/signals/reachability-contract.md) - Signal data structures
- [VEX Consensus Guide](../../VEX_CONSENSUS_GUIDE.md) - VEX correlation and consensus
---
## 12. Determinization Configuration
> **Sprint:** SPRINT_20260112_012_POLICY_determinization_reanalysis_config
The Determinization Gate uses persisted configuration for reanalysis triggers, conflict handling, and per-environment thresholds.
### 12.1 Configuration Schema
```json
{
"reanalysisTriggers": {
"epssDeltaThreshold": 0.2,
"triggerOnThresholdCrossing": true,
"triggerOnRekorEntry": true,
"triggerOnVexStatusChange": true,
"triggerOnRuntimeTelemetryChange": true,
"triggerOnPatchProofAdded": true,
"triggerOnDsseValidationChange": true,
"triggerOnToolVersionChange": false
},
"conflictHandling": {
"vexReachabilityContradiction": "RequireManualReview",
"staticRuntimeContradiction": "RequireManualReview",
"vexStatusConflict": "RequestVendorClarification",
"backportStatusConflict": "RequireManualReview",
"escalationSeverityThreshold": 0.85,
"conflictTtlHours": 48
},
"environmentThresholds": {
"production": {
"minConfidence": 0.75,
"maxEntropy": 0.3,
"epssThreshold": 0.3,
"requireReachability": true
},
"staging": {
"minConfidence": 0.60,
"maxEntropy": 0.5,
"epssThreshold": 0.4,
"requireReachability": true
},
"development": {
"minConfidence": 0.40,
"maxEntropy": 0.7,
"epssThreshold": 0.6,
"requireReachability": false
}
}
}
```
### 12.2 Reanalysis Trigger Defaults
| Trigger | Default | Description |
|---------|---------|-------------|
| `epssDeltaThreshold` | 0.2 | Minimum EPSS delta to trigger reanalysis |
| `triggerOnThresholdCrossing` | true | Trigger when EPSS crosses a bucket threshold |
| `triggerOnRekorEntry` | true | Trigger on new Rekor transparency entry |
| `triggerOnVexStatusChange` | true | Trigger when VEX status changes |
| `triggerOnRuntimeTelemetryChange` | true | Trigger on runtime exploit/reachability signals |
| `triggerOnPatchProofAdded` | true | Trigger when binary patch proof is added |
| `triggerOnDsseValidationChange` | true | Trigger when DSSE validation state changes |
| `triggerOnToolVersionChange` | false | Trigger on tool version updates (disabled by default) |
### 12.3 Conflict Handling Actions
| Action | Description |
|--------|-------------|
| `AutoResolve` | System resolves using trust scores |
| `RequireManualReview` | Route to Grey Queue for operator review |
| `RequestVendorClarification` | Queue for vendor outreach |
| `Escalate` | Escalate to security team |
| `Block` | Block until conflict is resolved |
### 12.4 Environment Threshold Presets
| Preset | MinConfidence | MaxEntropy | EPSS Threshold |
|--------|---------------|------------|----------------|
| Relaxed (dev) | 0.40 | 0.7 | 0.6 |
| Standard (staging) | 0.60 | 0.5 | 0.4 |
| Strict (production) | 0.75 | 0.3 | 0.3 |
### 12.5 Configuration API
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/policy/config/determinization` | GET | Get effective config for tenant |
| `/api/v1/policy/config/determinization/defaults` | GET | Get system defaults |
| `/api/v1/policy/config/determinization/audit` | GET | Get configuration change history |
| `/api/v1/policy/config/determinization` | PUT | Update config (policy-admin required) |
| `/api/v1/policy/config/determinization/validate` | POST | Validate config without saving |
### 12.6 Configuration Binding
In `appsettings.yaml`:
```yaml
Policy:
Determinization:
ReanalysisTriggers:
EpssDeltaThreshold: 0.2
TriggerOnThresholdCrossing: true
TriggerOnRekorEntry: true
TriggerOnVexStatusChange: true
TriggerOnToolVersionChange: false
ConflictHandling:
VexReachabilityContradiction: RequireManualReview
EscalationSeverityThreshold: 0.85
EnvironmentThresholds:
Production:
MinConfidence: 0.75
MaxEntropy: 0.3
```

View File

@@ -43,6 +43,58 @@ Findings can have special flags indicating evidence quality:
| `proven-path` | Checkmark | Blue | Verified reachability path confirmed |
| `vendor-na` | Strikethrough | Gray | Vendor marked as not affected |
| `speculative` | Question mark | Orange | Evidence is speculative/unconfirmed |
| `anchored` | [A] | Violet | Score anchored with DSSE/Rekor attestation |
| `hard-fail` | [!] | Red | Policy hard-fail triggered |
## Grey Queue Components
> **Sprint:** SPRINT_20260112_011_FE_policy_unknowns_queue_integration
The Grey Queue component suite handles observations with uncertain status requiring operator attention.
### Components
| Component | Purpose | Location |
|-----------|---------|----------|
| GreyQueuePanel | Display grey queue item with fingerprint, triggers, conflicts, and actions | `features/unknowns/` |
| GreyQueueDashboard | Dashboard view with filtering and deterministic ordering | `features/unknowns/` |
| DeterminizationReview | Detailed review context for grey queue items | `features/unknowns/` |
### Observation States
| State | Badge Color | Description |
|-------|-------------|-------------|
| `PendingDeterminization` | Yellow | Evidence incomplete; monitoring active |
| `Disputed` | Orange | Conflicting evidence; manual adjudication required |
| `GuardedPass` | Blue | Allowed with runtime guardrails |
| `Resolved` | Green | Operator has made a determination |
### Usage
```typescript
// Grey queue components
import {
GreyQueuePanelComponent,
GreyQueueDashboardComponent,
DeterminizationReviewComponent,
} from '@app/features/unknowns';
```
```html
<!-- Grey Queue Panel -->
<app-grey-queue-panel
[unknown]="policyUnknown"
(triageAction)="onTriageAction($event)"
/>
<!-- Grey Queue Dashboard -->
<app-grey-queue-dashboard
[unknowns]="unknownsList"
(selectUnknown)="onSelectUnknown($event)"
/>
```
See `docs/UI_GUIDE.md#grey-queue-and-unknowns-triage` for operator workflow documentation.
## Quick Start

View File

@@ -81,6 +81,23 @@ Filter by active score flags:
- Proven Path
- Vendor N/A
- Speculative
- Anchored (DSSE/Rekor attested)
- Hard Fail (policy triggered)
### Row Visual Indicators
#### Hard Fail Rows
Findings with `hard-fail` flag are highlighted with:
- Red left border (`3px solid #dc2626`)
- Subtle red background tint
- CSS class: `hard-fail-row`
#### Anchored Rows
Findings with `anchored` flag display:
- Violet left border (`3px solid #7c3aed`)
- CSS class: `anchored-row`
Note: If a finding is both anchored and hard-fail, hard-fail styling takes visual precedence.
### Search
Text search across advisory ID and package name.

View File

@@ -25,10 +25,12 @@ The `ScoreBadgeComponent` displays evidence quality flags that provide context a
| Type | Icon | Color | Description |
|------|------|-------|-------------|
| `live-signal` | Signal wave | Green (`#16A34A`) | Active runtime signals detected from deployed environments |
| `live-signal` | Signal wave | Green (`#059669`) | Active runtime signals detected from deployed environments |
| `proven-path` | Checkmark | Blue (`#2563EB`) | Verified reachability path to vulnerable code |
| `vendor-na` | Strikethrough | Gray (`#6B7280`) | Vendor has marked as not affected |
| `speculative` | Question mark | Orange (`#D97706`) | Evidence is speculative or unconfirmed |
| `speculative` | Question mark | Orange (`#F97316`) | Evidence is speculative or unconfirmed |
| `anchored` | [A] | Violet (`#7C3AED`) | Score is anchored with DSSE attestation and/or Rekor transparency log |
| `hard-fail` | [!] | Red (`#DC2626`) | Policy hard-fail triggered - requires immediate remediation |
## Usage Examples
@@ -45,6 +47,8 @@ The `ScoreBadgeComponent` displays evidence quality flags that provide context a
<stella-score-badge type="proven-path" />
<stella-score-badge type="vendor-na" />
<stella-score-badge type="speculative" />
<stella-score-badge type="anchored" />
<stella-score-badge type="hard-fail" />
```
### Size Variants
@@ -128,6 +132,30 @@ The evidence for this vulnerability is speculative or based on incomplete analys
- Heuristic-based detection
- Unverified reports
### anchored (Violet - Attested)
The score calculation has been cryptographically anchored via DSSE attestation and/or inclusion in a Rekor transparency log. This provides verifiable proof of the score at a specific point in time.
**Attestation Types:**
- DSSE envelope with signed payload
- Rekor log index and entry ID
- Offline ledger verification
**Visual Behavior:**
- Subtle violet glow effect via `anchored-glow` CSS class
### hard-fail (Red - Immediate Action)
A policy hard-fail condition has been triggered. This indicates the vulnerability meets criteria for mandatory immediate remediation, bypassing normal triage workflow.
**Triggers:**
- Known Exploited Vulnerability (KEV) list inclusion
- Active exploitation confirmed
- Critical severity with confirmed reachability
- Policy override by security team
**Visual Behavior:**
- Red alert pulse animation via `alert` CSS class
- Row highlighting in findings lists
## Accessibility
- Uses `role="img"` with descriptive `aria-label`

View File

@@ -57,6 +57,35 @@ interface EvidenceWeightedScoreResult {
};
policyDigest: string;
calculatedAt: string; // ISO 8601
// Sprint: SPRINT_20260112_004_FE_attested_score_ui
// Reduction profile, hard-fail, and anchor fields
reductionProfile?: ReductionProfile;
shortCircuitReason?: ShortCircuitReason;
hardFailStatus?: HardFailStatus;
isHardFail?: boolean;
proofAnchor?: ScoreProofAnchor;
}
interface ReductionProfile {
mode: 'none' | 'light' | 'standard' | 'aggressive' | 'custom';
originalScore: number;
reductionAmount: number;
reductionFactor: number;
contributingEvidence: string[];
cappedByPolicy: boolean;
}
interface ScoreProofAnchor {
anchored: boolean;
dsseDigest?: string;
rekorLogIndex?: number;
rekorEntryId?: string;
rekorLogId?: string;
attestationUri?: string;
verifiedAt?: string;
verificationStatus?: 'verified' | 'pending' | 'failed' | 'offline';
verificationError?: string;
}
```
@@ -129,22 +158,44 @@ export class ScoreDialogComponent {
### 1. Header
Displays the overall score with bucket label and color.
### 2. Dimensions Chart
### 2. Hard Fail Alert (Conditional)
If `isHardFail` is true, displays a prominent red warning section with the hard-fail reason (KEV, exploited, critical reachable, or policy override).
### 3. Dimensions Chart
Horizontal bar chart showing all six dimensions with their normalized values (0-100%).
### 3. Flags Section
Active flags displayed as badges. See [ScoreBadge](./score-badge.md) for flag types.
### 4. Reduction Profile (Conditional)
When a reduction profile is present, shows:
- Reduction mode (light, standard, aggressive, custom)
- Original vs reduced score
- Contributing evidence types
- Policy cap indicator
### 4. Guardrails Section
### 5. Short-Circuit Info (Conditional)
When the score was short-circuited, shows the reason (vendor not affected, VEX not affected, runtime confirmed, anchor verified).
### 6. Flags Section
Active flags displayed as badges. See [ScoreBadge](./score-badge.md) for flag types including:
- `anchored` - Cryptographic attestation present
- `hard-fail` - Policy hard-fail triggered
### 7. Guardrails Section
Applied caps and floors:
- **Speculative Cap**: Score limited due to unconfirmed evidence
- **Not Affected Cap**: Score reduced due to vendor VEX
- **Runtime Floor**: Score elevated due to active runtime signals
### 5. Explanations
### 8. Proof Anchor Details (Conditional)
When anchored, shows attestation details:
- DSSE envelope digest (truncated)
- Rekor log index and entry ID
- Verification status and timestamp
- Attestation URI link
### 9. Explanations
Human-readable explanations of factors affecting the score.
### 6. Footer
### 10. Footer
- Policy digest (truncated SHA-256)
- Calculation timestamp