feat: Add archived advisories and implement smart-diff as a core evidence primitive

- Introduced new advisory documents for archived superseded advisories, including detailed descriptions of features already implemented or covered by existing sprints.
- Added "Smart-Diff as a Core Evidence Primitive" advisory outlining the treatment of SBOM diffs as first-class evidence objects, enhancing vulnerability verdicts with deterministic replayability.
- Created "Visual Diffs for Explainable Triage" advisory to improve user experience in understanding policy decisions and reachability changes through visual diffs.
- Implemented "Weighted Confidence for VEX Sources" advisory to rank conflicting vulnerability evidence based on freshness and confidence, facilitating better decision-making.
- Established a signer module charter detailing the mission, expectations, key components, and signing modes for cryptographic signing services in StellaOps.
- Consolidated overlapping concepts from triage UI, visual diffs, and risk budget visualization advisories into a unified specification for better clarity and implementation tracking.
This commit is contained in:
StellaOps Bot
2025-12-26 13:01:43 +02:00
parent 22390057fc
commit 7792749bb4
50 changed files with 6844 additions and 130 deletions

View File

@@ -0,0 +1,48 @@
# Sprint 20251226 · CI/CD Release Gate Integration
## Topic & Scope
- Wire existing `DriftGateEvaluator` into CI/CD pipelines for automated release gating.
- Provide webhook endpoint for Zastava/registry triggers, scheduler job integration, and CI exit codes.
- Deliver example workflows for GitHub Actions and GitLab CI.
- **Working directory:** `src/Policy/StellaOps.Policy.Engine`, `src/Scheduler/StellaOps.Scheduler`
## Dependencies & Concurrency
- Depends on: `DriftGateEvaluator` (complete), `DeltaComputer` (complete), `DeltaVerdict` (complete).
- Can run in parallel with: SPRINT_20251226_005_SCANNER (reachability extractors).
- Blocks: SPRINT_20251226_004_FE (dashboard needs API endpoints from this sprint).
## Documentation Prerequisites
- `docs/modules/policy/architecture.md`
- `docs/modules/scheduler/architecture.md`
- `docs/modules/zastava/architecture.md`
- `CLAUDE.md` (project conventions)
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | CICD-GATE-01 | TODO | None | Policy Guild | Create `POST /api/v1/policy/gate/evaluate` endpoint accepting image digest + baseline ref; returns `DeltaVerdict` with Pass/Warn/Fail status |
| 2 | CICD-GATE-02 | TODO | CICD-GATE-01 | Policy Guild | Add webhook handler for Zastava image-push events; trigger async gate evaluation job |
| 3 | CICD-GATE-03 | TODO | CICD-GATE-01 | Scheduler Guild | Create `GateEvaluationJob` in Scheduler; wire to Policy Engine gate endpoint |
| 4 | CICD-GATE-04 | TODO | CICD-GATE-01 | Policy Guild | Define CI exit codes: 0=Pass, 1=Warn (configurable pass-through), 2=Fail/Block |
| 5 | CICD-GATE-05 | TODO | CICD-GATE-04 | Policy Guild | CLI command `stella gate evaluate --image <digest> --baseline <ref>` with exit code support |
| 6 | CICD-GATE-06 | TODO | CICD-GATE-02 | Policy Guild | Gate bypass audit logging: record who/when/why for any override; persist to audit table |
| 7 | CICD-GATE-07 | TODO | CICD-GATE-05 | DevOps Guild | GitHub Actions example workflow using `stella gate evaluate` |
| 8 | CICD-GATE-08 | TODO | CICD-GATE-05 | DevOps Guild | GitLab CI example workflow using `stella gate evaluate` |
| 9 | CICD-GATE-09 | TODO | CICD-GATE-03 | Policy Guild + Zastava Guild | Integration tests: Zastava webhook -> Scheduler -> Policy Engine -> verdict |
| 10 | CICD-GATE-10 | TODO | CICD-GATE-09 | Policy Guild | Documentation: update `docs/modules/policy/architecture.md` with gate API section |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from product advisory analysis; consolidates diff-aware release gate requirements. | Project Mgmt |
## Decisions & Risks
- Decision needed: Should Warn status block CI by default or pass-through? Recommend: configurable per-environment.
- Decision needed: Gate evaluation timeout for long-running reachability analysis. Recommend: 60s default, configurable.
- Risk: High evaluation latency may slow CI pipelines. Mitigation: async evaluation with cached baseline snapshots.
- Risk: Gate bypass abuse. Mitigation: audit logging + Authority scope enforcement for bypass permission.
## Next Checkpoints
- 2025-12-30 | CICD-GATE-01 complete | Gate endpoint accepting requests |
- 2026-01-03 | CICD-GATE-05 complete | CLI integration verified |
- 2026-01-06 | CICD-GATE-09 complete | End-to-end integration tested |

View File

@@ -0,0 +1,502 @@
# SPRINT_20251226_001_SIGNER_fulcio_keyless_client
**Sprint ID:** 20251226_001_SIGNER
**Topic:** Fulcio Keyless Signing Client Implementation
**Status:** TODO
**Priority:** P0 (Critical Path)
**Created:** 2025-12-26
**Working Directory:** `src/Signer/`
---
## Executive Summary
Implement Sigstore Fulcio integration for keyless signing in CI/CD pipelines. This enables ephemeral X.509 certificates (~10 min TTL) obtained via OIDC identity tokens, eliminating the need for persistent signing keys in CI environments while maintaining cryptographic non-repudiation through Rekor transparency logging.
**Business Value:**
- Zero key management overhead in CI pipelines
- Eliminates credential sprawl and secret rotation complexity
- Enables audit-grade non-repudiation via OIDC identity binding
- Aligns with Sigstore industry standard (adopted by Kubernetes, npm, PyPI)
**Dependencies:**
- Attestor module for Rekor submission (Sprint 20251226_002)
- Authority module for OIDC token minting (existing)
- RFC 8785 canonicalization (existing in `StellaOps.Canonicalization`)
---
## Prerequisites
**Required Reading (complete before DOING):**
- [ ] `docs/modules/signer/architecture.md` - Signer architecture dossier
- [ ] `docs/modules/attestor/architecture.md` - Attestor architecture (§2.1 for Rekor)
- [ ] `CLAUDE.md` - Project coding standards
- [ ] `src/Signer/AGENTS.md` - Module charter (if exists, create if not)
- [ ] Sigstore Fulcio documentation: https://docs.sigstore.dev/certificate_authority/overview/
**Technical Prerequisites:**
- [ ] Authority OIDC endpoint operational (`/oauth/token`)
- [ ] BouncyCastle crypto library available for ECDSA/Ed25519
- [ ] HTTP/2 client infrastructure for Fulcio API calls
---
## Scope & Boundaries
### In Scope
- Fulcio OIDC client implementation
- Ephemeral keypair generation (ECDSA P-256, Ed25519)
- Certificate chain handling and validation
- Integration with existing `IDsseSigner` interface
- Configuration schema for Fulcio endpoints
- Unit and integration tests
### Out of Scope
- Rekor submission (handled by Attestor - Sprint 002)
- Bundle rotation workflows (Sprint 002)
- CLI integration (Sprint 003)
- CI/CD templates (Sprint 004)
### Guardrails
- No hard-coded external URLs; all endpoints configurable
- Ephemeral keys MUST NOT persist to disk
- Certificate chains MUST validate to configured Fulcio roots
- All timestamps in UTC ISO-8601
---
## Architecture
### Component Diagram
```
┌─────────────────────────────────────────────────────────────────┐
│ Signer Service │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ SignerPipeline │───▶│ IDsseSigner │ │
│ └──────────────────┘ └────────┬─────────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ CryptoDsseSigner│ │ KeylessDsseSigner│ │ KmsDsseSigner │ │
│ │ (existing) │ │ (NEW) │ │ (existing) │ │
│ └────────────────┘ └────────┬─────────┘ └──────────────┘ │
│ │ │
│ ┌────────────┴────────────┐ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ IFulcioClient │ │ IEphemeralKeyGen │ │
│ │ (NEW) │ │ (NEW) │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ │
└────────────────────┼────────────────────────────────────────────┘
▼ HTTPS (mTLS optional)
┌──────────────────┐
│ Fulcio CA │
│ (external) │
└──────────────────┘
```
### New Interfaces
```csharp
// src/Signer/__Libraries/StellaOps.Signer.Keyless/IFulcioClient.cs
public interface IFulcioClient
{
Task<FulcioCertificateResult> GetCertificateAsync(
FulcioCertificateRequest request,
CancellationToken cancellationToken = default);
}
public record FulcioCertificateRequest(
byte[] PublicKey,
string Algorithm, // "ECDSA_P256" | "Ed25519"
string OidcIdentityToken,
string? ProofOfPossession); // Optional signed challenge
public record FulcioCertificateResult(
byte[] Certificate,
byte[][] CertificateChain,
string SignedCertificateTimestamp,
DateTimeOffset NotBefore,
DateTimeOffset NotAfter,
FulcioIdentity Identity);
public record FulcioIdentity(
string Issuer,
string Subject,
string? SubjectAlternativeName);
```
```csharp
// src/Signer/__Libraries/StellaOps.Signer.Keyless/IEphemeralKeyGenerator.cs
public interface IEphemeralKeyGenerator
{
EphemeralKeyPair Generate(string algorithm);
void Dispose(EphemeralKeyPair keyPair); // Secure erasure
}
public sealed class EphemeralKeyPair : IDisposable
{
public byte[] PublicKey { get; }
public byte[] PrivateKey { get; } // In-memory only, never persisted
public string Algorithm { get; }
public DateTimeOffset CreatedAt { get; }
public void Dispose(); // Zeros memory
}
```
---
## Delivery Tracker
| ID | Task | Owner | Status | Dependencies | Acceptance Criteria |
|----|------|-------|--------|--------------|---------------------|
| 0001 | Create `StellaOps.Signer.Keyless` library project | — | TODO | — | Project compiles, referenced by Signer.Infrastructure |
| 0002 | Implement `IEphemeralKeyGenerator` interface | — | TODO | 0001 | Generates ECDSA P-256 and Ed25519 keypairs |
| 0003 | Implement `EphemeralKeyPair` with secure disposal | — | TODO | 0002 | Memory zeroed on Dispose(), finalizer backup |
| 0004 | Implement `IFulcioClient` interface | — | TODO | 0001 | Contract defined, mockable |
| 0005 | Implement `HttpFulcioClient` | — | TODO | 0004 | HTTP/2 client, retries, circuit breaker |
| 0006 | Add Fulcio response parsing (X.509 chain) | — | TODO | 0005 | PEM/DER parsing, chain ordering |
| 0007 | Implement `KeylessDsseSigner` | — | TODO | 0003, 0006 | Signs DSSE with ephemeral key + Fulcio cert |
| 0008 | Add `verdict.stella/v1` predicate type | — | TODO | — | PredicateTypes.cs updated, schema defined |
| 0009 | Add configuration schema `SignerKeylessOptions` | — | TODO | 0005 | YAML/JSON config, validation |
| 0010 | Wire DI registration in `ServiceCollectionExtensions` | — | TODO | 0007, 0009 | `services.AddKeylessSigning()` |
| 0011 | Implement certificate chain validation | — | TODO | 0006 | Validates to configured Fulcio roots |
| 0012 | Add OIDC token acquisition from Authority | — | TODO | — | Client credentials flow, caching |
| 0013 | Unit tests: EphemeralKeyGenerator | — | TODO | 0003 | Key generation, disposal, algorithm coverage |
| 0014 | Unit tests: HttpFulcioClient (mocked) | — | TODO | 0005 | Happy path, error handling, retries |
| 0015 | Unit tests: KeylessDsseSigner | — | TODO | 0007 | Signing roundtrip, cert attachment |
| 0016 | Unit tests: Certificate chain validation | — | TODO | 0011 | Valid chain, expired cert, untrusted root |
| 0017 | Integration test: Full keyless signing flow | — | TODO | 0010 | End-to-end with mock Fulcio |
| 0018 | Integration test: Verify signed bundle | — | TODO | 0017 | Signature verification, cert chain |
| 0019 | Documentation: Keyless signing guide | — | TODO | 0017 | `docs/modules/signer/guides/keyless-signing.md` |
| 0020 | Update `src/Signer/AGENTS.md` | — | TODO | 0019 | Add keyless components to charter |
---
## Technical Specifications
### Configuration Schema
```yaml
# etc/signer.yaml
signer:
signing:
mode: "keyless" # "keyless" | "kms" | "hybrid"
keyless:
enabled: true
fulcio:
url: "https://fulcio.sigstore.dev"
# For private deployments:
# url: "https://fulcio.internal.example.com"
timeout: 30s
retries: 3
backoffBase: 1s
backoffMax: 30s
oidc:
# Use Authority as OIDC provider
issuer: "https://authority.internal"
clientId: "signer-keyless"
clientSecretRef: "env:SIGNER_OIDC_CLIENT_SECRET"
# Alternative: use ambient OIDC (CI runner tokens)
useAmbientToken: false
ambientTokenPath: "/var/run/secrets/tokens/oidc"
algorithms:
preferred: "ECDSA_P256"
allowed: ["ECDSA_P256", "Ed25519"]
certificate:
# Fulcio roots for validation
rootBundlePath: "/etc/stellaops/fulcio-roots.pem"
# Allow additional roots for private Fulcio instances
additionalRoots: []
validateChain: true
requireSCT: true # Require Signed Certificate Timestamp
identity:
# Expected OIDC issuer for verification
expectedIssuers:
- "https://authority.internal"
- "https://token.actions.githubusercontent.com"
- "https://gitlab.com"
# Expected SAN patterns (regex)
expectedSubjectPatterns:
- "^https://github\\.com/stella-ops/.*$"
- "^urn:stellaops:signer$"
```
### Error Handling
```csharp
public abstract class KeylessSigningException : SignerException
{
protected KeylessSigningException(string message, Exception? inner = null)
: base(message, inner) { }
}
public class FulcioUnavailableException : KeylessSigningException
{
public string FulcioUrl { get; }
public int HttpStatus { get; }
}
public class OidcTokenAcquisitionException : KeylessSigningException
{
public string Issuer { get; }
public string Reason { get; }
}
public class CertificateChainValidationException : KeylessSigningException
{
public string[] ChainSubjects { get; }
public string ValidationError { get; }
}
public class EphemeralKeyGenerationException : KeylessSigningException
{
public string Algorithm { get; }
}
```
### Metrics
```csharp
// Prometheus metrics
signer.keyless.cert_requests_total{result="success|failure|timeout"}
signer.keyless.cert_latency_seconds{quantile="0.5|0.9|0.99"}
signer.keyless.oidc_token_refresh_total{result="success|failure"}
signer.keyless.ephemeral_keys_generated_total{algorithm="ECDSA_P256|Ed25519"}
signer.keyless.cert_chain_validation_total{result="valid|expired|untrusted"}
```
### OpenTelemetry Traces
```
signer.keyless.sign
├── signer.keyless.generate_ephemeral_key
├── signer.keyless.acquire_oidc_token
├── signer.keyless.request_certificate
│ ├── http.request POST /api/v2/signingCert
│ └── signer.keyless.parse_certificate_chain
├── signer.keyless.validate_certificate_chain
└── signer.keyless.sign_payload
```
---
## Testing Requirements
### Unit Test Coverage
| Component | Test File | Coverage Target |
|-----------|-----------|-----------------|
| EphemeralKeyGenerator | `EphemeralKeyGeneratorTests.cs` | 100% |
| HttpFulcioClient | `HttpFulcioClientTests.cs` | 95% |
| KeylessDsseSigner | `KeylessDsseSignerTests.cs` | 95% |
| CertificateChainValidator | `CertificateChainValidatorTests.cs` | 100% |
| SignerKeylessOptions | `SignerKeylessOptionsTests.cs` | 100% |
### Integration Tests
```csharp
[Fact]
public async Task KeylessSigning_WithMockFulcio_ProducesValidDsse()
{
// Arrange: Mock Fulcio server returning valid cert chain
// Act: Sign a verdict payload
// Assert: DSSE envelope contains valid signature + cert chain
}
[Fact]
public async Task KeylessSigning_CertificateExpired_ThrowsValidationException()
{
// Arrange: Mock Fulcio returning expired certificate
// Act/Assert: CertificateChainValidationException thrown
}
[Fact]
public async Task KeylessSigning_FulcioUnavailable_RetriesWithBackoff()
{
// Arrange: Mock Fulcio returning 503 then 200
// Act: Sign payload
// Assert: Success after retry, metrics recorded
}
[Fact]
public async Task KeylessSigning_OidcTokenInvalid_ThrowsAcquisitionException()
{
// Arrange: Authority returns 401
// Act/Assert: OidcTokenAcquisitionException thrown
}
[Fact]
public async Task EphemeralKeyPair_Disposal_ZerosMemory()
{
// Arrange: Generate keypair
// Act: Dispose
// Assert: Private key memory is zeroed (via reflection/unsafe)
}
```
### Property-Based Tests
```csharp
[Property]
public void KeylessSigning_SamePayload_DifferentSignatures(byte[] payload)
{
// Ephemeral keys mean different signatures each time
var sig1 = await signer.SignAsync(payload);
var sig2 = await signer.SignAsync(payload);
Assert.NotEqual(sig1.Signature, sig2.Signature);
Assert.NotEqual(sig1.Certificate, sig2.Certificate);
}
[Property]
public void KeylessSigning_SignatureDeterminism_SameKeyPair(
byte[] payload, EphemeralKeyPair keyPair)
{
// Same ephemeral key produces same signature for same payload
var sig1 = Sign(payload, keyPair);
var sig2 = Sign(payload, keyPair);
Assert.Equal(sig1, sig2);
}
```
---
## Security Considerations
### Threat Model
| Threat | Mitigation |
|--------|------------|
| Private key theft | Keys exist only in memory, zeroed on disposal |
| Fulcio impersonation | TLS certificate validation, root pinning |
| OIDC token replay | Short-lived tokens, audience validation |
| Certificate forgery | Chain validation to trusted Fulcio roots |
| Timing attacks | Constant-time comparison for signatures |
### Security Checklist
- [ ] Ephemeral keys never written to disk or logs
- [ ] Private key memory zeroed in Dispose() and finalizer
- [ ] Fulcio TLS certificate validated
- [ ] OIDC token audience matches expected value
- [ ] Certificate chain validates to configured roots
- [ ] SCT (Signed Certificate Timestamp) verified when required
- [ ] No secrets in configuration (use refs: `env:`, `file:`, `vault:`)
---
## Decisions & Risks
| ID | Decision/Risk | Status | Owner | Notes |
|----|---------------|--------|-------|-------|
| D001 | Use ECDSA P-256 as default algorithm | DECIDED | — | Widest compatibility, Fulcio default |
| D002 | Support Ed25519 as alternative | DECIDED | — | Better performance, growing adoption |
| R001 | Fulcio availability dependency | OPEN | — | Mitigate with retries, circuit breaker, fallback to KMS |
| R002 | OIDC token acquisition latency | OPEN | — | Cache tokens, refresh proactively |
| R003 | Air-gap incompatibility | ACCEPTED | — | Keyless requires network; use KMS mode for air-gap |
---
## Upcoming Checkpoints
| Date | Milestone | Exit Criteria |
|------|-----------|---------------|
| +3 days | Core interfaces complete | 0001-0004 DONE |
| +7 days | Fulcio client working | 0005-0006 DONE, manual test passing |
| +10 days | Keyless signer integrated | 0007-0012 DONE |
| +14 days | Full test coverage | 0013-0018 DONE |
| +15 days | Documentation complete | 0019-0020 DONE, sprint DONE |
---
## Execution Log
| Date | Role | Action | Notes |
|------|------|--------|-------|
| 2025-12-26 | PM | Sprint created | Initial planning from keyless signing advisory |
---
## Related Documents
- **Parent Advisory:** `docs/product-advisories/25-Dec-2025 - Planning Keyless Signing for Verdicts.md`
- **Related Advisory:** `docs/product-advisories/25-Dec-2025 - Building a Deterministic Verdict Engine.md`
- **Signer Architecture:** `docs/modules/signer/architecture.md`
- **Attestor Architecture:** `docs/modules/attestor/architecture.md`
- **Successor Sprint:** `SPRINT_20251226_002_ATTESTOR_bundle_rotation.md`
---
## Appendix A: Fulcio API Contract
### Request: POST /api/v2/signingCert
```json
{
"credentials": {
"oidcIdentityToken": "eyJhbGciOiJSUzI1NiIs..."
},
"publicKeyRequest": {
"publicKey": {
"algorithm": "ECDSA",
"content": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..."
},
"proofOfPossession": "MEUCIQD..." // Optional
}
}
```
### Response: 200 OK
```json
{
"signedCertificateEmbeddedSct": {
"chain": {
"certificates": [
"-----BEGIN CERTIFICATE-----\nMIIC...",
"-----BEGIN CERTIFICATE-----\nMIIB..."
]
}
}
}
```
---
## Appendix B: DSSE Bundle with Keyless Certificate
```json
{
"payloadType": "application/vnd.in-toto+json",
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEi...",
"signatures": [
{
"keyid": "",
"sig": "MEUCIQDx5z...",
"cert": "-----BEGIN CERTIFICATE-----\nMIIC..."
}
],
"certificateChain": [
"-----BEGIN CERTIFICATE-----\nMIIC...",
"-----BEGIN CERTIFICATE-----\nMIIB..."
],
"signedCertificateTimestamp": "AO3W9T...",
"signingMode": "keyless",
"signingIdentity": {
"issuer": "https://authority.internal",
"subject": "signer@stella-ops.org",
"san": "urn:stellaops:signer"
}
}
```
---
*End of Sprint Document*

View File

@@ -0,0 +1,596 @@
# SPRINT_20251226_002_ATTESTOR_bundle_rotation
**Sprint ID:** 20251226_002_ATTESTOR
**Topic:** Attestation Bundle Rotation and Long-Term Verification
**Status:** TODO
**Priority:** P1 (High)
**Created:** 2025-12-26
**Working Directory:** `src/Attestor/`, `src/Scheduler/`
---
## Executive Summary
Implement monthly attestation bundle rotation to ensure long-term verification of keyless-signed artifacts. Since Fulcio certificates have short lifetimes (~10 minutes), attestations must be bundled with Rekor inclusion proofs and optionally re-signed with an organization key for verification beyond certificate expiry.
**Business Value:**
- Enables verification of attestations years after signing (regulatory compliance)
- Supports air-gapped environments with bundled proofs
- Provides organizational endorsement layer for high-assurance workflows
- Implements Sigstore best practices for long-term verification
**Dependencies:**
- Sprint 20251226_001 (Keyless signing client)
- Existing Rekor v2 integration in Attestor
- Scheduler module for periodic job execution
---
## Prerequisites
**Required Reading (complete before DOING):**
- [ ] `docs/modules/attestor/architecture.md` - Attestor architecture dossier
- [ ] `src/Attestor/AGENTS.md` - Module charter
- [ ] `docs/24_OFFLINE_KIT.md` - Offline bundle format
- [ ] `CLAUDE.md` - Project coding standards
- [ ] Sigstore bundle format: https://github.com/sigstore/protobuf-specs
**Technical Prerequisites:**
- [ ] Rekor v2 submission working (existing)
- [ ] Merkle inclusion proof verification (existing)
- [ ] PostgreSQL `attestor.entries` table populated
- [ ] S3/RustFS archive store configured
---
## Scope & Boundaries
### In Scope
- Attestation bundle schema design
- Bundle aggregation service
- Organization key re-signing workflow
- Scheduler job for monthly bundling
- Bundle retention policy (24 months default)
- Bundle export API
- Integration with Offline Kit
### Out of Scope
- Initial keyless signing (Sprint 001)
- CLI verification commands (Sprint 003)
- CI/CD templates (Sprint 004)
### Guardrails
- Bundles MUST be deterministic (same inputs → same bundle hash)
- Bundle creation MUST NOT modify original attestations
- Retention policy MUST be configurable per tenant
- All timestamps in UTC ISO-8601
---
## Architecture
### Bundle Data Model
```
┌─────────────────────────────────────────────────────────────────┐
│ Attestation Bundle (v1) │
├─────────────────────────────────────────────────────────────────┤
│ metadata: │
│ bundleId: sha256:<merkle_root> │
│ version: "1.0" │
│ createdAt: "2025-12-26T00:00:00Z" │
│ periodStart: "2025-12-01T00:00:00Z" │
│ periodEnd: "2025-12-31T23:59:59Z" │
│ attestationCount: 1542 │
│ orgKeyFingerprint: "sha256:abc123..." │
│ │
│ attestations: [ │
│ { │
│ entryId: "uuid-1" │
│ rekorUuid: "24296fb2..." │
│ rekorLogIndex: 12345678 │
│ artifactDigest: "sha256:..." │
│ predicateType: "verdict.stella/v1" │
│ signedAt: "2025-12-15T10:30:00Z" │
│ signingMode: "keyless" │
│ signingIdentity: { issuer, subject, san } │
│ inclusionProof: { checkpoint, path[] } │
│ envelope: { payloadType, payload, signatures[], certs[] } │
│ }, │
│ ... │
│ ] │
│ │
│ merkleTree: { │
│ algorithm: "SHA256" │
│ root: "sha256:..." │
│ leafCount: 1542 │
│ } │
│ │
│ orgSignature: { // Optional: org-key re-sign│
│ keyId: "org-signing-key-2025" │
│ algorithm: "ECDSA_P256" │
│ signature: "base64..." │
│ signedAt: "2025-12-26T01:00:00Z" │
│ certificateChain: [...] │
│ } │
└─────────────────────────────────────────────────────────────────┘
```
### Component Diagram
```
┌──────────────────────────────────────────────────────────────────┐
│ Attestor Service │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ BundleController │────────▶│ IAttestationBundler│ │
│ │ (API endpoints) │ │ (NEW) │ │
│ └────────────────────┘ └─────────┬──────────┘ │
│ │ │
│ ┌───────────────────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌────────────┐│
│ │ BundleAggregator│ │ BundleSigner │ │BundleStore ││
│ │ (NEW) │ │ (NEW) │ │(NEW) ││
│ └────────┬────────┘ └────────┬────────┘ └─────┬──────┘│
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌────────────┐│
│ │ AttestorEntry │ │ IOrgKeySigner │ │ S3/RustFS ││
│ │ Repository │ │ (KMS/HSM) │ │ Archive ││
│ │ (existing) │ │ │ │ ││
│ └─────────────────┘ └─────────────────┘ └────────────┘│
│ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ Scheduler Service │
├──────────────────────────────────────────────────────────────────┤
│ ┌────────────────────────────┐ │
│ │ BundleRotationJob │ ← Runs monthly (configurable) │
│ │ - Query attestations │ │
│ │ - Create bundle │ │
│ │ - Sign with org key │ │
│ │ - Store bundle │ │
│ │ - Apply retention policy │ │
│ └────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
### New Interfaces
```csharp
// src/Attestor/__Libraries/StellaOps.Attestor.Bundling/IAttestationBundler.cs
public interface IAttestationBundler
{
Task<AttestationBundle> CreateBundleAsync(
BundleCreationRequest request,
CancellationToken cancellationToken = default);
Task<AttestationBundle?> GetBundleAsync(
string bundleId,
CancellationToken cancellationToken = default);
Task<BundleListResult> ListBundlesAsync(
BundleListRequest request,
CancellationToken cancellationToken = default);
}
public record BundleCreationRequest(
DateTimeOffset PeriodStart,
DateTimeOffset PeriodEnd,
string? TenantId,
bool SignWithOrgKey,
string? OrgKeyId);
public record AttestationBundle(
string BundleId, // sha256:<merkle_root>
string Version,
DateTimeOffset CreatedAt,
DateTimeOffset PeriodStart,
DateTimeOffset PeriodEnd,
int AttestationCount,
IReadOnlyList<BundledAttestation> Attestations,
MerkleTreeInfo MerkleTree,
OrgSignature? OrgSignature);
public record BundledAttestation(
string EntryId,
string RekorUuid,
long RekorLogIndex,
string ArtifactDigest,
string PredicateType,
DateTimeOffset SignedAt,
string SigningMode,
SigningIdentity SigningIdentity,
InclusionProof InclusionProof,
DsseEnvelope Envelope);
public record MerkleTreeInfo(
string Algorithm,
string Root,
int LeafCount);
public record OrgSignature(
string KeyId,
string Algorithm,
string Signature,
DateTimeOffset SignedAt,
string[] CertificateChain);
```
```csharp
// src/Attestor/__Libraries/StellaOps.Attestor.Bundling/IOrgKeySigner.cs
public interface IOrgKeySigner
{
Task<OrgSignature> SignBundleAsync(
byte[] bundleDigest,
string keyId,
CancellationToken cancellationToken = default);
Task<bool> VerifyBundleAsync(
byte[] bundleDigest,
OrgSignature signature,
CancellationToken cancellationToken = default);
}
```
---
## Delivery Tracker
| ID | Task | Owner | Status | Dependencies | Acceptance Criteria |
|----|------|-------|--------|--------------|---------------------|
| 0001 | Create `StellaOps.Attestor.Bundling` library project | — | TODO | — | Project compiles, referenced by Attestor |
| 0002 | Define `AttestationBundle` record and schema | — | TODO | 0001 | JSON schema validated, versioned |
| 0003 | Implement `IBundleAggregator` for collecting attestations | — | TODO | 0002 | Queries by date range, tenant |
| 0004 | Implement deterministic Merkle tree for bundle | — | TODO | 0003 | Same attestations → same root |
| 0005 | Implement `IAttestationBundler` service | — | TODO | 0003, 0004 | Creates complete bundle |
| 0006 | Implement `IOrgKeySigner` interface | — | TODO | 0001 | Contract defined, KMS-backed |
| 0007 | Implement `KmsOrgKeySigner` | — | TODO | 0006 | Uses existing KMS infrastructure |
| 0008 | Add org-key signing to bundle workflow | — | TODO | 0005, 0007 | Optional signing step |
| 0009 | Implement `IBundleStore` for S3/RustFS | — | TODO | 0002 | Store and retrieve bundles |
| 0010 | Add bundle export API endpoint | — | TODO | 0005, 0009 | `GET /api/v1/bundles/{id}` |
| 0011 | Add bundle list API endpoint | — | TODO | 0009 | `GET /api/v1/bundles` with pagination |
| 0012 | Add bundle creation API endpoint | — | TODO | 0005 | `POST /api/v1/bundles` |
| 0013 | Define bundle retention policy schema | — | TODO | — | Configurable per tenant |
| 0014 | Implement retention policy enforcement | — | TODO | 0009, 0013 | Auto-delete after N months |
| 0015 | Create `BundleRotationJob` in Scheduler | — | TODO | 0005 | Runs on schedule |
| 0016 | Add job configuration (monthly by default) | — | TODO | 0015 | Cron expression support |
| 0017 | Integrate with Offline Kit export | — | TODO | 0009 | Bundle included in OUK |
| 0018 | Unit tests: BundleAggregator | — | TODO | 0003 | Date range, tenant filtering |
| 0019 | Unit tests: Merkle tree determinism | — | TODO | 0004 | Shuffle input → same root |
| 0020 | Unit tests: Bundle creation | — | TODO | 0005 | Complete bundle structure |
| 0021 | Unit tests: Org-key signing | — | TODO | 0007 | Sign/verify roundtrip |
| 0022 | Unit tests: Retention policy | — | TODO | 0014 | Expiry calculation, deletion |
| 0023 | Integration test: Full bundle workflow | — | TODO | 0010-0012 | Create → store → retrieve |
| 0024 | Integration test: Scheduler job | — | TODO | 0015 | Job executes, bundle created |
| 0025 | Documentation: Bundle format spec | — | TODO | 0002 | `docs/modules/attestor/bundle-format.md` |
| 0026 | Documentation: Rotation operations guide | — | TODO | 0015 | `docs/modules/attestor/operations/bundle-rotation.md` |
---
## Technical Specifications
### Configuration Schema
```yaml
# etc/attestor.yaml
attestor:
bundling:
enabled: true
schedule:
# Monthly on the 1st at 02:00 UTC
cron: "0 2 1 * *"
# Or explicit cadence
cadence: "monthly" # "weekly" | "monthly" | "quarterly"
aggregation:
# Look back period for attestations
lookbackDays: 31
# Maximum attestations per bundle
maxAttestationsPerBundle: 10000
# Batch size for database queries
queryBatchSize: 500
signing:
# Sign bundles with organization key
signWithOrgKey: true
orgKeyId: "org-signing-key-2025"
# Key rotation: use new key starting from date
keyRotation:
- keyId: "org-signing-key-2024"
validUntil: "2024-12-31T23:59:59Z"
- keyId: "org-signing-key-2025"
validFrom: "2025-01-01T00:00:00Z"
retention:
# Default retention period in months
defaultMonths: 24
# Per-tenant overrides
tenantOverrides:
"tenant-gov": 84 # 7 years for government
"tenant-finance": 120 # 10 years for finance
storage:
# Bundle storage location
backend: "s3" # "s3" | "filesystem"
s3:
bucket: "stellaops-attestor"
prefix: "bundles/"
objectLock: "governance" # WORM protection
filesystem:
path: "/var/lib/stellaops/attestor/bundles"
export:
# Include in Offline Kit
includeInOfflineKit: true
# Compression for export
compression: "zstd"
compressionLevel: 3
```
### API Endpoints
```yaml
# Bundle Management API
POST /api/v1/bundles:
description: Create a new attestation bundle
request:
periodStart: "2025-12-01T00:00:00Z"
periodEnd: "2025-12-31T23:59:59Z"
signWithOrgKey: true
orgKeyId: "org-signing-key-2025"
response:
bundleId: "sha256:abc123..."
status: "created"
attestationCount: 1542
createdAt: "2025-12-26T02:00:00Z"
GET /api/v1/bundles:
description: List bundles with pagination
query:
periodStart: "2025-01-01T00:00:00Z"
periodEnd: "2025-12-31T23:59:59Z"
limit: 20
cursor: "..."
response:
bundles: [{ bundleId, periodStart, periodEnd, attestationCount, createdAt }]
nextCursor: "..."
GET /api/v1/bundles/{bundleId}:
description: Get bundle metadata
response:
bundleId: "sha256:abc123..."
version: "1.0"
periodStart: "2025-12-01T00:00:00Z"
periodEnd: "2025-12-31T23:59:59Z"
attestationCount: 1542
merkleRoot: "sha256:..."
orgSignature: { keyId, signedAt }
createdAt: "2025-12-26T02:00:00Z"
GET /api/v1/bundles/{bundleId}/download:
description: Download full bundle (JSON or CBOR)
query:
format: "json" # "json" | "cbor"
compression: "zstd" # "none" | "gzip" | "zstd"
response:
Content-Type: application/json+zstd
Content-Disposition: attachment; filename="bundle-sha256-abc123.json.zst"
GET /api/v1/bundles/{bundleId}/attestations/{entryId}:
description: Get specific attestation from bundle
response:
entryId: "uuid-1"
rekorUuid: "24296fb2..."
envelope: { ... }
inclusionProof: { ... }
POST /api/v1/bundles/{bundleId}/verify:
description: Verify bundle integrity and signatures
response:
valid: true
merkleRootVerified: true
orgSignatureVerified: true
attestationsVerified: 1542
verifiedAt: "2025-12-26T10:00:00Z"
```
### Bundle JSON Schema
```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/schemas/attestation-bundle/v1",
"type": "object",
"required": ["metadata", "attestations", "merkleTree"],
"properties": {
"metadata": {
"type": "object",
"required": ["bundleId", "version", "createdAt", "periodStart", "periodEnd", "attestationCount"],
"properties": {
"bundleId": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
"version": { "type": "string", "const": "1.0" },
"createdAt": { "type": "string", "format": "date-time" },
"periodStart": { "type": "string", "format": "date-time" },
"periodEnd": { "type": "string", "format": "date-time" },
"attestationCount": { "type": "integer", "minimum": 0 },
"orgKeyFingerprint": { "type": "string" }
}
},
"attestations": {
"type": "array",
"items": { "$ref": "#/$defs/bundledAttestation" }
},
"merkleTree": {
"type": "object",
"required": ["algorithm", "root", "leafCount"],
"properties": {
"algorithm": { "type": "string", "enum": ["SHA256"] },
"root": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
"leafCount": { "type": "integer", "minimum": 0 }
}
},
"orgSignature": { "$ref": "#/$defs/orgSignature" }
},
"$defs": {
"bundledAttestation": {
"type": "object",
"required": ["entryId", "rekorUuid", "artifactDigest", "predicateType", "signedAt", "signingMode", "inclusionProof", "envelope"]
},
"orgSignature": {
"type": "object",
"required": ["keyId", "algorithm", "signature", "signedAt"],
"properties": {
"keyId": { "type": "string" },
"algorithm": { "type": "string", "enum": ["ECDSA_P256", "Ed25519", "RSA_PSS_SHA256"] },
"signature": { "type": "string" },
"signedAt": { "type": "string", "format": "date-time" },
"certificateChain": { "type": "array", "items": { "type": "string" } }
}
}
}
}
```
### Metrics
```csharp
// Prometheus metrics
attestor.bundle.created_total{tenant,signed}
attestor.bundle.creation_duration_seconds{quantile}
attestor.bundle.attestations_count{bundle_id}
attestor.bundle.size_bytes{bundle_id,format}
attestor.bundle.retention_deleted_total{tenant}
attestor.bundle.verification_total{result="valid|invalid|error"}
attestor.bundle.download_total{format="json|cbor",compression}
```
---
## Testing Requirements
### Unit Test Coverage
| Component | Test File | Coverage Target |
|-----------|-----------|-----------------|
| BundleAggregator | `BundleAggregatorTests.cs` | 100% |
| MerkleTreeBuilder | `MerkleTreeBuilderTests.cs` | 100% |
| AttestationBundler | `AttestationBundlerTests.cs` | 95% |
| KmsOrgKeySigner | `KmsOrgKeySignerTests.cs` | 95% |
| BundleRetentionPolicy | `BundleRetentionPolicyTests.cs` | 100% |
### Determinism Tests
```csharp
[Fact]
public async Task Bundle_SameAttestations_ShuffledOrder_SameMerkleRoot()
{
// Arrange: Create attestations in random order
var attestations = GenerateAttestations(100);
var shuffled1 = attestations.OrderBy(_ => Guid.NewGuid()).ToList();
var shuffled2 = attestations.OrderBy(_ => Guid.NewGuid()).ToList();
// Act: Create bundles
var bundle1 = await bundler.CreateBundleAsync(shuffled1);
var bundle2 = await bundler.CreateBundleAsync(shuffled2);
// Assert: Same Merkle root
Assert.Equal(bundle1.MerkleTree.Root, bundle2.MerkleTree.Root);
Assert.Equal(bundle1.BundleId, bundle2.BundleId);
}
[Fact]
public async Task Bundle_Serialization_Roundtrip_Identical()
{
// Arrange
var bundle = await CreateTestBundle();
// Act
var json1 = Serialize(bundle);
var deserialized = Deserialize(json1);
var json2 = Serialize(deserialized);
// Assert: Byte-for-byte identical
Assert.Equal(json1, json2);
}
```
### Integration Tests
```csharp
[Fact]
public async Task BundleRotationJob_ExecutesMonthly_CreatesBundle()
{
// Arrange: Populate attestor.entries with test data
// Act: Trigger scheduler job
// Assert: Bundle created with correct date range
}
[Fact]
public async Task BundleRetention_ExpiredBundles_Deleted()
{
// Arrange: Create bundles with old dates
// Act: Run retention enforcement
// Assert: Bundles beyond retention deleted
}
[Fact]
public async Task BundleOrgSigning_KmsBackend_SignsAndVerifies()
{
// Arrange: Configure KMS org key
// Act: Create signed bundle
// Assert: Org signature valid, certificate chain present
}
```
---
## Decisions & Risks
| ID | Decision/Risk | Status | Owner | Notes |
|----|---------------|--------|-------|-------|
| D001 | Monthly as default bundle cadence | DECIDED | — | Balance between overhead and granularity |
| D002 | SHA-256 for Merkle tree | DECIDED | — | Consistent with Rekor, industry standard |
| D003 | CBOR as optional compact format | DECIDED | — | ~40% smaller than JSON for transport |
| D004 | 24-month default retention | DECIDED | — | Covers most compliance requirements |
| R001 | Large bundle sizes for high-volume tenants | OPEN | — | Mitigate with pagination, streaming export |
| R002 | Org key compromise | OPEN | — | Use HSM, implement key rotation |
| R003 | S3 storage costs | OPEN | — | Enable lifecycle policies, intelligent tiering |
---
## Upcoming Checkpoints
| Date | Milestone | Exit Criteria |
|------|-----------|---------------|
| +3 days | Core data model complete | 0001-0002 DONE |
| +7 days | Aggregation and Merkle tree | 0003-0005 DONE |
| +10 days | Org signing integrated | 0006-0008 DONE |
| +14 days | API endpoints working | 0009-0012 DONE |
| +18 days | Scheduler job complete | 0013-0017 DONE |
| +21 days | Full test coverage | 0018-0024 DONE |
| +23 days | Documentation complete | 0025-0026 DONE, sprint DONE |
---
## Execution Log
| Date | Role | Action | Notes |
|------|------|--------|-------|
| 2025-12-26 | PM | Sprint created | Initial planning from keyless signing advisory |
---
## Related Documents
- **Parent Advisory:** `docs/product-advisories/25-Dec-2025 - Planning Keyless Signing for Verdicts.md`
- **Predecessor Sprint:** `SPRINT_20251226_001_SIGNER_fulcio_keyless_client.md`
- **Attestor Architecture:** `docs/modules/attestor/architecture.md`
- **Offline Kit:** `docs/24_OFFLINE_KIT.md`
- **Successor Sprint:** `SPRINT_20251226_003_ATTESTOR_offline_verification.md`
---
*End of Sprint Document*

View File

@@ -0,0 +1,51 @@
# Sprint 20251226 · Risk Budget Enforcement Automation
## Topic & Scope
- Operationalize the existing `RiskBudget` model with automated window management, consumption tracking, and notifications.
- Implement budget ledger persistence, threshold alerts, and CLI commands.
- Enable earned capacity replenishment based on performance metrics.
- **Working directory:** `src/Policy/StellaOps.Policy.Engine`, `src/Notify/StellaOps.Notify`
## Dependencies & Concurrency
- Depends on: `RiskBudget.cs` (complete), `RiskPointScoring.cs` (complete), `DeltaVerdict` (complete).
- Depends on: SPRINT_20251226_001_BE (gate integration provides consumption trigger).
- Can run in parallel with: SPRINT_20251226_003_BE (exception workflow).
## Documentation Prerequisites
- `docs/modules/policy/architecture.md`
- `docs/modules/policy/budget-attestation.md`
- `docs/modules/notify/architecture.md`
- `docs/product-advisories/archived/2025-12-21-moat-phase2/20-Dec-2025 - Moat Explanation - Risk Budgets and Diff-Aware Release Gates.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | BUDGET-01 | TODO | None | Policy Guild | Create `budget_ledger` PostgreSQL table: budget_id, service_id, tenant_id, tier, window, allocated, consumed, status, created_at, updated_at |
| 2 | BUDGET-02 | TODO | BUDGET-01 | Policy Guild | Implement `BudgetLedgerRepository` with CRUD + consumption recording |
| 3 | BUDGET-03 | TODO | BUDGET-02 | Policy Guild | Budget window management: monthly reset logic, window boundary detection, carry-over rules (none by default) |
| 4 | BUDGET-04 | TODO | BUDGET-02 | Policy Guild | Budget consumption API: `POST /api/v1/policy/budget/consume` called after gate verdict; updates ledger |
| 5 | BUDGET-05 | TODO | BUDGET-03 | Policy Guild | Threshold status computation: Green (<40%), Yellow (40-69%), Red (70-99%), Exhausted (>=100%) |
| 6 | BUDGET-06 | TODO | BUDGET-05 | Notify Guild | Budget threshold notifications: trigger alerts on Yellow/Red/Exhausted transitions |
| 7 | BUDGET-07 | TODO | BUDGET-06 | Notify Guild | Notification templates for budget alerts (Email, Slack, Teams) |
| 8 | BUDGET-08 | TODO | BUDGET-04 | Policy Guild | CLI command `stella budget status --service <id>` showing current budget state |
| 9 | BUDGET-09 | TODO | BUDGET-04 | Policy Guild | CLI command `stella budget consume --service <id> --points <n> --reason <text>` for manual adjustments |
| 10 | BUDGET-10 | TODO | BUDGET-05 | Policy Guild | Earned capacity replenishment: if MTTR/CFR improves for 2 windows, grant +10-20% budget increase |
| 11 | BUDGET-11 | TODO | BUDGET-10 | Policy Guild | Integration tests: window reset, consumption, threshold transitions, notifications |
| 12 | BUDGET-12 | TODO | BUDGET-11 | Policy Guild | Documentation: update `docs/modules/policy/budget-attestation.md` with enforcement section |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from product advisory analysis; implements risk budget enforcement from moat advisory. | Project Mgmt |
## Decisions & Risks
- Decision needed: Budget window period - monthly vs sprint-aligned. Recommend: monthly with weekly tracking.
- Decision needed: Budget carry-over between windows. Recommend: no carry-over (use it or lose it).
- Decision needed: Exhausted budget behavior - hard block or soft warn. Recommend: block high-risk (G3+), warn low-risk.
- Risk: Budget gaming via artificial low-point releases. Mitigation: minimum RP floor of 1 per release.
- Risk: Notification fatigue. Mitigation: configurable alert thresholds, aggregation windows.
## Next Checkpoints
- 2025-12-30 | BUDGET-03 complete | Window management logic verified |
- 2026-01-03 | BUDGET-06 complete | Notifications wired to Notify |
- 2026-01-06 | BUDGET-11 complete | Full integration tested |

View File

@@ -0,0 +1,626 @@
# SPRINT_20251226_003_ATTESTOR_offline_verification
**Sprint ID:** 20251226_003_ATTESTOR
**Topic:** Offline/Air-Gapped Attestation Verification
**Status:** TODO
**Priority:** P2 (Medium-High)
**Created:** 2025-12-26
**Working Directory:** `src/Attestor/`, `src/Cli/`
---
## Executive Summary
Implement offline verification capabilities for keyless-signed attestations. This enables air-gapped environments to verify attestations using bundled Rekor inclusion proofs and Fulcio root certificates without network connectivity. Essential for sovereign, defense, and regulated environments.
**Business Value:**
- Enables attestation verification in air-gapped/disconnected networks
- Supports regulatory compliance requiring offline audit capabilities
- Reduces network dependencies for high-security environments
- Completes the keyless signing story for sovereign customers
**Dependencies:**
- Sprint 20251226_001 (Keyless signing client)
- Sprint 20251226_002 (Bundle rotation)
- Existing Offline Kit infrastructure (`docs/24_OFFLINE_KIT.md`)
---
## Prerequisites
**Required Reading (complete before DOING):**
- [ ] `docs/24_OFFLINE_KIT.md` - Offline Update Kit specification
- [ ] `docs/modules/attestor/architecture.md` - Attestor architecture (§ Offline Mode)
- [ ] `src/Attestor/AGENTS.md` - Module charter
- [ ] `src/Cli/AGENTS.md` - CLI module charter (if exists)
- [ ] `CLAUDE.md` - Project coding standards
**Technical Prerequisites:**
- [ ] Bundle rotation working (Sprint 002)
- [ ] Fulcio root certificates bundled
- [ ] CLI infrastructure for new commands
---
## Scope & Boundaries
### In Scope
- Offline verification service implementation
- Bundled Fulcio roots in Offline Kit
- CLI commands for offline verification
- Bundle export command
- Verification without network connectivity
- Air-gap verification playbook documentation
### Out of Scope
- Initial keyless signing (Sprint 001)
- Bundle creation (Sprint 002)
- CI/CD templates (Sprint 004)
### Guardrails
- Verification MUST work completely offline once materials are imported
- No network calls during offline verification mode
- Verification results MUST be deterministic
- Support both JSON and CBOR bundle formats
---
## Architecture
### Offline Verification Flow
```
┌────────────────────────────────────────────────────────────────────┐
│ Air-Gapped Environment │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌────────────────┐ │
│ │ Offline Kit │ │ Bundle Store │ │ Fulcio Roots │ │
│ │ (imported) │───▶│ (local) │ │ (bundled) │ │
│ └─────────────────┘ └────────┬────────┘ └───────┬────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ OfflineVerificationService │ │
│ │ - Load bundle from local store │ │
│ │ - Verify Merkle inclusion │ │
│ │ - Verify DSSE signatures │ │
│ │ - Validate certificate chains │ │
│ │ - Check org signature (if present) │ │
│ └─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ VerificationResult │ │
│ │ - attestationValid: true/false │ │
│ │ - merkleProofValid: true/false │ │
│ │ - signatureValid: true/false │ │
│ │ - certificateChainValid: true/false │ │
│ │ - orgSignatureValid: true/false │ │
│ │ - verifiedAt: timestamp │ │
│ └─────────────────────────────────────┘ │
│ │
│ CLI Interface: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ $ stella attest verify --offline --bundle /path/to/bundle │ │
│ │ $ stella attest verify --offline --artifact sha256:... │ │
│ │ $ stella attest export-bundle --image sha256:... -o ./ │ │
│ │ $ stella attest import-roots --path /path/to/fulcio.pem │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘
```
### Components
```
┌──────────────────────────────────────────────────────────────────┐
│ Attestor Service │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Existing Components: │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ IAttestorVerifica- │ │ MerkleProofVerifier│ │
│ │ tionService │ │ (existing) │ │
│ └────────────────────┘ └────────────────────┘ │
│ │
│ New Components: │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ IOfflineVerifier │ │ IOfflineRootStore │ │
│ │ (NEW) │ │ (NEW) │ │
│ └─────────┬──────────┘ └─────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ OfflineVerifier │ │ FileSystemRoot │ │
│ │ Impl │ │ Store │ │
│ └────────────────────┘ └────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ CLI Module │
├──────────────────────────────────────────────────────────────────┤
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ AttestCommands │ │
│ │ - VerifyCommand (--offline flag) │ │
│ │ - ExportBundleCommand │ │
│ │ - ImportRootsCommand │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
### New Interfaces
```csharp
// src/Attestor/__Libraries/StellaOps.Attestor.Offline/IOfflineVerifier.cs
public interface IOfflineVerifier
{
Task<OfflineVerificationResult> VerifyBundleAsync(
AttestationBundle bundle,
OfflineVerificationOptions options,
CancellationToken cancellationToken = default);
Task<OfflineVerificationResult> VerifyAttestationAsync(
BundledAttestation attestation,
OfflineVerificationOptions options,
CancellationToken cancellationToken = default);
Task<OfflineVerificationResult> VerifyByArtifactAsync(
string artifactDigest,
string bundlePath,
OfflineVerificationOptions options,
CancellationToken cancellationToken = default);
}
public record OfflineVerificationOptions(
bool VerifyMerkleProof = true,
bool VerifySignatures = true,
bool VerifyCertificateChain = true,
bool VerifyOrgSignature = true,
bool RequireOrgSignature = false,
string? FulcioRootPath = null,
string? OrgKeyPath = null,
bool StrictMode = false);
public record OfflineVerificationResult(
bool Valid,
bool MerkleProofValid,
bool SignaturesValid,
bool CertificateChainValid,
bool OrgSignatureValid,
string? OrgSignatureKeyId,
DateTimeOffset VerifiedAt,
IReadOnlyList<VerificationIssue> Issues);
public record VerificationIssue(
VerificationIssueSeverity Severity,
string Code,
string Message,
string? AttestationId);
public enum VerificationIssueSeverity { Info, Warning, Error, Critical }
```
```csharp
// src/Attestor/__Libraries/StellaOps.Attestor.Offline/IOfflineRootStore.cs
public interface IOfflineRootStore
{
Task<X509Certificate2Collection> GetFulcioRootsAsync(
CancellationToken cancellationToken = default);
Task<X509Certificate2Collection> GetOrgSigningKeysAsync(
CancellationToken cancellationToken = default);
Task ImportRootsAsync(
string pemPath,
RootType rootType,
CancellationToken cancellationToken = default);
}
public enum RootType { Fulcio, OrgSigning, Rekor }
```
---
## Delivery Tracker
| ID | Task | Owner | Status | Dependencies | Acceptance Criteria |
|----|------|-------|--------|--------------|---------------------|
| 0001 | Create `StellaOps.Attestor.Offline` library project | — | TODO | — | Project compiles, referenced by Attestor |
| 0002 | Define `OfflineVerificationResult` and options | — | TODO | 0001 | Comprehensive result model |
| 0003 | Implement `IOfflineRootStore` interface | — | TODO | 0001 | Contract for root certificate access |
| 0004 | Implement `FileSystemRootStore` | — | TODO | 0003 | Reads roots from configured paths |
| 0005 | Implement `IOfflineVerifier` interface | — | TODO | 0002, 0004 | Core verification contract |
| 0006 | Implement `OfflineVerifier` service | — | TODO | 0005 | Full offline verification logic |
| 0007 | Add Merkle proof verification for bundles | — | TODO | 0006 | Verify attestation in bundle tree |
| 0008 | Add DSSE signature verification (offline) | — | TODO | 0006 | Verify without network |
| 0009 | Add certificate chain validation (offline) | — | TODO | 0006, 0004 | Validate to bundled Fulcio roots |
| 0010 | Add org signature verification | — | TODO | 0006, 0004 | Verify org-key signature if present |
| 0011 | Bundle Fulcio roots in Offline Kit | — | TODO | — | Update OUK packaging script |
| 0012 | Add Rekor checkpoint bundle support | — | TODO | — | Optional bundled checkpoints |
| 0013 | CLI: Add `stella attest verify --offline` | — | TODO | 0006 | Offline verification command |
| 0014 | CLI: Add `--bundle` flag for local bundle | — | TODO | 0013 | Specify bundle path |
| 0015 | CLI: Add `--artifact` flag for artifact lookup | — | TODO | 0013 | Find attestation by digest |
| 0016 | CLI: Add `stella attest export-bundle` | — | TODO | Sprint 002 | Export bundle for transport |
| 0017 | CLI: Add `stella attest import-roots` | — | TODO | 0004 | Import root certificates |
| 0018 | CLI: Add verification result formatting | — | TODO | 0013 | Human-readable and JSON output |
| 0019 | Unit tests: FileSystemRootStore | — | TODO | 0004 | Root loading, PEM parsing |
| 0020 | Unit tests: OfflineVerifier | — | TODO | 0006 | All verification paths |
| 0021 | Unit tests: Merkle proof verification | — | TODO | 0007 | Valid/invalid proofs |
| 0022 | Unit tests: Certificate chain validation | — | TODO | 0009 | Valid/expired/untrusted |
| 0023 | Integration test: Full offline verification | — | TODO | 0006 | No network calls made |
| 0024 | Integration test: CLI offline verify | — | TODO | 0013 | End-to-end CLI test |
| 0025 | Integration test: Offline Kit import + verify | — | TODO | 0011 | Complete air-gap flow |
| 0026 | Documentation: Air-gap verification playbook | — | TODO | 0013 | `docs/airgap/attestation-verification.md` |
| 0027 | Documentation: CLI attest commands | — | TODO | 0013 | `docs/modules/cli/guides/commands/attest.md` |
| 0028 | Update Offline Kit documentation | — | TODO | 0011 | Add attestation bundle section |
---
## Technical Specifications
### Configuration Schema
```yaml
# etc/attestor.yaml
attestor:
offline:
enabled: true
roots:
# Fulcio root certificates for keyless verification
fulcio:
bundlePath: "/etc/stellaops/roots/fulcio-roots.pem"
# Alternative: embedded in Offline Kit
useOfflineKit: true
offlineKitPath: "/var/lib/stellaops/offline-kit/roots"
# Organization signing keys for bundle verification
orgSigning:
bundlePath: "/etc/stellaops/roots/org-signing.pem"
keyIds:
- "org-signing-key-2024"
- "org-signing-key-2025"
# Rekor checkpoints (optional, for additional verification)
rekorCheckpoints:
enabled: false
bundlePath: "/etc/stellaops/roots/rekor-checkpoints.json"
verification:
# Strict mode: all checks must pass
strictMode: false
# Require org signature on bundles
requireOrgSignature: false
# Allow verification of individual attestations without bundle
allowUnbundled: true
storage:
# Local bundle cache
bundleCachePath: "/var/lib/stellaops/attestor/bundle-cache"
# Maximum cache size
maxCacheSizeMb: 1024
```
### CLI Commands
```bash
# Verify attestation offline using local bundle
stella attest verify --offline \
--bundle /path/to/bundle.json \
--artifact sha256:abc123...
# Output:
# Verification Result:
# ────────────────────────────────────────────
# Artifact: sha256:abc123...
# Bundle: sha256:def456... (2025-12-01 to 2025-12-31)
# Status: ✅ VALID
#
# Checks:
# ✅ Merkle Proof: Valid (leaf 42 of 1542)
# ✅ DSSE Signature: Valid (ECDSA_P256)
# ✅ Certificate Chain: Valid (Fulcio → Sigstore Root)
# ✅ Org Signature: Valid (org-signing-key-2025)
#
# Signing Identity:
# Issuer: https://authority.internal
# Subject: signer@stella-ops.org
# SAN: urn:stellaops:signer
#
# Verified At: 2025-12-26T10:30:00Z
# Verify with JSON output
stella attest verify --offline \
--bundle /path/to/bundle.json \
--artifact sha256:abc123... \
--output json
# Export bundle for transport to air-gapped environment
stella attest export-bundle \
--image sha256:abc123... \
--period-start 2025-12-01 \
--period-end 2025-12-31 \
--include-roots \
--output /mnt/usb/attestation-bundle.json.zst
# Import Fulcio roots into local store
stella attest import-roots \
--path /mnt/usb/fulcio-roots.pem \
--type fulcio
# List available bundles
stella attest list-bundles \
--local-only \
--format table
```
### Verification Algorithm
```csharp
public async Task<OfflineVerificationResult> VerifyBundleAsync(
AttestationBundle bundle,
OfflineVerificationOptions options,
CancellationToken cancellationToken)
{
var issues = new List<VerificationIssue>();
// 1. Verify bundle Merkle root
var merkleValid = VerifyMerkleTree(bundle);
if (!merkleValid)
{
issues.Add(new(Critical, "MERKLE_INVALID", "Bundle Merkle root mismatch"));
}
// 2. Verify org signature (if present and required)
var orgSigValid = true;
if (bundle.OrgSignature != null)
{
orgSigValid = await VerifyOrgSignatureAsync(bundle, options);
if (!orgSigValid)
{
issues.Add(new(Critical, "ORG_SIG_INVALID", "Organization signature invalid"));
}
}
else if (options.RequireOrgSignature)
{
issues.Add(new(Critical, "ORG_SIG_MISSING", "Required org signature missing"));
orgSigValid = false;
}
// 3. Verify each attestation
var signaturesValid = true;
var certsValid = true;
foreach (var attestation in bundle.Attestations)
{
// 3a. Verify Merkle inclusion
var inBundle = VerifyMerkleInclusion(attestation, bundle.MerkleTree);
if (!inBundle)
{
issues.Add(new(Critical, "MERKLE_INCLUSION",
$"Attestation {attestation.EntryId} not in Merkle tree"));
}
// 3b. Verify DSSE signature
var sigValid = VerifyDsseSignature(attestation.Envelope);
if (!sigValid)
{
signaturesValid = false;
issues.Add(new(Critical, "DSSE_SIG_INVALID",
$"Invalid signature on {attestation.EntryId}"));
}
// 3c. Verify certificate chain (offline)
if (options.VerifyCertificateChain)
{
var roots = await _rootStore.GetFulcioRootsAsync(cancellationToken);
var chainValid = VerifyCertificateChain(
attestation.Envelope.CertificateChain, roots);
if (!chainValid)
{
certsValid = false;
issues.Add(new(Critical, "CERT_CHAIN_INVALID",
$"Invalid cert chain on {attestation.EntryId}"));
}
}
// 3d. Verify Rekor inclusion proof (optional)
if (attestation.InclusionProof != null && options.VerifyMerkleProof)
{
var proofValid = VerifyRekorInclusionProof(
attestation.Envelope, attestation.InclusionProof);
if (!proofValid)
{
issues.Add(new(Warning, "REKOR_PROOF_INVALID",
$"Invalid Rekor proof on {attestation.EntryId}"));
}
}
}
var valid = merkleValid && signaturesValid && certsValid && orgSigValid;
return new OfflineVerificationResult(
Valid: valid,
MerkleProofValid: merkleValid,
SignaturesValid: signaturesValid,
CertificateChainValid: certsValid,
OrgSignatureValid: orgSigValid,
OrgSignatureKeyId: bundle.OrgSignature?.KeyId,
VerifiedAt: DateTimeOffset.UtcNow,
Issues: issues);
}
```
### Offline Kit Integration
```yaml
# Offline Kit structure for attestations
/offline-kit/
├── attestations/
│ ├── bundles/
│ │ ├── bundle-2025-11.json.zst
│ │ ├── bundle-2025-12.json.zst
│ │ └── manifest.json # Bundle inventory
│ └── roots/
│ ├── fulcio-roots.pem # Fulcio root certificates
│ ├── sigstore-root.pem # Sigstore TUF root
│ ├── org-signing-2024.pem # Org signing key 2024
│ ├── org-signing-2025.pem # Org signing key 2025
│ └── rekor-checkpoints.json # Optional Rekor checkpoints
├── ...
```
### Metrics
```csharp
// Prometheus metrics
attestor.offline.verify_total{result="valid|invalid|error",mode="bundle|single"}
attestor.offline.verify_duration_seconds{quantile}
attestor.offline.issues_total{severity="info|warning|error|critical",code}
attestor.offline.roots_loaded_total{type="fulcio|org|rekor"}
cli.attest.verify.offline_total{result}
cli.attest.export_bundle_total{result}
```
---
## Testing Requirements
### Unit Test Coverage
| Component | Test File | Coverage Target |
|-----------|-----------|-----------------|
| FileSystemRootStore | `FileSystemRootStoreTests.cs` | 100% |
| OfflineVerifier | `OfflineVerifierTests.cs` | 95% |
| MerkleInclusionVerifier | `MerkleInclusionVerifierTests.cs` | 100% |
| CertificateChainValidator | `OfflineCertChainValidatorTests.cs` | 100% |
### Network Isolation Tests
```csharp
[Fact]
public async Task OfflineVerification_NoNetworkCalls_WhenOfflineModeEnabled()
{
// Arrange: Configure network monitor
var networkMonitor = new NetworkCallMonitor();
var verifier = CreateOfflineVerifier(networkMonitor);
var bundle = LoadTestBundle();
// Act
var result = await verifier.VerifyBundleAsync(bundle, new OfflineVerificationOptions());
// Assert: Zero network calls made
Assert.Equal(0, networkMonitor.CallCount);
Assert.True(result.Valid);
}
[Fact]
public async Task OfflineVerification_SucceedsWithBundledRoots()
{
// Arrange: Import roots from Offline Kit
await ImportRootsFromOfflineKit();
var bundle = LoadTestBundle();
// Act: Disconnect network (mock)
DisableNetwork();
var result = await verifier.VerifyBundleAsync(bundle, new OfflineVerificationOptions());
// Assert
Assert.True(result.Valid);
Assert.True(result.CertificateChainValid);
}
```
### CLI Tests
```csharp
[Fact]
public async Task CLI_VerifyOffline_ValidBundle_ReturnsSuccess()
{
// Arrange
var bundlePath = CreateTestBundle();
var artifactDigest = "sha256:abc123...";
// Act
var result = await RunCli(
"attest", "verify", "--offline",
"--bundle", bundlePath,
"--artifact", artifactDigest);
// Assert
Assert.Equal(0, result.ExitCode);
Assert.Contains("VALID", result.Output);
}
[Fact]
public async Task CLI_ExportBundle_CreatesValidBundle()
{
// Arrange
var outputPath = GetTempFilePath();
// Act
var result = await RunCli(
"attest", "export-bundle",
"--image", "sha256:abc123...",
"--include-roots",
"--output", outputPath);
// Assert
Assert.Equal(0, result.ExitCode);
Assert.True(File.Exists(outputPath));
// Verify exported bundle is valid
var bundle = LoadBundle(outputPath);
Assert.NotNull(bundle);
Assert.True(bundle.Attestations.Count > 0);
}
```
---
## Decisions & Risks
| ID | Decision/Risk | Status | Owner | Notes |
|----|---------------|--------|-------|-------|
| D001 | Bundle Fulcio roots in Offline Kit | DECIDED | — | Essential for air-gap verification |
| D002 | Support both JSON and CBOR formats | DECIDED | — | JSON for debugging, CBOR for size |
| D003 | Org signature optional by default | DECIDED | — | Strict mode requires it |
| R001 | Root certificate rotation | OPEN | — | Need update mechanism for bundled roots |
| R002 | Bundle size for long periods | OPEN | — | Pagination, streaming decompression |
| R003 | Clock skew in air-gapped env | OPEN | — | Document time sync requirements |
---
## Upcoming Checkpoints
| Date | Milestone | Exit Criteria |
|------|-----------|---------------|
| +3 days | Core interfaces complete | 0001-0005 DONE |
| +7 days | Verification logic working | 0006-0010 DONE |
| +10 days | Offline Kit integration | 0011-0012 DONE |
| +14 days | CLI commands complete | 0013-0018 DONE |
| +18 days | Full test coverage | 0019-0025 DONE |
| +20 days | Documentation complete | 0026-0028 DONE, sprint DONE |
---
## Execution Log
| Date | Role | Action | Notes |
|------|------|--------|-------|
| 2025-12-26 | PM | Sprint created | Initial planning from keyless signing advisory |
---
## Related Documents
- **Parent Advisory:** `docs/product-advisories/25-Dec-2025 - Planning Keyless Signing for Verdicts.md`
- **Predecessor Sprints:**
- `SPRINT_20251226_001_SIGNER_fulcio_keyless_client.md`
- `SPRINT_20251226_002_ATTESTOR_bundle_rotation.md`
- **Offline Kit:** `docs/24_OFFLINE_KIT.md`
- **Attestor Architecture:** `docs/modules/attestor/architecture.md`
- **Successor Sprint:** `SPRINT_20251226_004_BE_cicd_signing_templates.md`
---
*End of Sprint Document*

View File

@@ -0,0 +1,60 @@
# Sprint 20251226 · Exception Approval Workflow
## Topic & Scope
- Implement role-based exception approval workflows building on existing `ExceptionAdapter`.
- Add approval request entity, time-limited overrides, and comprehensive audit trails.
- Integrate with Authority for approver role enforcement.
- **Working directory:** `src/Policy/StellaOps.Policy.Engine`, `src/Authority/StellaOps.Authority`
## Dependencies & Concurrency
- Depends on: `ExceptionAdapter.cs` (complete), `ExceptionLifecycleService` (complete).
- Depends on: SPRINT_20251226_001_BE (gate bypass requires approval workflow).
- Can run in parallel with: SPRINT_20251226_002_BE (budget enforcement).
## Documentation Prerequisites
- `docs/modules/policy/architecture.md`
- `docs/modules/authority/architecture.md`
- `docs/product-advisories/26-Dec-2026 - Diff-Aware Releases and Auditable Exceptions.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | EXCEPT-01 | TODO | None | Policy Guild | Create `exception_approval_requests` PostgreSQL table: request_id, exception_id, requestor_id, approver_ids[], status, justification, evidence_refs[], created_at, expires_at |
| 2 | EXCEPT-02 | TODO | EXCEPT-01 | Policy Guild | Implement `ExceptionApprovalRepository` with request/approve/reject operations |
| 3 | EXCEPT-03 | TODO | EXCEPT-02 | Policy Guild | Approval rules engine: define required approvers by gate level (G1=1 peer, G2=code owner, G3+=DM+PM) |
| 4 | EXCEPT-04 | TODO | EXCEPT-03 | Authority Guild | Create `exception:approve` and `exception:request` scopes in Authority |
| 5 | EXCEPT-05 | TODO | EXCEPT-04 | Policy Guild | API endpoint `POST /api/v1/policy/exception/request` to initiate approval workflow |
| 6 | EXCEPT-06 | TODO | EXCEPT-04 | Policy Guild | API endpoint `POST /api/v1/policy/exception/{id}/approve` for approver action |
| 7 | EXCEPT-07 | TODO | EXCEPT-04 | Policy Guild | API endpoint `POST /api/v1/policy/exception/{id}/reject` for rejection with reason |
| 8 | EXCEPT-08 | TODO | EXCEPT-02 | Policy Guild | Time-limited overrides: max TTL enforcement (30d default), auto-expiry with notification |
| 9 | EXCEPT-09 | TODO | EXCEPT-06 | Policy Guild | Audit trail: log all approval actions with who/when/why/evidence to `exception_audit` table |
| 10 | EXCEPT-10 | TODO | EXCEPT-06 | Policy Guild | CLI command `stella exception request --cve <id> --scope <image> --reason <text> --ttl <days>` |
| 11 | EXCEPT-11 | TODO | EXCEPT-06 | Policy Guild | CLI command `stella exception approve --request <id>` for approvers |
| 12 | EXCEPT-12 | TODO | EXCEPT-08 | Notify Guild | Approval request notifications to designated approvers |
| 13 | EXCEPT-13 | TODO | EXCEPT-08 | Notify Guild | Expiry warning notifications (7d, 1d before expiry) |
| 14 | EXCEPT-14 | TODO | EXCEPT-09 | Policy Guild | Integration tests: request/approve/reject flows, TTL enforcement, audit trail |
| 15 | EXCEPT-15 | TODO | EXCEPT-14 | Policy Guild | Documentation: add exception workflow section to policy architecture doc |
| 16 | EXCEPT-16 | TODO | EXCEPT-08 | Scheduler Guild | Auto-revalidation job: re-test exceptions on expiry, "fix available" feed signal, or EPSS increase |
| 17 | EXCEPT-17 | TODO | EXCEPT-16 | Policy Guild | Flip gate to "needs re-review" on revalidation failure with notification |
| 18 | EXCEPT-18 | TODO | EXCEPT-01 | Policy Guild | Exception inheritance: repo→image→env scoping with explicit shadowing |
| 19 | EXCEPT-19 | TODO | EXCEPT-18 | Policy Guild | Conflict surfacing: detect and report shadowed exceptions in evaluation |
| 20 | EXCEPT-20 | TODO | EXCEPT-09 | Attestor Guild | OCI-attached exception attestation: store exception as `application/vnd.stellaops.exception+json` |
| 21 | EXCEPT-21 | TODO | EXCEPT-20 | Policy Guild | CLI command `stella exception export --id <id> --format oci-attestation` |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from product advisory analysis; implements auditable exceptions from diff-aware release gates advisory. | Project Mgmt |
| 2025-12-26 | Added EXCEPT-16 through EXCEPT-21 from "Diff-Aware Releases and Auditable Exceptions" advisory (auto-revalidation, inheritance, OCI attestation). Advisory marked SUPERSEDED. | Project Mgmt |
## Decisions & Risks
- Decision needed: Can exceptions be self-approved for G1 level? Recommend: yes for G0-G1, no for G2+.
- Decision needed: Evidence requirement strictness. Recommend: mandatory for G2+, optional for G0-G1.
- Decision needed: Exception inheritance (repo -> image -> env). Recommend: explicit shadowing with conflict surfacing.
- Risk: Approval bottleneck slowing releases. Mitigation: parallel approval paths, escalation timeouts.
- Risk: Expired exceptions causing sudden build failures. Mitigation: 7d/1d expiry warnings, grace period option.
## Next Checkpoints
- 2025-12-30 | EXCEPT-03 complete | Approval rules engine implemented |
- 2026-01-03 | EXCEPT-07 complete | All API endpoints functional |
- 2026-01-06 | EXCEPT-14 complete | Full workflow integration tested |

View File

@@ -0,0 +1,621 @@
# SPRINT_20251226_004_BE_cicd_signing_templates
**Sprint ID:** 20251226_004_BE
**Topic:** CI/CD Keyless Signing Integration Templates
**Status:** TODO
**Priority:** P2 (Medium)
**Created:** 2025-12-26
**Working Directory:** `docs/`, `.gitea/workflows/`, `deploy/`
---
## Executive Summary
Create production-ready CI/CD templates for keyless signing integration. Provides GitHub Actions, GitLab CI, and Gitea workflow templates that enable zero-configuration keyless signing in pipelines using OIDC identity tokens. Includes identity verification policies and verification gate examples.
**Business Value:**
- Accelerates customer adoption with ready-to-use templates
- Reduces integration friction (copy-paste to production)
- Establishes best practices for identity verification
- Demonstrates Sigstore integration patterns
**Dependencies:**
- Sprint 20251226_001 (Keyless signing client)
- Sprint 20251226_002 (Bundle rotation)
- Sprint 20251226_003 (Offline verification)
---
## Prerequisites
**Required Reading (complete before DOING):**
- [ ] `docs/modules/signer/architecture.md` - Signer architecture
- [ ] `CLAUDE.md` - Project standards
- [ ] GitHub OIDC documentation: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
- [ ] GitLab OIDC documentation: https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html
- [ ] Sigstore cosign documentation: https://docs.sigstore.dev/cosign/signing/signing_with_containers/
**Technical Prerequisites:**
- [ ] Keyless signing operational (Sprint 001)
- [ ] Attestor bundle API available (Sprint 002)
- [ ] Verification endpoints working
---
## Scope & Boundaries
### In Scope
- GitHub Actions workflow template
- GitLab CI template
- Gitea workflow template (dogfooding)
- Identity constraint documentation
- Verification gate examples
- Integration guide documentation
### Out of Scope
- Core signing implementation (Sprint 001)
- Bundle rotation (Sprint 002)
- Offline verification (Sprint 003)
- Jenkins, Azure DevOps, CircleCI templates (future)
### Guardrails
- Templates MUST be copy-paste ready
- No hard-coded secrets in templates
- Identity constraints MUST be configurable
- Templates MUST handle errors gracefully
---
## Architecture
### OIDC Flow in CI/CD
```
┌─────────────────────────────────────────────────────────────────────┐
│ CI/CD Pipeline │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Build Step │─────▶│ Sign Step │─────▶│ Verify Gate │ │
│ │ - Build image │ │ - Get OIDC tok │ │ - Verify sig │ │
│ │ - Generate SBOM│ │ - Sign artifact│ │ - Check policy │ │
│ │ - Push to reg │ │ - Push attesta │ │ - Pass/Fail │ │
│ └────────────────┘ └───────┬────────┘ └────────────────┘ │
│ │ │
└──────────────────────────────────┼───────────────────────────────────┘
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ CI Platform │ │ Fulcio │ │ Rekor │
│ OIDC Provider│ │ (Sigstore) │ │ (Sigstore) │
│ │ │ │ │ │
│ Issues token │────▶│ Issues cert │────▶│ Logs entry │
│ with claims │ │ for identity │ │ transparency │
└──────────────┘ └──────────────┘ └──────────────┘
```
### Identity Verification Matrix
```
┌───────────────────────────────────────────────────────────────────────┐
│ Identity Constraint Policy │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ GitHub Actions: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Issuer: https://token.actions.githubusercontent.com │ │
│ │ Subject: repo:org/repo:ref:refs/heads/main │ │
│ │ OR repo:org/repo:environment:production │ │
│ │ SAN: https://github.com/org/repo/.github/workflows/x.yml │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ GitLab CI: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Issuer: https://gitlab.com │ │
│ │ Subject: project_path:org/repo:ref_type:branch:ref:main │ │
│ │ SAN: https://gitlab.com/org/repo │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ Gitea: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Issuer: https://git.stella-ops.org │ │
│ │ Subject: org/repo:ref:refs/heads/main │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────┘
```
---
## Delivery Tracker
| ID | Task | Owner | Status | Dependencies | Acceptance Criteria |
|----|------|-------|--------|--------------|---------------------|
| 0001 | Create GitHub Actions template directory | — | TODO | — | `.github/workflows/examples/` structure |
| 0002 | Implement `stellaops-sign.yml` reusable workflow | — | TODO | 0001 | Keyless signing for any artifact |
| 0003 | Implement `stellaops-verify.yml` reusable workflow | — | TODO | 0001 | Verification gate |
| 0004 | Create container signing example | — | TODO | 0002 | Sign + push OCI attestation |
| 0005 | Create SBOM signing example | — | TODO | 0002 | Sign SBOM, attach to image |
| 0006 | Create verdict signing example | — | TODO | 0002 | Sign policy verdict |
| 0007 | Create verification gate example | — | TODO | 0003 | Block deploy on invalid sig |
| 0008 | Create GitLab CI template directory | — | TODO | — | `deploy/gitlab/examples/` |
| 0009 | Implement `.gitlab-ci-stellaops.yml` template | — | TODO | 0008 | Include-able signing jobs |
| 0010 | Create GitLab signing job | — | TODO | 0009 | OIDC → keyless sign |
| 0011 | Create GitLab verification job | — | TODO | 0009 | Verification gate |
| 0012 | Update Gitea workflows for dogfooding | — | TODO | — | `.gitea/workflows/` |
| 0013 | Add keyless signing to release workflow | — | TODO | 0012 | Sign StellaOps releases |
| 0014 | Add verification to deploy workflow | — | TODO | 0012 | Verify before deploy |
| 0015 | Document identity constraint patterns | — | TODO | — | `docs/guides/identity-constraints.md` |
| 0016 | Document issuer allowlisting | — | TODO | 0015 | Security best practices |
| 0017 | Document subject patterns | — | TODO | 0015 | Branch/environment constraints |
| 0018 | Create troubleshooting guide | — | TODO | — | Common errors and solutions |
| 0019 | Create quick-start guide | — | TODO | — | 5-minute integration |
| 0020 | Test: GitHub Actions template | — | TODO | 0002-0007 | End-to-end in test repo |
| 0021 | Test: GitLab CI template | — | TODO | 0009-0011 | End-to-end in test project |
| 0022 | Test: Gitea workflows | — | TODO | 0012-0014 | End-to-end in StellaOps repo |
| 0023 | Test: Cross-platform verification | — | TODO | 0020-0022 | Verify GitHub sig in GitLab |
| 0024 | Documentation review and polish | — | TODO | 0015-0019 | Technical writer review |
---
## Technical Specifications
### GitHub Actions Reusable Workflow
```yaml
# .github/workflows/examples/stellaops-sign.yml
name: StellaOps Keyless Sign
on:
workflow_call:
inputs:
artifact-digest:
description: 'SHA256 digest of artifact to sign'
required: true
type: string
artifact-type:
description: 'Type: image, sbom, verdict'
required: false
type: string
default: 'image'
stellaops-url:
description: 'StellaOps API URL'
required: false
type: string
default: 'https://api.stella-ops.org'
push-attestation:
description: 'Push attestation to registry'
required: false
type: boolean
default: true
outputs:
attestation-digest:
description: 'Digest of created attestation'
value: ${{ jobs.sign.outputs.attestation-digest }}
rekor-uuid:
description: 'Rekor transparency log UUID'
value: ${{ jobs.sign.outputs.rekor-uuid }}
jobs:
sign:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read
packages: write # If pushing to GHCR
outputs:
attestation-digest: ${{ steps.sign.outputs.attestation-digest }}
rekor-uuid: ${{ steps.sign.outputs.rekor-uuid }}
steps:
- name: Install StellaOps CLI
uses: stella-ops/setup-cli@v1
with:
version: 'latest'
- name: Get OIDC Token
id: oidc
run: |
OIDC_TOKEN=$(curl -sLS "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore" \
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
| jq -r '.value')
echo "::add-mask::${OIDC_TOKEN}"
echo "token=${OIDC_TOKEN}" >> $GITHUB_OUTPUT
- name: Keyless Sign
id: sign
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
STELLAOPS_URL: ${{ inputs.stellaops-url }}
run: |
RESULT=$(stella attest sign \
--keyless \
--artifact "${{ inputs.artifact-digest }}" \
--type "${{ inputs.artifact-type }}" \
--output json)
echo "attestation-digest=$(echo $RESULT | jq -r '.attestationDigest')" >> $GITHUB_OUTPUT
echo "rekor-uuid=$(echo $RESULT | jq -r '.rekorUuid')" >> $GITHUB_OUTPUT
- name: Push Attestation
if: ${{ inputs.push-attestation }}
env:
STELLAOPS_URL: ${{ inputs.stellaops-url }}
run: |
stella attest push \
--attestation "${{ steps.sign.outputs.attestation-digest }}" \
--registry "${{ github.repository }}"
- name: Summary
run: |
echo "## Attestation Created" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Artifact | \`${{ inputs.artifact-digest }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Attestation | \`${{ steps.sign.outputs.attestation-digest }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Rekor UUID | \`${{ steps.sign.outputs.rekor-uuid }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Signing Mode | Keyless (Fulcio) |" >> $GITHUB_STEP_SUMMARY
```
### GitHub Actions Verification Gate
```yaml
# .github/workflows/examples/stellaops-verify.yml
name: StellaOps Verify Gate
on:
workflow_call:
inputs:
artifact-digest:
description: 'SHA256 digest of artifact to verify'
required: true
type: string
stellaops-url:
description: 'StellaOps API URL'
required: false
type: string
default: 'https://api.stella-ops.org'
certificate-identity:
description: 'Expected OIDC identity (regex)'
required: true
type: string
certificate-oidc-issuer:
description: 'Expected OIDC issuer'
required: true
type: string
require-rekor:
description: 'Require Rekor inclusion proof'
required: false
type: boolean
default: true
strict:
description: 'Fail on any verification issue'
required: false
type: boolean
default: true
outputs:
verified:
description: 'Whether verification passed'
value: ${{ jobs.verify.outputs.verified }}
jobs:
verify:
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
outputs:
verified: ${{ steps.verify.outputs.verified }}
steps:
- name: Install StellaOps CLI
uses: stella-ops/setup-cli@v1
with:
version: 'latest'
- name: Verify Attestation
id: verify
env:
STELLAOPS_URL: ${{ inputs.stellaops-url }}
run: |
set +e
RESULT=$(stella attest verify \
--artifact "${{ inputs.artifact-digest }}" \
--certificate-identity "${{ inputs.certificate-identity }}" \
--certificate-oidc-issuer "${{ inputs.certificate-oidc-issuer }}" \
${{ inputs.require-rekor && '--require-rekor' || '' }} \
--output json)
EXIT_CODE=$?
set -e
VERIFIED=$(echo $RESULT | jq -r '.valid')
echo "verified=${VERIFIED}" >> $GITHUB_OUTPUT
if [ "$VERIFIED" != "true" ] && [ "${{ inputs.strict }}" == "true" ]; then
echo "::error::Verification failed"
echo "$RESULT" | jq -r '.issues[]? | "::error::\(.code): \(.message)"'
exit 1
fi
- name: Summary
run: |
if [ "${{ steps.verify.outputs.verified }}" == "true" ]; then
echo "## ✅ Verification Passed" >> $GITHUB_STEP_SUMMARY
else
echo "## ❌ Verification Failed" >> $GITHUB_STEP_SUMMARY
fi
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Artifact | \`${{ inputs.artifact-digest }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Identity | \`${{ inputs.certificate-identity }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Issuer | \`${{ inputs.certificate-oidc-issuer }}\` |" >> $GITHUB_STEP_SUMMARY
```
### GitLab CI Template
```yaml
# deploy/gitlab/examples/.gitlab-ci-stellaops.yml
# Include this in your .gitlab-ci.yml:
# include:
# - project: 'stella-ops/templates'
# file: '.gitlab-ci-stellaops.yml'
.stellaops-sign:
image: stella-ops/cli:latest
id_tokens:
STELLAOPS_OIDC_TOKEN:
aud: sigstore
variables:
STELLAOPS_URL: "https://api.stella-ops.org"
script:
- |
RESULT=$(stella attest sign \
--keyless \
--artifact "${ARTIFACT_DIGEST}" \
--type "${ARTIFACT_TYPE:-image}" \
--output json)
echo "ATTESTATION_DIGEST=$(echo $RESULT | jq -r '.attestationDigest')" >> sign.env
echo "REKOR_UUID=$(echo $RESULT | jq -r '.rekorUuid')" >> sign.env
artifacts:
reports:
dotenv: sign.env
.stellaops-verify:
image: stella-ops/cli:latest
variables:
STELLAOPS_URL: "https://api.stella-ops.org"
REQUIRE_REKOR: "true"
STRICT: "true"
script:
- |
stella attest verify \
--artifact "${ARTIFACT_DIGEST}" \
--certificate-identity "${CERTIFICATE_IDENTITY}" \
--certificate-oidc-issuer "${CERTIFICATE_OIDC_ISSUER}" \
${REQUIRE_REKOR:+--require-rekor} \
|| { [ "${STRICT}" != "true" ] || exit 1; }
# Example usage:
# sign-container:
# extends: .stellaops-sign
# variables:
# ARTIFACT_DIGEST: $CI_REGISTRY_IMAGE@sha256:...
# ARTIFACT_TYPE: image
# only:
# - main
#
# verify-before-deploy:
# extends: .stellaops-verify
# variables:
# ARTIFACT_DIGEST: $CI_REGISTRY_IMAGE@sha256:...
# CERTIFICATE_IDENTITY: "project_path:myorg/myrepo:.*"
# CERTIFICATE_OIDC_ISSUER: "https://gitlab.com"
# only:
# - main
```
### Gitea Workflow (Dogfooding)
```yaml
# .gitea/workflows/release-sign.yml
name: Sign Release Artifacts
on:
release:
types: [published]
jobs:
sign:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup StellaOps CLI
run: |
curl -sL https://get.stella-ops.org/cli | sh
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
- name: Get OIDC Token
id: oidc
run: |
# Gitea OIDC token acquisition
OIDC_TOKEN="${ACTIONS_ID_TOKEN}"
echo "::add-mask::${OIDC_TOKEN}"
echo "token=${OIDC_TOKEN}" >> $GITHUB_OUTPUT
- name: Sign Release Artifacts
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
STELLAOPS_URL: "https://api.stella-ops.internal"
run: |
# Sign each release artifact
for asset in $(gh release view ${{ github.event.release.tag_name }} --json assets -q '.assets[].name'); do
DIGEST=$(sha256sum "$asset" | cut -d' ' -f1)
stella attest sign --keyless --artifact "sha256:$DIGEST" --type release
done
- name: Verify Signatures
env:
STELLAOPS_URL: "https://api.stella-ops.internal"
run: |
# Verify all signatures were created
for asset in $(gh release view ${{ github.event.release.tag_name }} --json assets -q '.assets[].name'); do
DIGEST=$(sha256sum "$asset" | cut -d' ' -f1)
stella attest verify \
--artifact "sha256:$DIGEST" \
--certificate-identity "org/stella-ops.org:ref:refs/tags/${{ github.event.release.tag_name }}" \
--certificate-oidc-issuer "https://git.stella-ops.org"
done
```
### Identity Constraint Documentation
```markdown
# docs/guides/identity-constraints.md
# Identity Constraints for Keyless Verification
## Overview
Keyless signing binds attestations to OIDC identities. During verification,
you must specify which identities are trusted using two key constraints:
1. **Certificate Identity** (`--certificate-identity`): The subject or SAN
2. **Certificate OIDC Issuer** (`--certificate-oidc-issuer`): The token issuer
## Platform-Specific Patterns
### GitHub Actions
| Constraint | Pattern | Example |
|------------|---------|---------|
| Repository | `repo:<owner>/<repo>:.*` | `repo:stella-ops/scanner:.*` |
| Branch | `repo:<owner>/<repo>:ref:refs/heads/<branch>` | `repo:stella-ops/scanner:ref:refs/heads/main` |
| Tag | `repo:<owner>/<repo>:ref:refs/tags/.*` | `repo:stella-ops/scanner:ref:refs/tags/v.*` |
| Environment | `repo:<owner>/<repo>:environment:<env>` | `repo:stella-ops/scanner:environment:production` |
| Workflow | (in SAN) | `.github/workflows/release.yml@refs/heads/main` |
**OIDC Issuer:** `https://token.actions.githubusercontent.com`
### GitLab CI
| Constraint | Pattern | Example |
|------------|---------|---------|
| Project | `project_path:<group>/<project>:.*` | `project_path:stellaops/scanner:.*` |
| Branch | `project_path:<group>/<project>:ref_type:branch:ref:<branch>` | `...:ref_type:branch:ref:main` |
| Tag | `project_path:<group>/<project>:ref_type:tag:ref:.*` | `...:ref_type:tag:ref:v.*` |
| Protected | `project_path:<group>/<project>:ref_protected:true` | N/A |
**OIDC Issuer:** `https://gitlab.com` (or self-hosted URL)
### Best Practices
1. **Always constrain to repository**: Never accept `.*` as the full identity
2. **Prefer branch constraints for production**: Use `ref:refs/heads/main`
3. **Use environment constraints when available**: More granular than branches
4. **Combine with Rekor verification**: `--require-rekor` ensures transparency
5. **Rotate issuer trust carefully**: Changes affect all verification
```
---
## Testing Requirements
### Template Validation Tests
```yaml
# Test: GitHub Actions template syntax
- name: Validate GitHub workflow
run: |
# Use actionlint for validation
actionlint .github/workflows/examples/*.yml
# Test: GitLab CI template syntax
- name: Validate GitLab CI
run: |
# Use gitlab-ci-lint
gitlab-ci-lint deploy/gitlab/examples/.gitlab-ci-stellaops.yml
```
### Integration Tests
| Test | Platform | Description |
|------|----------|-------------|
| `github-sign-verify` | GitHub | Sign in one workflow, verify in another |
| `gitlab-sign-verify` | GitLab | Sign in one job, verify in deployment job |
| `gitea-release` | Gitea | Sign release, verify before publish |
| `cross-platform` | All | Sign in GitHub, verify in GitLab |
### Test Repository Structure
```
tests/cicd-templates/
├── github/
│ ├── .github/workflows/
│ │ ├── test-sign.yml
│ │ ├── test-verify.yml
│ │ └── test-e2e.yml
│ └── README.md
├── gitlab/
│ ├── .gitlab-ci.yml
│ └── README.md
└── gitea/
├── .gitea/workflows/
│ └── test.yml
└── README.md
```
---
## Decisions & Risks
| ID | Decision/Risk | Status | Owner | Notes |
|----|---------------|--------|-------|-------|
| D001 | Reusable workflows over composite actions | DECIDED | — | More flexible, better secrets handling |
| D002 | Support regex for identity patterns | DECIDED | — | Enables flexible matching |
| D003 | Default to strict verification | DECIDED | — | Fail-secure by default |
| R001 | OIDC token format changes | OPEN | — | Monitor platform updates |
| R002 | Rate limiting on public Fulcio | OPEN | — | Document self-hosted option |
| R003 | Workflow permissions confusion | OPEN | — | Clear documentation needed |
---
## Upcoming Checkpoints
| Date | Milestone | Exit Criteria |
|------|-----------|---------------|
| +3 days | GitHub templates complete | 0001-0007 DONE |
| +6 days | GitLab templates complete | 0008-0011 DONE |
| +8 days | Gitea workflows updated | 0012-0014 DONE |
| +12 days | Documentation complete | 0015-0019 DONE |
| +15 days | All tests passing | 0020-0024 DONE, sprint DONE |
---
## Execution Log
| Date | Role | Action | Notes |
|------|------|--------|-------|
| 2025-12-26 | PM | Sprint created | Initial planning from keyless signing advisory |
---
## Related Documents
- **Parent Advisory:** `docs/product-advisories/25-Dec-2025 - Planning Keyless Signing for Verdicts.md`
- **Predecessor Sprints:**
- `SPRINT_20251226_001_SIGNER_fulcio_keyless_client.md`
- `SPRINT_20251226_002_ATTESTOR_bundle_rotation.md`
- `SPRINT_20251226_003_ATTESTOR_offline_verification.md`
- **Signer Architecture:** `docs/modules/signer/architecture.md`
- **Attestor Architecture:** `docs/modules/attestor/architecture.md`
---
*End of Sprint Document*

View File

@@ -0,0 +1,56 @@
# Sprint 20251226 · Risk Budget and Delta Verdict Dashboard
## Topic & Scope
- Build PM-facing Angular 17 dashboard for risk budget visualization and delta verdict display.
- Implement burn-up charts, verdict badges, evidence drill-downs, and exception management UI.
- Deliver side-by-side diff visualization for before/after risk comparison.
- **Working directory:** `src/Web/StellaOps.Web`
## Dependencies & Concurrency
- Depends on: SPRINT_20251226_001_BE (gate API endpoints), SPRINT_20251226_002_BE (budget API), SPRINT_20251226_003_BE (exception API).
- Can run in parallel with: SPRINT_20251226_005_SCANNER (reachability extractors).
- Blocked by: Backend API endpoints must be complete before full integration.
## Documentation Prerequisites
- `docs/modules/web/architecture.md`
- `docs/product-advisories/25-Dec-2025 - Visual Diffs for Explainable Triage.md`
- `docs/product-advisories/26-Dec-2026 - Visualizing the Risk Budget.md`
- Angular 17 component patterns in existing codebase
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | DASH-01 | TODO | None | Frontend Guild | Create `RiskBudgetService` Angular service consuming budget API endpoints |
| 2 | DASH-02 | TODO | None | Frontend Guild | Create `DeltaVerdictService` Angular service consuming gate API endpoints |
| 3 | DASH-03 | TODO | DASH-01 | Frontend Guild | Risk Budget Burn-Up chart component: X=calendar, Y=risk points, budget line + actual line, headroom shading |
| 4 | DASH-04 | TODO | DASH-03 | Frontend Guild | Budget status KPI tiles: Headroom (pts), Unknowns delta (24h), Risk retired (7d), Exceptions expiring |
| 5 | DASH-05 | TODO | DASH-02 | Frontend Guild | Delta Verdict badge component: Routine (green), Review (yellow), Block (red) with tooltip summary |
| 6 | DASH-06 | TODO | DASH-05 | Frontend Guild | "Why" summary bullets component: 3-5 bullet explanation of verdict drivers |
| 7 | DASH-07 | TODO | DASH-06 | Frontend Guild | Evidence buttons: "Show reachability slice", "Show VEX sources", "Show SBOM diff" opening modal panels |
| 8 | DASH-08 | TODO | DASH-07 | Frontend Guild | Reachability slice mini-graph component: visualize entry->sink call paths |
| 9 | DASH-09 | TODO | DASH-07 | Frontend Guild | VEX sources panel: list sources with trust scores, freshness, status |
| 10 | DASH-10 | TODO | DASH-07 | Frontend Guild | SBOM diff panel: side-by-side packages added/removed/changed |
| 11 | DASH-11 | TODO | DASH-02 | Frontend Guild | Side-by-side diff panes: Before vs After risk state with highlighted changes |
| 12 | DASH-12 | TODO | DASH-11 | Frontend Guild | Exception ledger timeline: history of exceptions with status, expiry, owner |
| 13 | DASH-13 | TODO | DASH-12 | Frontend Guild | "Create Exception" modal: reason, evidence refs, TTL, scope selection |
| 14 | DASH-14 | TODO | DASH-13 | Frontend Guild | "Approve Exception" action in exception list for users with approver role |
| 15 | DASH-15 | TODO | DASH-14 | Frontend Guild | Responsive design: dashboard usable on tablet/desktop |
| 16 | DASH-16 | TODO | DASH-15 | Frontend Guild | Unit tests for all new components |
| 17 | DASH-17 | TODO | DASH-16 | Frontend Guild | E2E tests: budget view, verdict view, exception workflow |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from product advisory analysis; implements PM-facing UI from visual diffs and risk budget advisories. | Project Mgmt |
## Decisions & Risks
- Decision needed: Chart library for burn-up visualization. Recommend: ngx-charts or Chart.js (already in use?).
- Decision needed: Mini-graph library for reachability slice. Recommend: D3.js or Cytoscape.js.
- Decision needed: Mobile support scope. Recommend: tablet minimum, phone deferred.
- Risk: Large diff graphs may cause performance issues. Mitigation: "changed neighborhood only" default view, progressive loading.
- Risk: Evidence panel latency for large SBOMs. Mitigation: paginated loading, summary-first approach.
## Next Checkpoints
- 2026-01-06 | DASH-06 complete | Core verdict display functional |
- 2026-01-10 | DASH-11 complete | Diff visualization working |
- 2026-01-15 | DASH-17 complete | Full dashboard with tests |

View File

@@ -0,0 +1,64 @@
# Sprint 20251226 · Language Reachability Call Graph Extractors
## Topic & Scope
- Complete language-specific call graph extractors for reachability drift analysis.
- Implement extractors for Java (ASM), Node.js (Babel), Python (AST), and Go (SSA completion).
- Integrate extractors into scanner registry with determinism guarantees.
- **Working directory:** `src/Scanner/StellaOps.Scanner.Reachability`, `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.*`
## Dependencies & Concurrency
- Depends on: Existing .NET Roslyn extractor (complete), `ReachabilityDriftResult` model (complete).
- Depends on: SmartDiff predicate schema (complete), SinkRegistry (complete).
- Can run in parallel with: All other sprints (independent language work).
## Documentation Prerequisites
- `docs/modules/scanner/AGENTS.md`
- `docs/modules/scanner/reachability-drift.md`
- `docs/product-advisories/archived/2025-12-21-moat-gap-closure/14-Dec-2025 - Smart-Diff Technical Reference.md`
- `docs/product-advisories/25-Dec-2025 - Evolving Evidence Models for Reachability.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | REACH-JAVA-01 | TODO | None | Scanner Guild | Create `StellaOps.Scanner.Analyzers.Lang.Java.Reachability` project structure |
| 2 | REACH-JAVA-02 | TODO | REACH-JAVA-01 | Scanner Guild | Implement ASM-based bytecode call graph extraction from .class/.jar files |
| 3 | REACH-JAVA-03 | TODO | REACH-JAVA-02 | Scanner Guild | Map ASM method refs to purl + symbol for CVE correlation |
| 4 | REACH-JAVA-04 | TODO | REACH-JAVA-03 | Scanner Guild | Sink detection: identify calls to known vulnerable methods (SQL, deserialization, exec) |
| 5 | REACH-JAVA-05 | TODO | REACH-JAVA-04 | Scanner Guild | Integration tests with sample Maven/Gradle projects |
| 6 | REACH-NODE-01 | TODO | None | Scanner Guild | Create `StellaOps.Scanner.Analyzers.Lang.Node.Reachability` project structure |
| 7 | REACH-NODE-02 | TODO | REACH-NODE-01 | Scanner Guild | Implement Babel AST parser for JavaScript/TypeScript call extraction |
| 8 | REACH-NODE-03 | TODO | REACH-NODE-02 | Scanner Guild | Handle CommonJS require() and ESM import resolution |
| 9 | REACH-NODE-04 | TODO | REACH-NODE-03 | Scanner Guild | Map npm package refs to purl for CVE correlation |
| 10 | REACH-NODE-05 | TODO | REACH-NODE-04 | Scanner Guild | Sink detection: eval, child_process, fs operations, SQL templates |
| 11 | REACH-NODE-06 | TODO | REACH-NODE-05 | Scanner Guild | Integration tests with sample Node.js projects (Express, NestJS) |
| 12 | REACH-PY-01 | TODO | None | Scanner Guild | Create `StellaOps.Scanner.Analyzers.Lang.Python.Reachability` project structure |
| 13 | REACH-PY-02 | TODO | REACH-PY-01 | Scanner Guild | Implement Python AST call graph extraction using ast module |
| 14 | REACH-PY-03 | TODO | REACH-PY-02 | Scanner Guild | Handle import resolution for installed packages (pip/poetry) |
| 15 | REACH-PY-04 | TODO | REACH-PY-03 | Scanner Guild | Sink detection: subprocess, pickle, eval, SQL string formatting |
| 16 | REACH-PY-05 | TODO | REACH-PY-04 | Scanner Guild | Integration tests with sample Python projects (Flask, Django) |
| 17 | REACH-GO-01 | TODO | None | Scanner Guild | Complete Go SSA extractor skeleton in existing project |
| 18 | REACH-GO-02 | TODO | REACH-GO-01 | Scanner Guild | Implement golang.org/x/tools/go/callgraph/cha integration |
| 19 | REACH-GO-03 | TODO | REACH-GO-02 | Scanner Guild | Map Go packages to purl for CVE correlation |
| 20 | REACH-GO-04 | TODO | REACH-GO-03 | Scanner Guild | Sink detection: os/exec, net/http client, database/sql |
| 21 | REACH-GO-05 | TODO | REACH-GO-04 | Scanner Guild | Integration tests with sample Go projects |
| 22 | REACH-REG-01 | TODO | REACH-JAVA-05, REACH-NODE-06, REACH-PY-05, REACH-GO-05 | Scanner Guild | Register all extractors in `ReachabilityExtractorRegistry` |
| 23 | REACH-REG-02 | TODO | REACH-REG-01 | Scanner Guild | Determinism tests: same input -> same call graph hash across runs |
| 24 | REACH-REG-03 | TODO | REACH-REG-02 | Scanner Guild | Documentation: update scanner AGENTS.md with extractor usage |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from product advisory analysis; addresses reachability extractor gaps for diff-aware gates. | Project Mgmt |
## Decisions & Risks
- Decision needed: ASM version for Java extractor (9.x recommended for Java 21 support).
- Decision needed: Babel parser plugins for TypeScript/JSX support.
- Decision needed: Python version support (3.8+ recommended).
- Risk: Dynamic dispatch in Java/Python limits static call graph accuracy. Mitigation: conservative over-approximation, flag unknowns.
- Risk: Node.js dynamic requires are hard to resolve. Mitigation: mark as unknown, runtime evidence can supplement.
- Risk: Large codebases may cause memory issues. Mitigation: streaming/chunked processing, configurable depth limits.
## Next Checkpoints
- 2026-01-10 | REACH-JAVA-05 complete | Java extractor functional |
- 2026-01-15 | REACH-NODE-06 complete | Node.js extractor functional |
- 2026-01-20 | REACH-REG-02 complete | All extractors registered and determinism verified |

View File

@@ -0,0 +1,66 @@
# Sprint 20251226 · Product Advisory Consolidation
## Topic & Scope
- Consolidate 8 overlapping product advisories into a single master document for diff-aware release gates.
- Archive original advisories with cross-reference preservation.
- Create executive summary for stakeholder communication.
- **Working directory:** `docs/product-advisories/`
## Dependencies & Concurrency
- No technical dependencies; documentation-only sprint.
- Can run immediately and in parallel with all other sprints.
- Should complete first to provide unified reference for implementation sprints.
## Documentation Prerequisites
- All source advisories (listed in Delivery Tracker)
- `CLAUDE.md` (documentation conventions)
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | DOCS-01 | TODO | None | Project Mgmt | Create consolidated master document: `CONSOLIDATED - Diff-Aware Release Gates and Risk Budgets.md` |
| 2 | DOCS-02 | TODO | DOCS-01 | Project Mgmt | Merge content from: `25-Dec-2025 - Implementing Diff-Aware Release Gates.md` |
| 3 | DOCS-03 | TODO | DOCS-01 | Project Mgmt | Merge content from: `26-Dec-2026 - Diff-Aware Releases and Auditable Exceptions.md` |
| 4 | DOCS-04 | TODO | DOCS-01 | Project Mgmt | Merge content from: `26-Dec-2026 - Smart-Diff as a Core Evidence Primitive.md` |
| 5 | DOCS-05 | TODO | DOCS-01 | Project Mgmt | Merge content from: `25-Dec-2025 - Visual Diffs for Explainable Triage.md` |
| 6 | DOCS-06 | TODO | DOCS-01 | Project Mgmt | Merge content from: `25-Dec-2025 - Building a Deterministic Verdict Engine.md` |
| 7 | DOCS-07 | TODO | DOCS-01 | Project Mgmt | Merge content from: `26-Dec-2026 - Visualizing the Risk Budget.md` |
| 8 | DOCS-08 | TODO | DOCS-01 | Project Mgmt | Merge content from: `26-Dec-2026 - Weighted Confidence for VEX Sources.md` |
| 9 | DOCS-09 | TODO | DOCS-01 | Project Mgmt | Reference archived technical spec: `archived/2025-12-21-moat-gap-closure/14-Dec-2025 - Smart-Diff Technical Reference.md` |
| 10 | DOCS-10 | TODO | DOCS-01 | Project Mgmt | Reference archived moat document: `archived/2025-12-21-moat-phase2/20-Dec-2025 - Moat Explanation - Risk Budgets and Diff-Aware Release Gates.md` |
| 11 | DOCS-11 | TODO | DOCS-08 | Project Mgmt | Create archive directory: `archived/2025-12-26-diff-aware-gates/` |
| 12 | DOCS-12 | TODO | DOCS-11 | Project Mgmt | Move original advisories to archive directory |
| 13 | DOCS-13 | TODO | DOCS-12 | Project Mgmt | Update cross-references in `docs/modules/policy/architecture.md` |
| 14 | DOCS-14 | TODO | DOCS-12 | Project Mgmt | Update cross-references in `docs/modules/scanner/AGENTS.md` |
| 15 | DOCS-15 | TODO | DOCS-13 | Project Mgmt | Create executive summary (1-page) for stakeholder communication |
| 16 | DOCS-16 | TODO | DOCS-15 | Project Mgmt | Review consolidated document for consistency and completeness |
## Consolidated Document Structure
The master document should include these sections:
1. **Executive Summary** - 1-page overview for PMs/stakeholders
2. **Core Concepts** - SBOM, VEX, Reachability, Semantic Delta definitions
3. **Risk Budget Model** - Service tiers, RP scoring, window management, thresholds
4. **Release Gate Levels** - G0-G4 definitions, gate selection logic
5. **Delta Verdict Engine** - Computation, scoring, determinism, replay
6. **Smart-Diff Algorithm** - Material change detection rules, suppression rules
7. **Exception Workflow** - Entity model, approval flow, audit requirements
8. **VEX Trust Scoring** - Confidence/freshness lattice, source weights
9. **UI/UX Patterns** - PM dashboard, visual diffs, evidence panels
10. **CI/CD Integration** - Pipeline recipe, CLI commands, exit codes
11. **Implementation Status** - What exists, what's needed, sprint references
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from product advisory gap analysis; identified 8 overlapping advisories requiring consolidation. | Project Mgmt |
## Decisions & Risks
- Decision: Preserve all unique content from each advisory vs. deduplicate aggressively. Recommend: deduplicate, keep most detailed version of each concept.
- Decision: Archive naming convention. Recommend: date-prefixed directory with original filenames.
- Risk: Broken cross-references after archival. Mitigation: grep for advisory filenames, update all references.
- Risk: Loss of advisory authorship/history. Mitigation: note original sources in consolidated doc header.
## Next Checkpoints
- 2025-12-27 | DOCS-01 complete | Master document structure created |
- 2025-12-28 | DOCS-10 complete | All content merged |
- 2025-12-29 | DOCS-16 complete | Consolidation reviewed and finalized |

View File

@@ -0,0 +1,85 @@
# Sprint 20251226 · Determinism Gap Closure
## Topic & Scope
- Close remaining gaps in deterministic verdict engine infrastructure.
- Implement unified feed snapshot coordination, keyless signing, and cross-platform testing.
- Formalize determinism manifest schema for certification.
- Enforce canonical JSON (RFC 8785 JCS + NFC) at resolver boundaries.
- **Working directory:** `src/Policy/`, `src/Concelier/`, `src/Attestor/`, `src/Signer/`, `src/__Libraries/`
## Dependencies & Concurrency
- Depends on: Existing determinism infrastructure (85% complete).
- No blocking dependencies; can start immediately.
- Can run in parallel with: SPRINT_20251226_008_DOCS (documentation consolidation).
## Documentation Prerequisites
- `docs/modules/policy/design/deterministic-evaluator.md`
- `docs/modules/policy/design/policy-determinism-tests.md`
- `docs/modules/scanner/deterministic-execution.md`
- `docs/product-advisories/25-Dec-2025 - Planning Keyless Signing for Verdicts.md`
- `docs/product-advisories/25-Dec-2025 - Enforcing Canonical JSON for Stable Verdicts.md` (SUPERSEDED - tasks merged here)
## Context: What Already Exists
The following determinism features are **already implemented**:
| Component | Location | Status |
|-----------|----------|--------|
| Canonical JSON (JCS) | `StellaOps.Canonical.Json` | COMPLETE |
| Content-Addressed IDs | `Attestor.ProofChain/Identifiers/` | COMPLETE |
| Determinism Guards | `Policy.Engine/DeterminismGuard/` | COMPLETE |
| Replay Manifest | `StellaOps.Replay.Core` | COMPLETE |
| DSSE Signing | `Signer/`, `Attestor/` | COMPLETE |
| Delta Verdict | `Policy/Deltas/DeltaVerdict.cs` | COMPLETE |
| Merkle Trees | `ProofChain/Merkle/` | COMPLETE |
| Golden Tests | `Integration.Determinism/` | PARTIAL |
This sprint closes the **remaining 15% gaps**.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | DET-GAP-01 | TODO | None | Concelier Guild + Excititor Guild | Create `IFeedSnapshotCoordinator` interface for atomic multi-source snapshots |
| 2 | DET-GAP-02 | TODO | DET-GAP-01 | Concelier Guild | Implement `FeedSnapshotCoordinatorService` coordinating Advisory + VEX + Policy snapshots |
| 3 | DET-GAP-03 | TODO | DET-GAP-02 | Concelier Guild | Add `POST /api/v1/feeds/snapshot` endpoint returning atomic bundle with composite digest |
| 4 | DET-GAP-04 | TODO | DET-GAP-03 | Concelier Guild | CLI command `stella feeds snapshot --output bundle.tar.gz` for offline use |
| 5 | DET-GAP-05 | TODO | None | Signer Guild | Integrate Sigstore Fulcio for keyless signing (OIDC token -> ephemeral cert) |
| 6 | DET-GAP-06 | TODO | DET-GAP-05 | Signer Guild | Add `SigningMode.Keyless` option to `DsseSigner` configuration |
| 7 | DET-GAP-07 | TODO | DET-GAP-05 | Signer Guild | Implement Rekor transparency log integration for keyless signatures |
| 8 | DET-GAP-08 | TODO | DET-GAP-07 | Signer Guild | CLI command `stella sign --keyless --rekor` for CI pipelines |
| 9 | DET-GAP-09 | TODO | None | Policy Guild | Create formal JSON Schema: `determinism-manifest.schema.json` |
| 10 | DET-GAP-10 | TODO | DET-GAP-09 | Policy Guild | Validator for determinism manifest compliance |
| 11 | DET-GAP-11 | TODO | None | Testing Guild | Add Windows determinism test runner to CI matrix |
| 12 | DET-GAP-12 | TODO | DET-GAP-11 | Testing Guild | Add macOS determinism test runner to CI matrix |
| 13 | DET-GAP-13 | TODO | DET-GAP-12 | Testing Guild | Cross-platform hash comparison report generation |
| 14 | DET-GAP-14 | TODO | None | Bench Guild | Property-based determinism tests (input permutations -> same hash) |
| 15 | DET-GAP-15 | TODO | DET-GAP-14 | Bench Guild | Floating-point stability validation (decimal vs float edge cases) |
| 16 | DET-GAP-16 | TODO | All above | Policy Guild | Integration test: full verdict pipeline with all gaps closed |
| 17 | DET-GAP-17 | TODO | None | Resolver Guild | Add optional NFC normalization pass to `Rfc8785JsonCanonicalizer` for Unicode string stability |
| 18 | DET-GAP-18 | TODO | None | Tooling Guild | Create Roslyn analyzer `STELLA0100` to enforce canonicalization at resolver boundary |
| 19 | DET-GAP-19 | TODO | None | Attestor Guild | Add pre-canonical hash debug logging for audit trails (log both raw and canonical SHA-256) |
| 20 | DET-GAP-20 | TODO | None | Docs Guild | Document resolver boundary canonicalization pattern in `CONTRIBUTING.md` |
| 21 | DET-GAP-21 | TODO | None | Metrics Guild | Add proof generation rate metric (proofs/second by type) |
| 22 | DET-GAP-22 | TODO | DET-GAP-21 | Metrics Guild | Add median proof size metric (KB by type: witness, subgraph, spine) |
| 23 | DET-GAP-23 | TODO | DET-GAP-21 | Metrics Guild | Add replay success rate metric (successful replays / total attempts) |
| 24 | DET-GAP-24 | TODO | DET-GAP-21 | Metrics Guild | Add proof dedup ratio metric (unique proofs / total generated) |
| 25 | DET-GAP-25 | TODO | None | Policy Guild | Add "unknowns" burn-down tracking (count reduction per scan) |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from advisory analysis; identified remaining 15% gaps in determinism infrastructure. | Project Mgmt |
| 2025-12-26 | Added DET-GAP-17 through DET-GAP-20 from "Enforcing Canonical JSON for Stable Verdicts" advisory analysis. Advisory marked SUPERSEDED. | Project Mgmt |
| 2025-12-26 | Added DET-GAP-21 through DET-GAP-25 from "Reachability as Cryptographic Proof" advisory (metrics, unknowns tracking). Advisory marked SUPERSEDED. | Project Mgmt |
## Decisions & Risks
- Decision needed: Sigstore instance (public vs self-hosted). Recommend: public for CI, self-hosted option for air-gap.
- Decision needed: Feed snapshot retention period. Recommend: 90 days default, configurable.
- Decision needed: Cross-platform CI runners (GitHub Actions vs self-hosted). Recommend: GitHub Actions for broad coverage.
- Risk: Keyless signing requires stable OIDC provider. Mitigation: fallback to key-based signing if OIDC unavailable.
- Risk: Cross-platform float differences. Mitigation: use decimal for all numeric comparisons (already enforced).
## Next Checkpoints
- 2025-12-30 | DET-GAP-04 complete | Feed snapshot coordinator functional |
- 2026-01-03 | DET-GAP-08 complete | Keyless signing working in CI |
- 2026-01-06 | DET-GAP-16 complete | Full integration verified |

View File

@@ -0,0 +1,113 @@
# Sprint 20251226 · Determinism Advisory and Documentation Consolidation
## Topic & Scope
- Consolidate 6 overlapping product advisories into a single determinism architecture specification.
- Create authoritative documentation for all determinism guarantees and digest algorithms.
- Archive original advisories with cross-reference preservation.
- **Working directory:** `docs/product-advisories/`, `docs/technical/`
## Dependencies & Concurrency
- No technical dependencies; documentation-only sprint.
- Can run in parallel with: SPRINT_20251226_007_BE (determinism gap closure).
- Should reference implementation status from gap closure sprint.
## Documentation Prerequisites
- All source advisories (listed in Delivery Tracker)
- Existing determinism docs:
- `docs/modules/policy/design/deterministic-evaluator.md`
- `docs/modules/policy/design/policy-determinism-tests.md`
- `docs/modules/scanner/deterministic-execution.md`
## Advisories to Consolidate
| Advisory | Primary Concepts | Keep Verbatim |
|----------|------------------|---------------|
| `25-Dec-2025 - Building a Deterministic Verdict Engine.md` | Manifest, verdict format, replay APIs | Engine architecture, rollout plan |
| `25-Dec-2025 - Enforcing Canonical JSON for Stable Verdicts.md` | JCS, UTF-8, NFC, .NET snippet | Rule statement, code snippet |
| `25-Dec-2025 - Planning Keyless Signing for Verdicts.md` | Sigstore, Fulcio, Rekor, bundles | Rollout checklist |
| `26-Dec-2026 - Smart-Diff as a Core Evidence Primitive.md` | Delta verdict, evidence model | Schema sketch |
| `26-Dec-2026 - Reachability as Cryptographic Proof.md` | Proof-carrying reachability | Proof example, UI concept |
| `25-Dec-2025 - Hybrid Binary and Call-Graph Analysis.md` | Binary+static+runtime analysis | Keep as separate (different focus) |
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | DOC-DET-01 | TODO | None | Project Mgmt | Create master document structure: `CONSOLIDATED - Deterministic Evidence and Verdict Architecture.md` |
| 2 | DOC-DET-02 | TODO | DOC-DET-01 | Project Mgmt | Merge "Building a Deterministic Verdict Engine" as core engine section |
| 3 | DOC-DET-03 | TODO | DOC-DET-01 | Project Mgmt | Merge "Enforcing Canonical JSON" as serialization section |
| 4 | DOC-DET-04 | TODO | DOC-DET-01 | Project Mgmt | Merge "Planning Keyless Signing" as signing section |
| 5 | DOC-DET-05 | TODO | DOC-DET-01 | Project Mgmt | Merge "Smart-Diff as Evidence Primitive" as delta section |
| 6 | DOC-DET-06 | TODO | DOC-DET-01 | Project Mgmt | Merge "Reachability as Cryptographic Proof" as reachability section |
| 7 | DOC-DET-07 | TODO | DOC-DET-06 | Project Mgmt | Add implementation status matrix (what exists vs gaps) |
| 8 | DOC-DET-08 | TODO | DOC-DET-07 | Project Mgmt | Create archive directory: `archived/2025-12-26-determinism-advisories/` |
| 9 | DOC-DET-09 | TODO | DOC-DET-08 | Project Mgmt | Move 5 original advisories to archive |
| 10 | DOC-DET-10 | TODO | None | Policy Guild | Create `docs/technical/architecture/determinism-specification.md` |
| 11 | DOC-DET-11 | TODO | DOC-DET-10 | Policy Guild | Document all digest algorithms: VerdictId, EvidenceId, GraphRevisionId, etc. |
| 12 | DOC-DET-12 | TODO | DOC-DET-10 | Policy Guild | Document canonicalization version strategy and migration path |
| 13 | DOC-DET-13 | TODO | DOC-DET-11 | Policy Guild | Add troubleshooting guide: "Why are my verdicts different?" |
| 14 | DOC-DET-14 | TODO | DOC-DET-09 | Project Mgmt | Update cross-references in `docs/modules/policy/architecture.md` |
| 15 | DOC-DET-15 | TODO | DOC-DET-09 | Project Mgmt | Update cross-references in `docs/modules/scanner/AGENTS.md` |
| 16 | DOC-DET-16 | TODO | All above | Project Mgmt | Final review of consolidated document |
## Consolidated Document Structure
```markdown
# Deterministic Evidence and Verdict Architecture
## 1. Executive Summary
## 2. Why Determinism Matters
- Reproducibility for auditors
- Content-addressed caching
- Cross-agent consensus
## 3. Core Principles
- No wall-clock, no RNG, no network during evaluation
- Content-addressing all inputs
- Pure evaluation functions
## 4. Canonical Serialization (from "Enforcing Canonical JSON")
- UTF-8 + NFC + JCS (RFC 8785)
- .NET implementation reference
## 5. Data Artifacts (from "Building Deterministic Verdict Engine")
- Scan Manifest schema
- Verdict schema
- Delta Verdict schema
## 6. Signing & Attestation (from "Planning Keyless Signing")
- DSSE envelopes
- Keyless via Sigstore/Fulcio
- Rekor transparency
- Monthly bundle rotation
## 7. Reachability Proofs (from "Reachability as Cryptographic Proof")
- Proof structure
- Graph snippets
- Operating modes (strict/lenient)
## 8. Delta Verdicts (from "Smart-Diff as Evidence Primitive")
- Evidence model
- Merge semantics
- OCI attachment
## 9. Implementation Status
- What's complete (85%)
- What's in progress
- What's planned
## 10. Testing Strategy
- Golden tests
- Chaos tests
- Cross-platform validation
## 11. References
- Code locations
- Related sprints
```
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from advisory analysis; identified 6 overlapping advisories for consolidation. | Project Mgmt |
## Decisions & Risks
- Decision: Keep "Hybrid Binary and Call-Graph Analysis" separate (different focus). Recommend: Yes, it's about analysis methods not determinism.
- Decision: Archive location. Recommend: `archived/2025-12-26-determinism-advisories/` with README explaining consolidation.
- Risk: Broken cross-references after archival. Mitigation: grep all docs for advisory filenames before archiving.
- Risk: Loss of nuance from individual advisories. Mitigation: preserve verbatim sections where noted.
## Next Checkpoints
- 2025-12-27 | DOC-DET-06 complete | All content merged into master document |
- 2025-12-28 | DOC-DET-12 complete | Technical specification created |
- 2025-12-29 | DOC-DET-16 complete | Final review and publication |

View File

@@ -0,0 +1,98 @@
# Sprint 20251226 · Function-Level Proof Generation (FuncProof)
## Topic & Scope
- Implement function-level proof objects for binary-level reachability evidence.
- Generate symbol digests, function-range hashes, and entry→sink trace serialization.
- Publish FuncProof as DSSE-signed OCI referrer artifacts linked from SBOM.
- **Working directory:** `src/Scanner/`, `src/BinaryIndex/`, `src/Attestor/`
## Dependencies & Concurrency
- Depends on: `BinaryIdentity` (complete), `NativeReachabilityGraphBuilder` (complete).
- No blocking dependencies; can start immediately.
- Enables: SPRINT_20251226_011_BE (auto-VEX needs funcproof for symbol correlation).
## Documentation Prerequisites
- `docs/modules/scanner/design/native-reachability-plan.md`
- `docs/modules/scanner/os-analyzers-evidence.md`
- `docs/product-advisories/25-Dec-2025 - Evolving Evidence Models for Reachability.md`
- `docs/product-advisories/26-Dec-2026 - Mapping a Binary Intelligence Graph.md`
## Context: What Already Exists
| Component | Location | Status |
|-----------|----------|--------|
| BinaryIdentity (Build-ID, sections) | `BinaryIndex/BinaryIdentity.cs` | COMPLETE |
| ELF/PE/Mach-O parsers | `Scanner.Analyzers.Native/` | COMPLETE |
| Disassemblers (ARM64, x86) | `Scanner.CallGraph/Extraction/Binary/` | COMPLETE |
| DWARF debug reader | `Scanner.CallGraph/Extraction/Binary/DwarfDebugReader.cs` | COMPLETE |
| Call graph snapshot | `Scanner.CallGraph/CallGraphSnapshot.cs` | COMPLETE |
| DSSE envelope support | `Attestor/` | COMPLETE |
This sprint adds **function-level granularity** on top of existing binary infrastructure.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | FUNC-01 | TODO | None | Scanner Guild | Define `FuncProof` JSON model: buildId, sections, functions[], traces[] |
| 2 | FUNC-02 | TODO | FUNC-01 | Scanner Guild | Create `FuncProofDocument` PostgreSQL entity with indexes on build_id |
| 3 | FUNC-03 | TODO | FUNC-01 | Scanner Guild | Implement function-range boundary detection using DWARF/symbol table |
| 4 | FUNC-04 | TODO | FUNC-03 | Scanner Guild | Fallback: heuristic prolog/epilog detection for stripped binaries |
| 5 | FUNC-05 | TODO | FUNC-03 | Scanner Guild | Symbol digest computation: BLAKE3(symbol_name + offset_range) |
| 6 | FUNC-06 | TODO | FUNC-05 | Scanner Guild | Populate `symbol_digest` field in `FuncNodeDocument` |
| 7 | FUNC-07 | TODO | FUNC-03 | Scanner Guild | Function-range hashing: rolling BLAKE3 over `.text` subranges per function |
| 8 | FUNC-08 | TODO | FUNC-07 | Scanner Guild | Section hash integration: compute `.text` + `.rodata` digests per binary |
| 9 | FUNC-09 | TODO | FUNC-08 | Scanner Guild | Store section hashes in `BinaryIdentity` model |
| 10 | FUNC-10 | TODO | None | Scanner Guild | Entry→sink trace serialization: compact spans with edge list hash |
| 11 | FUNC-11 | TODO | FUNC-10 | Scanner Guild | Serialize traces as `trace_hashes[]` in FuncProof |
| 12 | FUNC-12 | TODO | FUNC-01 | Attestor Guild | DSSE envelope generation for FuncProof (`application/vnd.stellaops.funcproof+json`) |
| 13 | FUNC-13 | TODO | FUNC-12 | Attestor Guild | Rekor transparency log integration for FuncProof |
| 14 | FUNC-14 | TODO | FUNC-12 | Scanner Guild | OCI referrer publishing: push FuncProof alongside image |
| 15 | FUNC-15 | TODO | FUNC-14 | Scanner Guild | SBOM `evidence` link: add CycloneDX `components.evidence` reference to funcproof |
| 16 | FUNC-16 | TODO | FUNC-15 | Scanner Guild | CLI command: `stella scan --funcproof` to generate proofs |
| 17 | FUNC-17 | TODO | FUNC-12 | Scanner Guild | Auditor replay: `stella verify --funcproof <image>` downloads and verifies hashes |
| 18 | FUNC-18 | TODO | All above | Scanner Guild | Integration tests: full FuncProof pipeline with sample ELF binaries |
## FuncProof Schema (Target)
```json
{
"buildId": "ab12cd34...",
"sections": {
".text": "blake3:...",
".rodata": "blake3:..."
},
"functions": [
{
"sym": "libfoo::parse_hdr",
"start": "0x401120",
"end": "0x4013af",
"hash": "blake3:..."
}
],
"traces": [
"blake3(edge-list-1)",
"blake3(edge-list-2)"
],
"meta": {
"compiler": "clang-18",
"flags": "-O2 -fno-plt"
}
}
```
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from advisory analysis; implements FuncProof from "Evolving Evidence Models for Reachability". | Project Mgmt |
## Decisions & Risks
- Decision needed: Hash algorithm (BLAKE3 vs SHA256). Recommend: BLAKE3 for speed.
- Decision needed: Stripped binary handling (heuristics vs fail). Recommend: heuristics with `stripped=true` flag.
- Decision needed: Trace depth limit. Recommend: 10 hops max for compressed paths.
- Risk: Function boundary detection may be imprecise for heavily optimized code. Mitigation: mark confidence per function.
- Risk: Large binaries may produce huge FuncProof files. Mitigation: compress, limit to security-relevant functions.
## Next Checkpoints
- 2025-12-30 | FUNC-06 complete | Symbol digests populated in reachability models |
- 2026-01-03 | FUNC-12 complete | DSSE signing working |
- 2026-01-06 | FUNC-18 complete | Full integration tested |

View File

@@ -0,0 +1,354 @@
# SPRINT_20251226_010_FE_visual_diff_enhancements
> **Status:** TODO
> **Priority:** P2
> **Module:** Frontend (Web)
> **Created:** 2025-12-26
> **Advisory:** [`25-Dec-2025 - Visual Diffs for Explainable Triage.md`](../product-advisories/25-Dec-2025%20-%20Visual%20Diffs%20for%20Explainable%20Triage.md)
---
## Topic & Scope
Enhance the existing Smart-Diff UI with visual graph diff capabilities, plain language explanations, and improved interactivity. This sprint addresses the remaining ~20-25% of the Visual Diffs advisory not covered by existing implementation.
**Existing Infrastructure (already complete):**
- `TriageWorkspaceComponent` - Full triage workspace with tabs, gated buckets, VEX trust
- `ProofTreeComponent` - Merkle tree visualization, evidence chunks
- `smart-diff-ui-architecture.md` - Three-pane layout, delta summary, role-based views
- `DeltaVerdict` backend - Full delta computation, signing, OCI attachment
**Working directory:** `src/Web/StellaOps.Web/src/app/features/`
---
## Documentation Prerequisites
- `docs/modules/web/smart-diff-ui-architecture.md`
- `docs/modules/web/README.md`
- `src/Web/StellaOps.Web/src/app/features/triage/triage-workspace.component.ts`
- `src/Web/StellaOps.Web/src/app/shared/components/proof-tree.component.ts`
---
## Delivery Tracker
| # | Task ID | Status | Depends | Owner | Description |
|---|---------|--------|---------|-------|-------------|
| 1 | VD-ENH-01 | TODO | None | FE Guild | Create `GraphDiffComponent` with node/edge change highlighting |
| 2 | VD-ENH-02 | TODO | VD-ENH-01 | FE Guild | Implement before/after split view for graph comparison |
| 3 | VD-ENH-03 | TODO | VD-ENH-01 | FE Guild | Add interactive graph navigation (hover highlights connected paths) |
| 4 | VD-ENH-04 | TODO | VD-ENH-01 | FE Guild | Add graph zoom/pan controls with minimap |
| 5 | VD-ENH-05 | TODO | None | FE Guild | Create `PlainLanguageToggle` component for "Explain like I'm new" mode |
| 6 | VD-ENH-06 | TODO | VD-ENH-05 | FE Guild | Add plain language explanations for delta categories |
| 7 | VD-ENH-07 | TODO | VD-ENH-05 | FE Guild | Add plain language tooltips for technical terms |
| 8 | VD-ENH-08 | TODO | VD-ENH-01 | FE Guild | Add graph diff export (SVG/PNG) for audit reports |
| 9 | VD-ENH-09 | TODO | None | FE Guild | Merge competitive insights from "Triage UI Lessons" advisory |
| 10 | VD-ENH-10 | TODO | All | FE Guild | Add Storybook stories for new components |
| 11 | VD-ENH-11 | TODO | All | FE Guild | Add unit tests for graph diff logic |
| 12 | VD-ENH-12 | TODO | All | FE Guild | Add E2E tests for visual diff workflow |
**Total Tasks:** 12
---
## Task Details
### VD-ENH-01: GraphDiffComponent
Create a new Angular component for visualizing reachability/dependency graph diffs with change highlighting.
**Requirements:**
- Display nodes (components/functions) and edges (call paths)
- Highlight added nodes/edges in green
- Highlight removed nodes/edges in red
- Highlight changed nodes in amber
- Support keyboard navigation (arrow keys, Enter to expand)
- WCAG 2.1 AA accessible (color-blind safe indicators)
**Component API:**
```typescript
@Component({
selector: 'stellaops-graph-diff',
standalone: true,
})
export class GraphDiffComponent {
baseGraph = input<ReachabilityGraph | null>(null);
headGraph = input<ReachabilityGraph | null>(null);
highlightedNode = input<string | null>(null);
nodeSelected = output<GraphNode>();
edgeSelected = output<GraphEdge>();
}
```
**Location:** `src/Web/StellaOps.Web/src/app/shared/components/graph-diff/`
---
### VD-ENH-02: Before/After Split View
Implement side-by-side graph comparison mode.
**Requirements:**
- Split view with synchronized scrolling/zooming
- "Before" (baseline) graph on left, "After" (head) on right
- Linked node selection (selecting in one highlights in both)
- Toggle between split view and unified diff view
- Responsive layout (stack vertically on mobile)
**Integration:**
- Add to `CompareViewComponent` as view mode option
- Persist view preference in localStorage
---
### VD-ENH-03: Interactive Graph Navigation
Add hover and click interactions for graph exploration.
**Requirements:**
- Hover on node: highlight all connected edges and ancestor/descendant nodes
- Click on node: expand detail panel with node metadata
- Double-click: zoom to fit node and immediate neighbors
- Path highlighting: show full call path from entry point to vulnerable function
- Breadcrumb trail for navigation history
---
### VD-ENH-04: Graph Zoom/Pan Controls
Add navigation controls for large graphs.
**Requirements:**
- Zoom in/out buttons (+/-)
- Fit-to-view button
- Minimap for large graphs (>50 nodes)
- Mouse wheel zoom with Ctrl modifier
- Touch gesture support (pinch zoom)
---
### VD-ENH-05: PlainLanguageToggle Component
Create toggle for switching between technical and plain language modes.
**Requirements:**
- Toggle in header/toolbar area
- Persist preference per user
- Animate transition between modes
- Keyboard accessible (Alt+P shortcut)
**Component API:**
```typescript
@Component({
selector: 'stellaops-plain-language-toggle',
standalone: true,
})
export class PlainLanguageToggleComponent {
enabled = model<boolean>(false);
toggled = output<boolean>();
}
```
---
### VD-ENH-06: Plain Language Explanations
Add human-readable explanations for delta categories.
**Technical → Plain Language Mapping:**
| Technical | Plain Language |
|-----------|----------------|
| "Component added with reachable CVE" | "A new library was added that has a known security issue that your code actually uses" |
| "VEX status: not_affected" | "The vendor confirmed this issue doesn't apply to your version" |
| "Reachability: unreachable" | "This vulnerability exists in the code, but your app never actually runs that code" |
| "Risk score delta: +15" | "This release is riskier than the last one - 15 points higher" |
| "KEV flagged" | "Attackers are actively exploiting this vulnerability in the wild" |
**Implementation:**
- Create `PlainLanguageService` with i18n support
- Add explanations to `DeltaSummaryStripComponent`
- Add explanations to `ItemsPaneComponent`
---
### VD-ENH-07: Plain Language Tooltips
Add contextual tooltips for technical terms.
**Terms to explain:**
- SBOM, VEX, CVE, CVSS, EPSS, KEV
- Reachability, Call path, Entry point
- DSSE, Attestation, Merkle proof
- Baseline, Head, Delta
**Implementation:**
- Create `GlossaryTooltipDirective`
- Auto-detect technical terms and add tooltips
- Link to full documentation for each term
---
### VD-ENH-08: Graph Diff Export
Add export functionality for audit reports.
**Requirements:**
- Export to SVG (vector, scalable)
- Export to PNG (raster, with resolution options)
- Include legend with change indicators
- Include metadata (baseline/head digests, timestamp)
- Filename format: `graph-diff-{baseDigest}-{headDigest}.{ext}`
---
### VD-ENH-09: Competitive Insights Integration
Review "Triage UI Lessons from Competitors" advisory and integrate relevant patterns.
**Key patterns to evaluate:**
- Snyk's exploitability scoring visualization
- Wiz's attack path diagrams
- Endor Labs' reachability evidence display
- Chainguard's provenance indicators
**Deliverable:** Design document with recommended adoptions
---
### VD-ENH-10: Storybook Stories
Add Storybook stories for new components.
**Stories to create:**
- `graph-diff.stories.ts` - GraphDiffComponent with various states
- `plain-language-toggle.stories.ts` - Toggle in both states
- `graph-controls.stories.ts` - Zoom/pan controls
**Requirements:**
- Include accessibility annotations
- Add interaction tests
- Document component API in story docs
---
### VD-ENH-11: Unit Tests
Add unit tests for graph diff logic.
**Test coverage:**
- Graph diff computation (added/removed/changed nodes)
- Path highlighting algorithm
- Plain language translation
- Export generation
**Target:** 80% code coverage for new components
---
### VD-ENH-12: E2E Tests
Add end-to-end tests for visual diff workflow.
**Scenarios:**
- Load compare view with two digests
- Toggle between split and unified view
- Navigate graph with keyboard
- Export graph diff
- Toggle plain language mode
**Location:** `src/Web/StellaOps.Web/tests/e2e/visual-diff.spec.ts`
---
## Technical Architecture
### Graph Rendering
Use lightweight SVG-based rendering (no heavy dependencies):
```
┌─────────────────────────────────────────────────────────────────┐
│ GraphDiffComponent │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ GraphSvgRenderer │ │ GraphDiffEngine │ │ GraphControls │ │
│ │ │ │ │ │ │ │
│ │ - renderNodes() │ │ - computeDiff() │ │ - zoom() │ │
│ │ - renderEdges() │ │ - classifyNodes()│ │ - pan() │ │
│ │ - highlight() │ │ - findPaths() │ │ - fitToView() │ │
│ └──────────────────┘ └──────────────────┘ └───────────────┘ │
│ │ │ │ │
│ └─────────────────────┼────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ SVG Viewport │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ [main()]──────▶[parse()]──────▶[vuln_func()] │ │ │
│ │ │ │ │ │ (removed) │ │ │
│ │ │ │ │ ▼ │ │ │
│ │ │ │ └──────▶[safe_func()] (added) │ │ │
│ │ │ ▼ │ │ │
│ │ │ [other()] │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### Plain Language Service
```typescript
@Injectable({ providedIn: 'root' })
export class PlainLanguageService {
private readonly translations = new Map<string, string>();
translate(technicalTerm: string, context?: TranslationContext): string;
isPlainLanguageEnabled(): Signal<boolean>;
togglePlainLanguage(): void;
}
```
---
## Acceptance Criteria
1. **Graph diff displays correctly** with color-coded change indicators
2. **Split view works** with synchronized navigation
3. **Plain language toggle** persists preference and updates all text
4. **Export produces** valid SVG/PNG with metadata
5. **All new components** have Storybook stories
6. **Test coverage** ≥80% for new code
7. **E2E tests pass** for complete visual diff workflow
8. **Accessibility audit** passes WCAG 2.1 AA
---
## Decisions & Risks
| ID | Decision/Risk | Status | Notes |
|----|---------------|--------|-------|
| D1 | Use SVG-based rendering (no Cytoscape/D3) | DECIDED | Lighter bundle, easier styling |
| D2 | Plain language as user preference, not role-based | DECIDED | More flexible |
| R1 | Large graphs (>200 nodes) may have performance issues | OPEN | May need virtualization |
| R2 | Export quality on high-DPI displays | OPEN | Test on various screen densities |
---
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2025-12-26 | Sprint created from Visual Diffs advisory gap analysis. Existing implementation covers ~75-80%; this sprint addresses remaining enhancements. | Project Mgmt |
---
## Related Documentation
- [Smart-Diff UI Architecture](../modules/web/smart-diff-ui-architecture.md)
- [Triage UI Lessons from Competitors](../product-advisories/25-Dec-2025%20-%20Triage%20UI%20Lessons%20from%20Competitors.md)
- [Implementing Diff-Aware Release Gates](../product-advisories/25-Dec-2025%20-%20Implementing%20Diff%E2%80%91Aware%20Release%20Gates.md)

View File

@@ -0,0 +1,81 @@
# Sprint 20251226 · Runtime Stack Capture and Canonicalization
## Topic & Scope
- Implement eBPF-based stack trace sampling for production workloads.
- Build symbol canonicalization service to resolve PC → (Build-ID, function, offset).
- Create hot symbol index for correlating runtime observations with reachability models.
- **Working directory:** `src/Scanner/StellaOps.Scanner.Analyzers.Native/`, `src/Signals/`
## Dependencies & Concurrency
- Depends on: `LinuxEbpfCaptureAdapter` (complete for dlopen), `BinaryIdentity` (complete).
- Enhances: SPRINT_20251226_009_SCANNER (symbol digests enable correlation).
- Enables: SPRINT_20251226_011_BE (auto-VEX needs hot symbol detection).
## Documentation Prerequisites
- `docs/modules/scanner/runtime-evidence.md`
- `docs/modules/signals/architecture.md`
- `docs/product-advisories/25-Dec-2025 - Evolving Evidence Models for Reachability.md`
## Context: What Already Exists
| Component | Location | Status |
|-----------|----------|--------|
| LinuxEbpfCaptureAdapter | `Scanner.Native/RuntimeCapture/` | COMPLETE (dlopen hooks only) |
| RuntimeEvidence models | `Scanner.Native/RuntimeCapture/RuntimeEvidence.cs` | COMPLETE |
| ReachabilityLattice (8 states) | `Signals/Lattice/ReachabilityLatticeState.cs` | COMPLETE |
| Evidence-weighted scoring | `Signals/EvidenceWeightedScore/` | COMPLETE |
| Symbol demangler interface | `ISymbolDemangler.cs` | Interface only |
This sprint adds **stack trace capture** (beyond dlopen) and **symbol canonicalization**.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | STACK-01 | TODO | None | Scanner Guild | Extend eBPF adapter with `bpf_get_stackid` for stack trace sampling |
| 2 | STACK-02 | TODO | STACK-01 | Scanner Guild | Configure sampling rate (default: 49 Hz) and duration per workload |
| 3 | STACK-03 | TODO | STACK-01 | Scanner Guild | Capture user + kernel stacks with PID, container ID, image digest |
| 4 | STACK-04 | TODO | STACK-03 | Scanner Guild | Collapsed stack format: "frameA;frameB;frameC count" (flamegraph-compatible) |
| 5 | STACK-05 | TODO | STACK-04 | Scanner Guild | Include Build-ID tuples in stack records |
| 6 | STACK-06 | TODO | None | Signals Guild | Create `ISymbolCanonicalizationService` interface |
| 7 | STACK-07 | TODO | STACK-06 | Signals Guild | Implement PC → (Build-ID, function, offset) resolution via ELF symbol table |
| 8 | STACK-08 | TODO | STACK-07 | Signals Guild | Language runtime mapping: Java frames via JVMTI, .NET via DAC, Python via symbols |
| 9 | STACK-09 | TODO | STACK-07 | Signals Guild | Slim symbol cache for production (avoid full debuginfod) |
| 10 | STACK-10 | TODO | STACK-04 | Signals Guild | Hot symbol index: track function → observation count with timestamp window |
| 11 | STACK-11 | TODO | STACK-10 | Signals Guild | Persistence: `hot_symbols` PostgreSQL table with Build-ID, symbol, count, window |
| 12 | STACK-12 | TODO | STACK-10 | Signals Guild | API endpoint: `GET /api/v1/signals/hot-symbols?image=<digest>` |
| 13 | STACK-13 | TODO | STACK-05 | Scanner Guild | Correlate stacks with SBOM: (image-digest, Build-ID, function) → purl |
| 14 | STACK-14 | TODO | STACK-13 | Scanner Guild | Link to FuncProof: verify observed symbol exists in funcproof |
| 15 | STACK-15 | TODO | STACK-04 | Scanner Guild | Privacy-preserving redaction: hash short-lived arguments, scrub paths |
| 16 | STACK-16 | TODO | STACK-15 | Scanner Guild | Configurable sampling budget: P99 overhead < 1% |
| 17 | STACK-17 | TODO | All above | Signals Guild | Integration tests: stack capture canonicalization hot symbol index |
## Collapsed Stack Format
```
api-gw@sha256:abc123;buildid=ab12...;libfoo::parse_hdr+0x3a;net/http::Serve;main 97
api-gw@sha256:abc123;buildid=ab12...;libfoo::validate+0x12;net/http::Serve;main 42
```
Fields:
- `container@digest`: Image identifier
- `buildid=...`: ELF Build-ID
- `symbol+offset`: Canonical function + offset within function
- `count`: Observation frequency
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from advisory analysis; implements runtime stack capture from "Evolving Evidence Models". | Project Mgmt |
## Decisions & Risks
- Decision needed: Sampling frequency (49 Hz vs 99 Hz). Recommend: 49 Hz for production safety.
- Decision needed: Stack depth limit. Recommend: 64 frames max.
- Decision needed: Symbol cache strategy. Recommend: slim cache in pod, full cache in cluster service.
- Risk: High overhead in CPU-bound workloads. Mitigation: adaptive sampling based on CPU load.
- Risk: Java/.NET frame resolution requires JIT metadata. Mitigation: fallback to address-only if JIT info unavailable.
- Risk: Privacy concerns with stack traces. Mitigation: redaction + short retention (24h default).
## Next Checkpoints
- 2025-12-30 | STACK-05 complete | Stack capture with Build-ID working |
- 2026-01-03 | STACK-11 complete | Hot symbol index persisted |
- 2026-01-06 | STACK-17 complete | Full integration tested |

View File

@@ -0,0 +1,103 @@
# Sprint 20251226 · Auto-VEX Downgrade Based on Runtime Observation
## Topic & Scope
- Implement automatic VEX status downgrade when vulnerable symbols are observed in production.
- Generate DSSE-signed VEX statements with runtime evidence attachment.
- Integrate with policy gates and notification routing.
- **Working directory:** `src/Policy/`, `src/Excititor/`, `src/Signals/`, `src/Notify/`
## Dependencies & Concurrency
- Depends on: SPRINT_20251226_009_SCANNER (FuncProof for symbol correlation).
- Depends on: SPRINT_20251226_010_SIGNALS (hot symbol index for detection).
- Can start API/schema work in parallel while waiting for upstream sprints.
## Documentation Prerequisites
- `docs/modules/signals/architecture.md`
- `docs/modules/policy/architecture.md`
- `docs/modules/excititor/architecture.md`
- `docs/product-advisories/25-Dec-2025 - Evolving Evidence Models for Reachability.md`
## Context: What Already Exists
| Component | Location | Status |
|-----------|----------|--------|
| VEX ingestion/emission | `Excititor/` | COMPLETE |
| ReachabilityLattice (8 states) | `Signals/Lattice/` | COMPLETE |
| Evidence-weighted scoring | `Signals/EvidenceWeightedScore/` | COMPLETE |
| DSSE signing | `Signer/` | COMPLETE |
| Policy gates (drift gate) | `Policy/Gates/DriftGateEvaluator.cs` | COMPLETE |
| Notification routing | `Notify/` | COMPLETE |
This sprint adds **runtime-triggered VEX state transitions**.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | AUTOVEX-01 | TODO | None | Policy Guild | Define hot vulnerable symbol detection logic: (CVE, symbol_digest) in hot_symbols |
| 2 | AUTOVEX-02 | TODO | AUTOVEX-01 | Policy Guild | Threshold configuration: minimum observation count/percentage for downgrade |
| 3 | AUTOVEX-03 | TODO | AUTOVEX-02 | Excititor Guild | VEX downgrade generation: emit `affected` status with evidence |
| 4 | AUTOVEX-04 | TODO | AUTOVEX-03 | Excititor Guild | Evidence attachment: stacks (top 5), percentiles, Build-IDs, timestamp window |
| 5 | AUTOVEX-05 | TODO | AUTOVEX-03 | Excititor Guild | DSSE signing for VEX downgrade statement |
| 6 | AUTOVEX-06 | TODO | AUTOVEX-05 | Excititor Guild | Rekor logging for VEX downgrade transparency |
| 7 | AUTOVEX-07 | TODO | AUTOVEX-03 | Policy Guild | Update reachability lattice: RuntimeObserved → ConfirmedReachable |
| 8 | AUTOVEX-08 | TODO | AUTOVEX-07 | Policy Guild | Trigger DriftGateEvaluator re-evaluation on VEX downgrade |
| 9 | AUTOVEX-09 | TODO | AUTOVEX-03 | Signals Guild | Update EvidenceWeightedScore: RTS dimension reflects runtime observation |
| 10 | AUTOVEX-10 | TODO | AUTOVEX-08 | Notify Guild | Notification template: "CVE-XXXX observed in libfoo::parse_hdr (17% CPU)" |
| 11 | AUTOVEX-11 | TODO | AUTOVEX-08 | Policy Guild | Policy gate action: quarantine, canary freeze, release block options |
| 12 | AUTOVEX-12 | TODO | None | Policy Guild | Time-boxed confidence: maintain not_affected if symbol never observed (with TTL) |
| 13 | AUTOVEX-13 | TODO | AUTOVEX-12 | Policy Guild | TTL configuration: default 7 days, configurable per environment |
| 14 | AUTOVEX-14 | TODO | AUTOVEX-12 | Excititor Guild | Emit VEX with justification `not_reachable_at_runtime` and conditions |
| 15 | AUTOVEX-15 | TODO | AUTOVEX-06 | Policy Guild | CLI command: `stella vex auto-downgrade --check <image>` for manual trigger |
| 16 | AUTOVEX-16 | TODO | All above | Policy Guild | Integration tests: symbol observation → VEX downgrade → gate block |
## Auto-VEX Evidence Schema
```json
{
"type": "openvex",
"statement": {
"vulnerability": "CVE-2025-XXXX",
"product": "pkg:oci/api-gw@sha256:abc123",
"status": "affected",
"status_notes": "Vulnerable symbol observed in production",
"evidence": {
"runtime_observation": {
"symbol": "libfoo::parse_hdr",
"symbol_digest": "blake3:...",
"build_id": "ab12cd34...",
"observation_window": {
"start": "2025-12-26T12:00:00Z",
"end": "2025-12-26T14:00:00Z"
},
"cpu_percentage": 17.3,
"top_stacks": [
"api-gw;libfoo::parse_hdr+0x3a;net/http::Serve;main 97"
],
"container_ids": ["abc123", "def456"]
},
"static_proof": {
"funcproof_uri": "oci://registry/api-gw@sha256:abc123/funcproof",
"funcproof_digest": "sha256:..."
}
}
}
}
```
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from advisory analysis; implements auto-VEX from "Evolving Evidence Models". | Project Mgmt |
## Decisions & Risks
- Decision needed: Downgrade threshold (1% CPU? 5%?). Recommend: configurable per CVE severity.
- Decision needed: Auto-downgrade scope (all images or per-image). Recommend: per-image with inheritance.
- Decision needed: Human approval required for high-severity auto-downgrade. Recommend: approval for KEV, auto for others.
- Risk: False positives from sampling noise. Mitigation: require minimum observation count (default: 10).
- Risk: Rapid VEX state thrashing. Mitigation: hysteresis (upgrade requires 24h of no observation).
- Risk: Notification fatigue. Mitigation: aggregate downgrades, configurable quiet hours.
## Next Checkpoints
- 2025-12-30 | AUTOVEX-06 complete | VEX downgrade with DSSE signing working |
- 2026-01-03 | AUTOVEX-11 complete | Policy gate integration functional |
- 2026-01-06 | AUTOVEX-16 complete | Full integration tested |

View File

@@ -0,0 +1,214 @@
# SPRINT_20251226_011_BINIDX_known_build_catalog
> **Status:** TODO
> **Priority:** P1
> **Module:** BinaryIndex
> **Created:** 2025-12-26
> **Architecture:** [`docs/modules/binaryindex/architecture.md`](../modules/binaryindex/architecture.md)
> **Advisory:** [`26-Dec-2026 - Mapping a Binary Intelligence Graph.md`](../product-advisories/26-Dec-2026%20-%20Mapping%20a%20Binary%20Intelligence%20Graph.md) (SUPERSEDED)
---
## Topic & Scope
Implement the foundational **Known-Build Binary Catalog** - the first MVP tier that enables querying "is this Build-ID vulnerable?" with distro-level precision.
**Goal:** Query binary vulnerability by Build-ID/PE signature with distro-specific accuracy.
**Working directory:** `src/BinaryIndex/`
---
## Documentation Prerequisites
- `docs/modules/binaryindex/architecture.md`
- `docs/db/schemas/binaries_schema_specification.md` (to be created)
- `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Core/`
---
## Delivery Tracker
| # | Task ID | Status | Depends | Owner | Description |
|---|---------|--------|---------|-------|-------------|
| 1 | BINCAT-01 | TODO | None | BE Guild | Create `binaries` PostgreSQL schema with RLS |
| 2 | BINCAT-02 | TODO | BINCAT-01 | BE Guild | Implement `binary_identity` table and migrations |
| 3 | BINCAT-03 | TODO | BINCAT-01 | BE Guild | Implement `binary_package_map` table for Build-ID → package mapping |
| 4 | BINCAT-04 | TODO | BINCAT-01 | BE Guild | Implement `vulnerable_buildids` table for known-vulnerable binaries |
| 5 | BINCAT-05 | TODO | BINCAT-01 | BE Guild | Implement `corpus_snapshots` table for ingestion tracking |
| 6 | BINCAT-06 | TODO | None | BE Guild | Create `IBinaryIdentityRepository` interface and implementation |
| 7 | BINCAT-07 | TODO | BINCAT-06 | BE Guild | Implement `BinaryIdentityRepository` with PostgreSQL persistence |
| 8 | BINCAT-08 | TODO | None | BE Guild | Enhance `ElfFeatureExtractor` with full Build-ID extraction |
| 9 | BINCAT-09 | TODO | None | BE Guild | Create `PeFeatureExtractor` for Windows PE CodeView GUID extraction |
| 10 | BINCAT-10 | TODO | None | BE Guild | Create `MachoFeatureExtractor` for Mach-O LC_UUID extraction |
| 11 | BINCAT-11 | TODO | None | BE Guild | Finalize `DebianCorpusConnector` implementation |
| 12 | BINCAT-12 | TODO | BINCAT-11 | BE Guild | Implement `DebianMirrorPackageSource` for mirror interaction |
| 13 | BINCAT-13 | TODO | BINCAT-11 | BE Guild | Implement `DebianPackageExtractor` for .deb binary extraction |
| 14 | BINCAT-14 | TODO | BINCAT-11 | BE Guild | Create corpus snapshot persistence in `CorpusSnapshotRepository` |
| 15 | BINCAT-15 | TODO | BINCAT-06,BINCAT-08 | BE Guild | Implement basic `IBinaryVulnerabilityService.LookupByIdentityAsync` |
| 16 | BINCAT-16 | TODO | BINCAT-15 | BE Guild | Implement batch lookup `LookupBatchAsync` for scan performance |
| 17 | BINCAT-17 | TODO | All | BE Guild | Add unit tests for identity extraction (ELF, PE, Mach-O) |
| 18 | BINCAT-18 | TODO | All | BE Guild | Add integration tests with Testcontainers PostgreSQL |
| 19 | BINCAT-19 | TODO | BINCAT-01 | BE Guild | Create database schema specification document |
| 20 | BINCAT-20 | TODO | All | BE Guild | Add OpenTelemetry traces for lookup operations |
**Total Tasks:** 20
---
## Task Details
### BINCAT-01: PostgreSQL Schema with RLS
Create the `binaries` schema with Row-Level Security for tenant isolation.
**Requirements:**
```sql
CREATE SCHEMA IF NOT EXISTS binaries;
CREATE SCHEMA IF NOT EXISTS binaries_app;
-- RLS helper function
CREATE OR REPLACE FUNCTION binaries_app.require_current_tenant()
RETURNS TEXT LANGUAGE plpgsql STABLE SECURITY DEFINER AS $$
DECLARE v_tenant TEXT;
BEGIN
v_tenant := current_setting('app.tenant_id', true);
IF v_tenant IS NULL OR v_tenant = '' THEN
RAISE EXCEPTION 'app.tenant_id session variable not set';
END IF;
RETURN v_tenant;
END;
$$;
```
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Persistence/Migrations/`
---
### BINCAT-02: binary_identity Table
Store known binary identities with all extraction methods.
**Schema:**
```sql
CREATE TABLE binaries.binary_identity (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL DEFAULT binaries_app.require_current_tenant(),
binary_key TEXT NOT NULL, -- Canonical key
format TEXT NOT NULL, -- elf, pe, macho
build_id TEXT, -- ELF GNU Build-ID
build_id_type TEXT, -- gnu, go, sha1
pe_codeview_guid TEXT, -- PE CodeView GUID
pe_imphash TEXT, -- PE import hash
macho_uuid TEXT, -- Mach-O LC_UUID
file_sha256 TEXT NOT NULL, -- Whole file hash
text_sha256 TEXT, -- .text section hash
architecture TEXT NOT NULL, -- x86_64, aarch64, etc.
compiler_hint TEXT, -- gcc-13.2, clang-18
source_hint TEXT, -- Package name/version if known
indexed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (tenant_id, binary_key)
);
ALTER TABLE binaries.binary_identity ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON binaries.binary_identity
USING (tenant_id = binaries_app.require_current_tenant());
```
---
### BINCAT-08: Enhanced ElfFeatureExtractor
Enhance existing `ElfFeatureExtractor` with complete feature extraction.
**Requirements:**
- Extract GNU Build-ID from `.note.gnu.build-id`
- Extract Go Build-ID if present
- Compute `.text` section SHA-256
- Extract DT_NEEDED dynamic dependencies
- Extract exported/imported symbols
- Detect hardening flags (RELRO, PIE, NX, stack canary)
**Existing file:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Core/Services/ElfFeatureExtractor.cs`
---
### BINCAT-09: PeFeatureExtractor
Create PE (Windows) binary feature extractor.
**Requirements:**
- Extract CodeView GUID + Age from debug directory
- Compute import hash (imphash)
- Extract PE timestamp and linker version
- Extract DLL imports
- Detect ASLR/DEP/CFG flags
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Core/Services/PeFeatureExtractor.cs`
---
### BINCAT-10: MachoFeatureExtractor
Create Mach-O (macOS/iOS) binary feature extractor.
**Requirements:**
- Extract LC_UUID from load commands
- Compute __TEXT section hash
- Extract dylib dependencies
- Detect code signing info
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Core/Services/MachoFeatureExtractor.cs`
---
### BINCAT-11: DebianCorpusConnector
Finalize the Debian corpus connector for binary ingestion.
**Requirements:**
- Connect to Debian/Ubuntu mirrors
- Fetch package lists for specified releases
- Track snapshot state in `corpus_snapshots` table
- Support incremental updates
**Existing file:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Corpus.Debian/DebianCorpusConnector.cs`
---
## Acceptance Criteria
1. **Schema deployed** with RLS policies active
2. **Build-ID extraction** works for ELF binaries
3. **PE GUID extraction** works for Windows binaries
4. **Mach-O UUID extraction** works for macOS binaries
5. **Debian connector** can ingest packages from mirror
6. **Lookup service** returns matches by Build-ID
7. **Integration tests** pass with Testcontainers
8. **Metrics exported** for lookup latency and counts
---
## Decisions & Risks
| ID | Decision/Risk | Status | Notes |
|----|---------------|--------|-------|
| D1 | Use composite binary_key for canonical identification | DECIDED | Format: `{format}:{arch}:{build_id or hash}` |
| D2 | Store hashes as TEXT not BYTEA | DECIDED | Easier debugging, hex format |
| R1 | Large corpus ingestion may take hours | OPEN | Consider background job with progress tracking |
| R2 | Mirror availability varies by region | OPEN | Support multiple mirror fallbacks |
---
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2025-12-26 | Sprint created from BinaryIndex MVP roadmap. | Project Mgmt |
---
## Related Documentation
- [BinaryIndex Architecture](../modules/binaryindex/architecture.md)
- [Scanner Native Analysis](../modules/scanner/analyzers/native.md)

View File

@@ -0,0 +1,234 @@
# SPRINT_20251226_012_BINIDX_backport_handling
> **Status:** TODO
> **Priority:** P1
> **Module:** BinaryIndex
> **Created:** 2025-12-26
> **Depends On:** [`SPRINT_20251226_011_BINIDX_known_build_catalog.md`](./SPRINT_20251226_011_BINIDX_known_build_catalog.md)
> **Architecture:** [`docs/modules/binaryindex/architecture.md`](../modules/binaryindex/architecture.md)
---
## Topic & Scope
Implement **Patch-Aware Backport Handling** - the second MVP tier that handles "version says vulnerable but distro backported the fix" scenarios.
**Goal:** Detect when a distro has backported a security fix without bumping the upstream version.
**Working directory:** `src/BinaryIndex/`
---
## Documentation Prerequisites
- `docs/modules/binaryindex/architecture.md`
- `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.FixIndex/`
- Debian changelog format: https://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog
- DEP-3 patch header format: https://dep-team.pages.debian.net/deps/dep3/
---
## Delivery Tracker
| # | Task ID | Status | Depends | Owner | Description |
|---|---------|--------|---------|-------|-------------|
| 1 | BACKPORT-01 | TODO | None | BE Guild | Create `cve_fix_index` table for patch-aware fix status |
| 2 | BACKPORT-02 | TODO | BACKPORT-01 | BE Guild | Create `fix_evidence` table for audit trail |
| 3 | BACKPORT-03 | TODO | None | BE Guild | Finalize `DebianChangelogParser` implementation |
| 4 | BACKPORT-04 | TODO | None | BE Guild | Finalize `PatchHeaderParser` for DEP-3 format |
| 5 | BACKPORT-05 | TODO | None | BE Guild | Finalize `AlpineSecfixesParser` for Alpine APKBUILD |
| 6 | BACKPORT-06 | TODO | None | BE Guild | Create `RpmChangelogParser` for RPM spec files |
| 7 | BACKPORT-07 | TODO | None | BE Guild | Create `IFixIndexBuilder` implementation |
| 8 | BACKPORT-08 | TODO | BACKPORT-07 | BE Guild | Implement `FixIndexBuilder.BuildIndexAsync` for Debian |
| 9 | BACKPORT-09 | TODO | BACKPORT-07 | BE Guild | Implement `FixIndexBuilder.BuildIndexAsync` for Alpine |
| 10 | BACKPORT-10 | TODO | BACKPORT-07 | BE Guild | Implement `FixIndexBuilder.BuildIndexAsync` for RPM |
| 11 | BACKPORT-11 | TODO | BACKPORT-01 | BE Guild | Create `IFixIndexRepository` interface |
| 12 | BACKPORT-12 | TODO | BACKPORT-11 | BE Guild | Implement `FixIndexRepository` with PostgreSQL |
| 13 | BACKPORT-13 | TODO | BACKPORT-12 | BE Guild | Add `GetFixStatusAsync` to `IBinaryVulnerabilityService` |
| 14 | BACKPORT-14 | TODO | None | BE Guild | Create `RpmCorpusConnector` for RHEL/Fedora/CentOS |
| 15 | BACKPORT-15 | TODO | BACKPORT-14 | BE Guild | Implement SRPM changelog extraction |
| 16 | BACKPORT-16 | TODO | BACKPORT-05 | BE Guild | Create `AlpineCorpusConnector` for Alpine APK |
| 17 | BACKPORT-17 | TODO | BACKPORT-16 | BE Guild | Implement APKBUILD secfixes extraction |
| 18 | BACKPORT-18 | TODO | All | BE Guild | Add confidence scoring for fix evidence |
| 19 | BACKPORT-19 | TODO | All | BE Guild | Add unit tests for all parsers |
| 20 | BACKPORT-20 | TODO | All | BE Guild | Add integration tests for fix index building |
| 21 | BACKPORT-21 | TODO | All | BE Guild | Document fix evidence chain in architecture doc |
**Total Tasks:** 21
---
## Task Details
### BACKPORT-01: cve_fix_index Table
Store patch-aware CVE fix status per distro/release/package.
**Schema:**
```sql
CREATE TABLE binaries.cve_fix_index (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL DEFAULT binaries_app.require_current_tenant(),
distro TEXT NOT NULL, -- debian, ubuntu, alpine, rhel
release TEXT NOT NULL, -- bookworm, jammy, v3.19
source_pkg TEXT NOT NULL, -- Source package name
cve_id TEXT NOT NULL, -- CVE-YYYY-NNNN
state TEXT NOT NULL, -- fixed, vulnerable, not_affected, wontfix, unknown
fixed_version TEXT, -- Distro version string where fixed
method TEXT NOT NULL, -- security_feed, changelog, patch_header, upstream_match
confidence DECIMAL(3,2) NOT NULL, -- 0.00-1.00
evidence_id UUID, -- Reference to fix_evidence
snapshot_id UUID, -- Corpus snapshot this came from
indexed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (tenant_id, distro, release, source_pkg, cve_id)
);
CREATE INDEX idx_cve_fix_lookup ON binaries.cve_fix_index
(tenant_id, distro, release, source_pkg, cve_id);
```
---
### BACKPORT-03: DebianChangelogParser
Parse Debian/Ubuntu changelog files for CVE fix mentions.
**Input format:**
```
package (1.2.3-4) bookworm-security; urgency=high
* Fix CVE-2024-1234: buffer overflow in parse_header
* Fix CVE-2024-1235: use-after-free in cleanup
-- Maintainer <email> Mon, 01 Jan 2024 12:00:00 +0000
```
**Requirements:**
- Extract CVE mentions from changelog entries
- Map to version where fix appeared
- Handle multiple CVEs per entry
- Support urgency levels
**Existing file:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.FixIndex/Parsers/DebianChangelogParser.cs`
---
### BACKPORT-04: PatchHeaderParser
Parse DEP-3 patch headers for upstream patch references.
**Input format:**
```
Description: Fix buffer overflow in parse_header
Origin: upstream, https://github.com/project/commit/abc123
Bug-Debian: https://bugs.debian.org/123456
CVE: CVE-2024-1234
Applied-Upstream: 1.2.4
```
**Requirements:**
- Extract CVE references
- Extract upstream commit/version
- Extract bug tracker references
- Calculate confidence based on origin
**Existing file:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.FixIndex/Parsers/PatchHeaderParser.cs`
---
### BACKPORT-05: AlpineSecfixesParser
Parse Alpine APKBUILD secfixes section.
**Input format:**
```
# secfixes:
# 1.2.3-r1:
# - CVE-2024-1234
# - CVE-2024-1235
# 1.2.2-r0:
# - CVE-2024-1000
```
**Requirements:**
- Parse secfixes comment block
- Map CVEs to Alpine version strings
- Handle version ranges
**Existing file:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.FixIndex/Parsers/AlpineSecfixesParser.cs`
---
### BACKPORT-06: RpmChangelogParser
Parse RPM spec file changelog for CVE mentions.
**Input format:**
```
%changelog
* Mon Jan 01 2024 Packager <email> - 1.2.3-4
- Fix CVE-2024-1234
- Backport upstream security patches
```
**Requirements:**
- Parse RPM spec %changelog section
- Extract CVE mentions
- Map to NEVRA version
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.FixIndex/Parsers/RpmChangelogParser.cs`
---
### BACKPORT-18: Confidence Scoring
Implement confidence scoring for fix evidence.
**Confidence Levels:**
| Method | Base Confidence | Notes |
|--------|-----------------|-------|
| Security Feed (OVAL) | 0.99 | Authoritative |
| Patch Header with upstream ref | 0.95 | Strong evidence |
| Changelog with CVE mention | 0.85 | Good evidence |
| Changelog inference | 0.70 | Version-based inference |
| Upstream patch match | 0.90 | Binary diff match |
---
## Acceptance Criteria
1. **Fix index populated** for Debian/Ubuntu packages
2. **Changelog parser** correctly extracts CVE fixes
3. **Patch header parser** handles DEP-3 format
4. **Alpine secfixes** parsed correctly
5. **GetFixStatusAsync** returns backport status
6. **Confidence scores** calculated per method
7. **Evidence chain** auditable
8. **Integration tests** cover all distros
---
## Decisions & Risks
| ID | Decision/Risk | Status | Notes |
|----|---------------|--------|-------|
| D1 | Prioritize security feed over changelog when conflicting | DECIDED | Feed is authoritative |
| D2 | Store raw evidence excerpts for audit | DECIDED | Truncate at 1KB |
| R1 | Changelog parsing may have false positives | OPEN | Use confidence scoring |
| R2 | Some distros don't maintain consistent CVE references | OPEN | Flag as "unknown" with low confidence |
---
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2025-12-26 | Sprint created from BinaryIndex MVP roadmap. | Project Mgmt |
---
## Related Documentation
- [BinaryIndex Architecture](../modules/binaryindex/architecture.md)
- [Debian Policy - Changelogs](https://www.debian.org/doc/debian-policy/ch-source.html)
- [DEP-3 Patch Tagging Guidelines](https://dep-team.pages.debian.net/deps/dep3/)

View File

@@ -0,0 +1,99 @@
# Sprint 20251226 · Smart-Diff Three-Pane Compare View
## Topic & Scope
- Implement the three-pane Smart-Diff Compare View as designed in `docs/modules/web/smart-diff-ui-architecture.md`.
- Build baseline selector, delta summary strip, categories/items/proof pane layout.
- Implement role-based defaults (Developer/Security/Audit) and trust indicators.
- **Working directory:** `src/Web/StellaOps.Web`
## Dependencies & Concurrency
- Depends on: SPRINT_20251226_004_FE (risk dashboard components), SPRINT_20251226_001_BE (gate API).
- Can run in parallel with: SPRINT_20251226_013_FE (triage canvas).
- Enhances: SPRINT_20251226_004_FE by adding detailed comparison capability.
## Documentation Prerequisites
- `docs/modules/web/smart-diff-ui-architecture.md` (REQUIRED - primary design reference)
- `docs/product-advisories/25-Dec-2025 - Visual Diffs for Explainable Triage.md`
- `docs/product-advisories/25-Dec-2025 - Triage UI Lessons from Competitors.md`
- Angular 17 patterns in existing codebase
## Context: What Already Exists
| Component | Location | Status |
|-----------|----------|--------|
| Smart-Diff Architecture | `docs/modules/web/smart-diff-ui-architecture.md` | COMPLETE (design only) |
| Release Flow | `features/releases/release-flow.component.ts` | COMPLETE |
| Policy Gate Indicator | `features/releases/policy-gate-indicator.component.ts` | COMPLETE |
| Confidence Badge | `shared/components/confidence-badge.component.ts` | COMPLETE |
| Evidence Page | `features/evidence/evidence-page.component.ts` | PARTIAL |
| Determinism Badge | `features/scans/determinism-badge.component.ts` | COMPLETE |
This sprint implements the **three-pane compare view** from the architecture specification.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | SDIFF-01 | TODO | None | Frontend Guild | Create `CompareService` Angular service with baseline recommendations API |
| 2 | SDIFF-02 | TODO | SDIFF-01 | Frontend Guild | Create `DeltaComputeService` for idempotent delta computation |
| 3 | SDIFF-03 | TODO | None | Frontend Guild | `CompareViewComponent` container with signals-based state management |
| 4 | SDIFF-04 | TODO | SDIFF-03 | Frontend Guild | `BaselineSelectorComponent` with dropdown and rationale display |
| 5 | SDIFF-05 | TODO | SDIFF-04 | Frontend Guild | `BaselineRationaleComponent` explaining baseline selection logic |
| 6 | SDIFF-06 | TODO | SDIFF-03 | Frontend Guild | `TrustIndicatorsComponent` showing determinism hash, policy version, feed snapshot |
| 7 | SDIFF-07 | TODO | SDIFF-06 | Frontend Guild | `DeterminismHashDisplay` with copy button and verification status |
| 8 | SDIFF-08 | TODO | SDIFF-06 | Frontend Guild | `SignatureStatusDisplay` with DSSE verification result |
| 9 | SDIFF-09 | TODO | SDIFF-06 | Frontend Guild | `PolicyDriftIndicator` warning if policy changed since baseline |
| 10 | SDIFF-10 | TODO | SDIFF-03 | Frontend Guild | `DeltaSummaryStripComponent`: [+N added] [-N removed] [~N changed] counts |
| 11 | SDIFF-11 | TODO | SDIFF-10 | Frontend Guild | `ThreePaneLayoutComponent` responsive container for Categories/Items/Proof |
| 12 | SDIFF-12 | TODO | SDIFF-11 | Frontend Guild | `CategoriesPaneComponent`: SBOM, Reachability, VEX, Policy, Unknowns with counts |
| 13 | SDIFF-13 | TODO | SDIFF-12 | Frontend Guild | `ItemsPaneComponent` with virtual scrolling for large deltas (cdk-virtual-scroll) |
| 14 | SDIFF-14 | TODO | SDIFF-13 | Frontend Guild | Priority score display with color-coded severity |
| 15 | SDIFF-15 | TODO | SDIFF-11 | Frontend Guild | `ProofPaneComponent` container for evidence details |
| 16 | SDIFF-16 | TODO | SDIFF-15 | Frontend Guild | `WitnessPathComponent`: entry→sink call path visualization |
| 17 | SDIFF-17 | TODO | SDIFF-15 | Frontend Guild | `VexMergeExplanationComponent`: vendor + distro + org → merged result |
| 18 | SDIFF-18 | TODO | SDIFF-15 | Frontend Guild | `EnvelopeHashesComponent`: display content-addressed hashes |
| 19 | SDIFF-19 | TODO | SDIFF-03 | Frontend Guild | `ActionablesPanelComponent`: prioritized recommendations list |
| 20 | SDIFF-20 | TODO | SDIFF-03 | Frontend Guild | `ExportActionsComponent`: copy replay command, download evidence pack |
| 21 | SDIFF-21 | TODO | SDIFF-03 | Frontend Guild | Role-based view switching: Developer/Security/Audit defaults |
| 22 | SDIFF-22 | TODO | SDIFF-21 | Frontend Guild | User preference persistence for role and panel states |
| 23 | SDIFF-23 | TODO | SDIFF-13 | Frontend Guild | Micro-interaction: hover badge explaining "why it changed" |
| 24 | SDIFF-24 | TODO | SDIFF-17 | Frontend Guild | Micro-interaction: click rule → spotlight affected subgraph |
| 25 | SDIFF-25 | TODO | SDIFF-03 | Frontend Guild | "Explain like I'm new" toggle expanding jargon to plain language |
| 26 | SDIFF-26 | TODO | SDIFF-20 | Frontend Guild | "Copy audit bundle" one-click export as JSON attachment |
| 27 | SDIFF-27 | TODO | SDIFF-03 | Frontend Guild | Keyboard navigation: Tab/Arrow/Enter/Escape/C shortcuts |
| 28 | SDIFF-28 | TODO | SDIFF-27 | Frontend Guild | ARIA labels and screen reader live regions |
| 29 | SDIFF-29 | TODO | SDIFF-03 | Frontend Guild | Degraded mode: warning banner when signature verification fails |
| 30 | SDIFF-30 | TODO | SDIFF-11 | Frontend Guild | "Changed neighborhood only" default with mini-map for large graphs |
| 31 | SDIFF-31 | TODO | All above | Frontend Guild | Unit tests for all new components |
| 32 | SDIFF-32 | TODO | SDIFF-31 | Frontend Guild | E2E tests: full comparison workflow |
| 33 | SDIFF-33 | TODO | SDIFF-32 | Frontend Guild | Integration tests: API service calls and response handling |
## Routing Configuration
```typescript
// From smart-diff-ui-architecture.md
{
path: 'compare',
children: [
{ path: ':currentDigest', component: CompareViewComponent },
{ path: ':currentDigest/:baselineDigest', component: CompareViewComponent }
]
}
```
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from "Triage UI Lessons from Competitors" analysis; implements Smart-Diff Compare View. | Project Mgmt |
## Decisions & Risks
- Decision needed: Virtual scroll item height. Recommend: 56px consistent with Angular Material.
- Decision needed: Max graph nodes in witness path. Recommend: 25 nodes, "show more" for larger paths.
- Decision needed: Export format for audit bundle. Recommend: JSON-LD with DSSE envelope.
- Risk: Large deltas may exceed 1000 items. Mitigation: category pre-filtering, virtual scroll.
- Risk: Complex witness paths hard to visualize. Mitigation: collapsed by default, expand on demand.
- Risk: Keyboard shortcuts may conflict with browser. Mitigation: only active when component focused.
## Next Checkpoints
- 2026-01-03 | SDIFF-11 complete | Three-pane layout functional |
- 2026-01-08 | SDIFF-20 complete | Core comparison features working |
- 2026-01-13 | SDIFF-33 complete | Full implementation with tests |

View File

@@ -0,0 +1,240 @@
# SPRINT_20251226_013_BINIDX_fingerprint_factory
> **Status:** TODO
> **Priority:** P2
> **Module:** BinaryIndex
> **Created:** 2025-12-26
> **Depends On:** [`SPRINT_20251226_012_BINIDX_backport_handling.md`](./SPRINT_20251226_012_BINIDX_backport_handling.md)
> **Architecture:** [`docs/modules/binaryindex/architecture.md`](../modules/binaryindex/architecture.md)
---
## Topic & Scope
Implement the **Binary Fingerprint Factory** - the third MVP tier that enables detecting vulnerable code independent of package metadata through function-level fingerprinting.
**Goal:** Detect vulnerable code by matching function fingerprints, not just Build-IDs or versions.
**Working directory:** `src/BinaryIndex/`
---
## Documentation Prerequisites
- `docs/modules/binaryindex/architecture.md`
- `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Fingerprints/`
- Research: BinDiff, Diaphora, TLSH for binary similarity
---
## Delivery Tracker
| # | Task ID | Status | Depends | Owner | Description |
|---|---------|--------|---------|-------|-------------|
| 1 | FPRINT-01 | TODO | None | BE Guild | Create `vulnerable_fingerprints` table schema |
| 2 | FPRINT-02 | TODO | FPRINT-01 | BE Guild | Create `fingerprint_matches` table for match results |
| 3 | FPRINT-03 | TODO | None | BE Guild | Create `IFingerprintBlobStorage` for fingerprint storage |
| 4 | FPRINT-04 | TODO | FPRINT-03 | BE Guild | Implement `FingerprintBlobStorage` with RustFS backend |
| 5 | FPRINT-05 | TODO | None | BE Guild | Design `IVulnFingerprintGenerator` interface |
| 6 | FPRINT-06 | TODO | FPRINT-05 | BE Guild | Implement `BasicBlockFingerprintGenerator` |
| 7 | FPRINT-07 | TODO | FPRINT-05 | BE Guild | Implement `ControlFlowGraphFingerprintGenerator` |
| 8 | FPRINT-08 | TODO | FPRINT-05 | BE Guild | Implement `StringRefsFingerprintGenerator` |
| 9 | FPRINT-09 | TODO | FPRINT-05 | BE Guild | Implement `CombinedFingerprintGenerator` (ensemble) |
| 10 | FPRINT-10 | TODO | None | BE Guild | Create reference build generation pipeline |
| 11 | FPRINT-11 | TODO | FPRINT-10 | BE Guild | Implement vulnerable/fixed binary pair builder |
| 12 | FPRINT-12 | TODO | FPRINT-06 | BE Guild | Implement `IFingerprintMatcher` interface |
| 13 | FPRINT-13 | TODO | FPRINT-12 | BE Guild | Implement similarity matching with configurable threshold |
| 14 | FPRINT-14 | TODO | FPRINT-12 | BE Guild | Add `LookupByFingerprintAsync` to vulnerability service |
| 15 | FPRINT-15 | TODO | All | BE Guild | Seed fingerprints for OpenSSL high-impact CVEs |
| 16 | FPRINT-16 | TODO | All | BE Guild | Seed fingerprints for glibc high-impact CVEs |
| 17 | FPRINT-17 | TODO | All | BE Guild | Seed fingerprints for zlib high-impact CVEs |
| 18 | FPRINT-18 | TODO | All | BE Guild | Seed fingerprints for curl high-impact CVEs |
| 19 | FPRINT-19 | TODO | All | BE Guild | Create fingerprint validation corpus |
| 20 | FPRINT-20 | TODO | FPRINT-19 | BE Guild | Implement false positive rate validation |
| 21 | FPRINT-21 | TODO | All | BE Guild | Add unit tests for fingerprint generation |
| 22 | FPRINT-22 | TODO | All | BE Guild | Add integration tests for matching pipeline |
| 23 | FPRINT-23 | TODO | All | BE Guild | Document fingerprint algorithms in architecture |
**Total Tasks:** 23
---
## Task Details
### FPRINT-01: vulnerable_fingerprints Table
Store function-level vulnerability fingerprints.
**Schema:**
```sql
CREATE TABLE binaries.vulnerable_fingerprints (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL DEFAULT binaries_app.require_current_tenant(),
cve_id TEXT NOT NULL,
component TEXT NOT NULL, -- openssl, glibc, etc.
purl TEXT, -- Package URL if known
algorithm TEXT NOT NULL, -- basic_block, cfg, string_refs, combined
fingerprint_id TEXT NOT NULL, -- Unique fingerprint identifier
fingerprint_hash BYTEA NOT NULL, -- 16-32 byte hash
architecture TEXT NOT NULL, -- x86_64, aarch64
function_name TEXT, -- Function name if known
source_file TEXT, -- Source file if known
source_line INT, -- Line number if known
similarity_threshold DECIMAL(3,2) DEFAULT 0.95,
confidence DECIMAL(3,2),
validated BOOLEAN DEFAULT false,
validation_stats JSONB, -- {tp, fp, tn, fn}
vuln_build_ref TEXT, -- Reference to vulnerable build
fixed_build_ref TEXT, -- Reference to fixed build
indexed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (tenant_id, fingerprint_id)
);
CREATE INDEX idx_fingerprint_cve ON binaries.vulnerable_fingerprints (tenant_id, cve_id);
CREATE INDEX idx_fingerprint_component ON binaries.vulnerable_fingerprints (tenant_id, component);
```
---
### FPRINT-06: BasicBlockFingerprintGenerator
Generate fingerprints based on basic block hashing.
**Algorithm:**
1. Disassemble function to basic blocks
2. Normalize instructions (remove absolute addresses)
3. Hash each basic block
4. Combine block hashes with topology info
**Requirements:**
- Architecture-independent normalization
- Stable across compiler optimizations (-O1 to -O3)
- 16-byte fingerprint output
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Fingerprints/Generators/BasicBlockFingerprintGenerator.cs`
---
### FPRINT-07: ControlFlowGraphFingerprintGenerator
Generate fingerprints based on control flow graph structure.
**Algorithm:**
1. Build CFG from disassembly
2. Extract graph properties (node count, edge count, cyclomatic complexity)
3. Compute structural hash (adjacency matrix or graph kernel)
**Requirements:**
- Resilient to instruction reordering
- Capture loop and branch structure
- 32-byte fingerprint output
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Fingerprints/Generators/ControlFlowGraphFingerprintGenerator.cs`
---
### FPRINT-08: StringRefsFingerprintGenerator
Generate fingerprints based on string references in code.
**Algorithm:**
1. Extract string constants referenced by function
2. Hash string content (normalized)
3. Include reference order/pattern
**Requirements:**
- Useful for error message patterns
- Language-agnostic
- 16-byte fingerprint output
**Location:** `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Fingerprints/Generators/StringRefsFingerprintGenerator.cs`
---
### FPRINT-10: Reference Build Pipeline
Create automated pipeline for generating vulnerable/fixed binary pairs.
**Pipeline Steps:**
1. Identify CVE with known commit fix
2. Clone upstream source
3. Build at vulnerable version
4. Build at fixed version
5. Extract fingerprints from both
6. Compute differential fingerprint (what changed)
**Requirements:**
- Sandboxed build environment
- Multi-architecture support (x86_64, aarch64)
- Reproducible builds where possible
---
### FPRINT-15-18: High-Impact CVE Seeding
Seed initial fingerprint database with high-impact CVEs.
**Target Components:**
| Component | Priority CVEs | Notes |
|-----------|---------------|-------|
| OpenSSL | CVE-2024-*, CVE-2023-* | Heartbleed-class vulns |
| glibc | CVE-2024-*, CVE-2023-* | Memory corruption |
| zlib | CVE-2022-37434 | Heap overflow |
| curl | CVE-2024-*, CVE-2023-* | Protocol vulns |
**Goal:** 10+ fingerprints per component covering critical/high severity.
---
### FPRINT-19: Validation Corpus
Create corpus for validating fingerprint accuracy.
**Requirements:**
- Known-vulnerable binaries from multiple distros
- Known-fixed binaries (backported)
- Ground truth labels
- Measure: Precision, Recall, F1
**Target Metrics:**
- Precision: > 0.95 (low false positives)
- Recall: > 0.80 (reasonable coverage)
---
## Acceptance Criteria
1. **Fingerprint generation** works for ELF binaries
2. **All three algorithms** produce stable fingerprints
3. **Matching service** returns similarity scores
4. **10 high-impact CVEs** seeded per component
5. **Validation corpus** shows acceptable F1 score
6. **False positive rate** < 5%
7. **Integration tests** cover full pipeline
---
## Decisions & Risks
| ID | Decision/Risk | Status | Notes |
|----|---------------|--------|-------|
| D1 | Use combined algorithm for production | DECIDED | Ensemble of all three |
| D2 | Default similarity threshold 0.95 | DECIDED | Configurable per fingerprint |
| R1 | Compiler optimization may affect stability | OPEN | Test across -O0 to -O3 |
| R2 | Architecture differences may cause false negatives | OPEN | Generate per-architecture |
| R3 | Large functions may have weak fingerprints | OPEN | Add function size filter |
---
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2025-12-26 | Sprint created from BinaryIndex MVP roadmap. | Project Mgmt |
---
## Related Documentation
- [BinaryIndex Architecture](../modules/binaryindex/architecture.md)
- [Binary Similarity Research](https://github.com/google/bindiff)

View File

@@ -0,0 +1,117 @@
# Sprint 20251226 · Unified Triage Canvas with AdvisoryAI Integration
## Topic & Scope
- Build unified triage experience combining VulnExplorer, AdvisoryAI, and evidence in single canvas.
- Integrate AdvisoryAI recommendations into triage workflow.
- Implement competitor-parity features: reachability context, VEX decisioning, attestable exceptions.
- **Working directory:** `src/Web/StellaOps.Web`, `src/VulnExplorer/`
## Dependencies & Concurrency
- Depends on: SPRINT_20251226_012_FE (smart diff compare view), VulnExplorer API.
- Depends on: AdvisoryAI module (already complete).
- Can run in parallel with: Backend API work.
## Documentation Prerequisites
- `docs/product-advisories/25-Dec-2025 - Triage UI Lessons from Competitors.md`
- `docs/modules/advisoryai/architecture.md`
- `src/VulnExplorer/StellaOps.VulnExplorer.Api/Models/` (existing models)
- Angular 17 component patterns
## Context: What Already Exists
| Component | Location | Status |
|-----------|----------|--------|
| VEX Decision Models | `VulnExplorer/Models/VexDecisionModels.cs` | COMPLETE |
| Vulnerability Models | `VulnExplorer/Models/VulnModels.cs` | COMPLETE |
| VEX Decision Store | `VulnExplorer/Data/VexDecisionStore.cs` | COMPLETE (in-memory, production uses PG) |
| AdvisoryAI Pipeline | `AdvisoryAI/Orchestration/` | COMPLETE |
| AdvisoryAI Retrievers | `AdvisoryAI/Retrievers/` | COMPLETE |
| Vulnerability Detail | `Web/features/vulnerabilities/` | PARTIAL |
| Evidence Page | `Web/features/evidence/` | PARTIAL |
| Confidence Badge | `Web/shared/components/` | COMPLETE |
This sprint creates the **unified triage canvas** that competitors lack.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | TRIAGE-01 | TODO | None | Frontend Guild | Create `TriageCanvasComponent` container with multi-pane layout |
| 2 | TRIAGE-02 | TODO | None | Frontend Guild | Create `VulnerabilityListService` consuming VulnExplorer API |
| 3 | TRIAGE-03 | TODO | None | Frontend Guild | Create `AdvisoryAiService` consuming AdvisoryAI API endpoints |
| 4 | TRIAGE-04 | TODO | None | Frontend Guild | Create `VexDecisionService` for creating/updating VEX decisions |
| 5 | TRIAGE-05 | TODO | TRIAGE-01 | Frontend Guild | `TriageListComponent`: paginated vulnerability list with filters |
| 6 | TRIAGE-06 | TODO | TRIAGE-05 | Frontend Guild | Severity, KEV, exploitability, fix-available filter chips |
| 7 | TRIAGE-07 | TODO | TRIAGE-05 | Frontend Guild | Quick triage actions: "Mark Not Affected", "Request Analysis" |
| 8 | TRIAGE-08 | TODO | TRIAGE-01 | Frontend Guild | `TriageDetailComponent`: selected vulnerability deep-dive |
| 9 | TRIAGE-09 | TODO | TRIAGE-08 | Frontend Guild | Affected packages panel with PURL links |
| 10 | TRIAGE-10 | TODO | TRIAGE-08 | Frontend Guild | Advisory references panel with external links |
| 11 | TRIAGE-11 | TODO | TRIAGE-08 | Frontend Guild | Evidence provenance display: ledger entry, evidence bundle links |
| 12 | TRIAGE-12 | TODO | TRIAGE-08 | Frontend Guild | `ReachabilityContextComponent`: call graph slice from entry to vulnerability |
| 13 | TRIAGE-13 | TODO | TRIAGE-12 | Frontend Guild | Reachability confidence band using existing ConfidenceBadge |
| 14 | TRIAGE-14 | TODO | TRIAGE-03 | Frontend Guild | `AiRecommendationPanel`: AdvisoryAI suggestions for current vuln |
| 15 | TRIAGE-15 | TODO | TRIAGE-14 | Frontend Guild | "Why is this reachable?" AI-generated explanation |
| 16 | TRIAGE-16 | TODO | TRIAGE-14 | Frontend Guild | Suggested VEX justification from AI analysis |
| 17 | TRIAGE-17 | TODO | TRIAGE-14 | Frontend Guild | Similar vulnerabilities suggestion based on AI clustering |
| 18 | TRIAGE-18 | TODO | TRIAGE-04 | Frontend Guild | `VexDecisionModalComponent`: create VEX decision with justification |
| 19 | TRIAGE-19 | TODO | TRIAGE-18 | Frontend Guild | VEX status dropdown: NotAffected, AffectedMitigated, AffectedUnmitigated, Fixed |
| 20 | TRIAGE-20 | TODO | TRIAGE-18 | Frontend Guild | Justification type selector matching VexJustificationType enum |
| 21 | TRIAGE-21 | TODO | TRIAGE-18 | Frontend Guild | Evidence reference input: PR, Ticket, Doc, Commit links |
| 22 | TRIAGE-22 | TODO | TRIAGE-18 | Frontend Guild | Scope selector: environments and projects |
| 23 | TRIAGE-23 | TODO | TRIAGE-18 | Frontend Guild | Validity window: NotBefore/NotAfter date pickers |
| 24 | TRIAGE-24 | TODO | TRIAGE-18 | Frontend Guild | "Sign as Attestation" checkbox triggering DSSE envelope creation |
| 25 | TRIAGE-25 | TODO | TRIAGE-01 | Frontend Guild | `VexHistoryComponent`: timeline of VEX decisions for current vuln |
| 26 | TRIAGE-26 | TODO | TRIAGE-25 | Frontend Guild | "Supersedes" relationship visualization in history |
| 27 | TRIAGE-27 | TODO | TRIAGE-01 | Frontend Guild | Bulk triage: select multiple vulns, apply same VEX decision |
| 28 | TRIAGE-28 | TODO | TRIAGE-27 | Frontend Guild | Bulk action confirmation modal with impact summary |
| 29 | TRIAGE-29 | TODO | TRIAGE-01 | Frontend Guild | `TriageQueueComponent`: prioritized queue for triage workflow |
| 30 | TRIAGE-30 | TODO | TRIAGE-29 | Frontend Guild | Auto-advance to next item after triage decision |
| 31 | TRIAGE-31 | TODO | TRIAGE-01 | Frontend Guild | Keyboard shortcuts: N(next), P(prev), M(mark not affected), A(analyze) |
| 32 | TRIAGE-32 | TODO | TRIAGE-01 | Frontend Guild | Responsive layout for tablet/desktop |
| 33 | TRIAGE-33 | TODO | All above | Frontend Guild | Unit tests for all triage components |
| 34 | TRIAGE-34 | TODO | TRIAGE-33 | Frontend Guild | E2E tests: complete triage workflow |
| 35 | TRIAGE-35 | TODO | TRIAGE-34 | Frontend Guild | Integration tests: VulnExplorer and AdvisoryAI API calls |
## AdvisoryAI Integration Points
```typescript
// API endpoints from AdvisoryAI.WebService
POST /api/v1/advisory/plan // Get AI analysis plan for vulnerability
POST /api/v1/advisory/execute // Execute AI analysis
GET /api/v1/advisory/output // Retrieve AI recommendations
// Frontend service
@Injectable({ providedIn: 'root' })
export class AdvisoryAiService {
getRecommendations(vulnId: string): Observable<AiRecommendation[]>;
requestAnalysis(vulnId: string, context: AnalysisContext): Observable<TaskId>;
getExplanation(vulnId: string, question: string): Observable<AiExplanation>;
}
```
## Competitor Parity Matrix
| Competitor Feature | Implementation |
|--------------------|----------------|
| Snyk reachability graphs | TRIAGE-12: ReachabilityContextComponent |
| Snyk AI prioritization | TRIAGE-14/15/16/17: AiRecommendationPanel |
| Anchore VEX annotations | TRIAGE-18-24: VexDecisionModalComponent |
| Anchore VEX export | Existing Excititor export (no new work) |
| Prisma runtime context | Future: integrate Signals module |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from "Triage UI Lessons from Competitors" analysis; implements unified triage canvas. | Project Mgmt |
## Decisions & Risks
- Decision needed: AI recommendation display format. Recommend: collapsible cards with confidence scores.
- Decision needed: Bulk triage limit. Recommend: 50 items max per bulk action.
- Decision needed: Triage queue algorithm. Recommend: priority by (KEV × severity × reachability).
- Risk: AdvisoryAI latency may slow triage. Mitigation: async loading, skeleton UI.
- Risk: VEX decision conflicts across users. Mitigation: optimistic locking with version check.
- Risk: Overwhelming information density. Mitigation: progressive disclosure, role-based defaults.
## Next Checkpoints
- 2026-01-08 | TRIAGE-13 complete | Core triage list and detail working |
- 2026-01-15 | TRIAGE-24 complete | VEX decisioning functional |
- 2026-01-20 | TRIAGE-35 complete | Full canvas with AI integration |

View File

@@ -0,0 +1,274 @@
# SPRINT_20251226_014_BINIDX_scanner_integration
> **Status:** TODO
> **Priority:** P1
> **Module:** BinaryIndex, Scanner
> **Created:** 2025-12-26
> **Depends On:** [`SPRINT_20251226_013_BINIDX_fingerprint_factory.md`](./SPRINT_20251226_013_BINIDX_fingerprint_factory.md)
> **Architecture:** [`docs/modules/binaryindex/architecture.md`](../modules/binaryindex/architecture.md), [`docs/modules/scanner/architecture.md`](../modules/scanner/architecture.md)
---
## Topic & Scope
Implement **Full Scanner Integration** - the fourth MVP tier that brings binary evidence into production scans with proper attestation and findings ledger integration.
**Goal:** Binary vulnerability matches appear in scan results with cryptographic evidence.
**Working directories:**
- `src/BinaryIndex/`
- `src/Scanner/`
- `src/Attestor/`
---
## Documentation Prerequisites
- `docs/modules/binaryindex/architecture.md`
- `docs/modules/scanner/architecture.md`
- `docs/modules/attestor/architecture.md`
- `src/Scanner/StellaOps.Scanner.Worker/`
---
## Delivery Tracker
| # | Task ID | Status | Depends | Owner | Description |
|---|---------|--------|---------|-------|-------------|
| 1 | SCANINT-01 | TODO | None | BE Guild | Add BinaryIndex service registration to Scanner.Worker |
| 2 | SCANINT-02 | TODO | SCANINT-01 | BE Guild | Create `IBinaryLookupStep` in scan pipeline |
| 3 | SCANINT-03 | TODO | SCANINT-02 | BE Guild | Implement binary extraction from container layers |
| 4 | SCANINT-04 | TODO | SCANINT-03 | BE Guild | Integrate `BinaryIdentityService` for identity extraction |
| 5 | SCANINT-05 | TODO | SCANINT-04 | BE Guild | Call `LookupByIdentityAsync` for each extracted binary |
| 6 | SCANINT-06 | TODO | SCANINT-05 | BE Guild | Call `GetFixStatusAsync` for distro-aware backport check |
| 7 | SCANINT-07 | TODO | SCANINT-05 | BE Guild | Call `LookupByFingerprintAsync` for fingerprint matching |
| 8 | SCANINT-08 | TODO | All | BE Guild | Create `BinaryFindingMapper` to convert matches to findings |
| 9 | SCANINT-09 | TODO | SCANINT-08 | BE Guild | Integrate with Findings Ledger for persistence |
| 10 | SCANINT-10 | TODO | None | BE Guild | Create `binary_fingerprint_evidence` proof segment type |
| 11 | SCANINT-11 | TODO | SCANINT-10 | BE Guild | Implement proof segment generation in Attestor |
| 12 | SCANINT-12 | TODO | SCANINT-11 | BE Guild | Sign binary evidence with DSSE |
| 13 | SCANINT-13 | TODO | SCANINT-12 | BE Guild | Attach binary attestation as OCI referrer |
| 14 | SCANINT-14 | TODO | None | CLI Guild | Add `stella binary inspect` CLI command |
| 15 | SCANINT-15 | TODO | SCANINT-14 | CLI Guild | Add `stella binary lookup <build-id>` command |
| 16 | SCANINT-16 | TODO | SCANINT-14 | CLI Guild | Add `stella binary fingerprint <file>` command |
| 17 | SCANINT-17 | TODO | None | FE Guild | Add "Binary Evidence" tab to scan results UI |
| 18 | SCANINT-18 | TODO | SCANINT-17 | FE Guild | Display "Backported & Safe" badge for fixed binaries |
| 19 | SCANINT-19 | TODO | SCANINT-17 | FE Guild | Display "Affected & Reachable" badge for vulnerable binaries |
| 20 | SCANINT-20 | TODO | All | BE Guild | Add performance benchmarks for binary lookup |
| 21 | SCANINT-21 | TODO | All | BE Guild | Add Valkey cache layer for hot lookups |
| 22 | SCANINT-22 | TODO | All | QA | Add E2E tests for complete scan with binary evidence |
| 23 | SCANINT-23 | TODO | All | QA | Add determinism tests for binary verdict reproducibility |
| 24 | SCANINT-24 | TODO | All | Docs | Update Scanner architecture with binary lookup flow |
| 25 | SCANINT-25 | TODO | All | Docs | Create binary evidence user guide |
**Total Tasks:** 25
---
## Task Details
### SCANINT-02: IBinaryLookupStep
Create pipeline step for binary vulnerability lookup during scan.
**Interface:**
```csharp
public interface IBinaryLookupStep : IScanPipelineStep
{
Task<BinaryLookupResult> LookupAsync(
ExtractedBinary binary,
ScanContext context,
CancellationToken ct);
}
public sealed record BinaryLookupResult(
BinaryIdentity Identity,
ImmutableArray<BinaryVulnMatch> Matches,
ImmutableArray<FixRecord> FixStatuses);
```
**Location:** `src/Scanner/StellaOps.Scanner.Worker/Pipeline/BinaryLookupStep.cs`
---
### SCANINT-03: Binary Extraction from Layers
Extract binaries from container image layers for analysis.
**Requirements:**
- Identify ELF/PE/Mach-O files in layers
- Skip small files (< 4KB)
- Limit to executable sections
- Track layer origin for provenance
**Performance Target:** < 100ms per binary extraction
---
### SCANINT-08: BinaryFindingMapper
Convert binary matches to standard findings format.
**Mapping:**
```csharp
public Finding MapToFinding(BinaryVulnMatch match, BinaryIdentity identity)
{
return new Finding
{
Id = GenerateFindingId(match, identity),
Type = FindingType.BinaryVulnerability,
Severity = GetSeverityFromCve(match.CveId),
Title = $"Binary contains vulnerable code: {match.CveId}",
Description = GenerateDescription(match),
Evidence = new BinaryFindingEvidence
{
BinaryKey = identity.BinaryKey,
BuildId = identity.BuildId,
MatchMethod = match.Method,
Confidence = match.Confidence
},
Remediation = GenerateRemediation(match)
};
}
```
---
### SCANINT-10: binary_fingerprint_evidence Proof Segment
Create new proof segment type for binary evidence.
**Schema:**
```json
{
"segment_type": "binary_fingerprint_evidence",
"version": "1.0.0",
"payload": {
"binary_identity": {
"format": "elf",
"build_id": "abc123...",
"file_sha256": "def456...",
"architecture": "x86_64"
},
"layer_digest": "sha256:...",
"matches": [
{
"cve_id": "CVE-2024-1234",
"method": "buildid_catalog",
"confidence": 0.98,
"vulnerable_purl": "pkg:deb/debian/libssl3@1.1.1n-0+deb11u3",
"fix_status": {
"state": "fixed",
"fixed_version": "1.1.1n-0+deb11u4",
"method": "changelog",
"confidence": 0.85
}
}
]
}
}
```
---
### SCANINT-14: CLI Binary Inspect Command
Add CLI commands for binary analysis.
**Commands:**
```bash
# Inspect binary identity
stella binary inspect /path/to/binary
# Output: Build-ID, hashes, architecture, format
# Lookup vulnerabilities by Build-ID
stella binary lookup abc123def456...
# Output: CVE matches, fix status
# Generate fingerprint for binary
stella binary fingerprint /path/to/binary --algorithm combined
# Output: Fingerprint ID, algorithm, hash
```
---
### SCANINT-17: Binary Evidence UI Tab
Add UI component for viewing binary evidence in scan results.
**Requirements:**
- List binaries found in image
- Show Build-ID, path, layer
- Display vulnerability matches with confidence
- Show backport status badges
- Drill-down to proof chain
---
### SCANINT-18-19: Status Badges
Display clear status badges for binary findings.
**Badge Types:**
| Badge | Color | Meaning |
|-------|-------|---------|
| Backported & Safe | Green | Distro backported the fix |
| Affected & Reachable | Red | Vulnerable and in code path |
| Affected (Low Priority) | Orange | Vulnerable but unreachable |
| Unknown | Gray | Could not determine status |
---
### SCANINT-21: Valkey Cache Layer
Add caching for frequently looked up binaries.
**Cache Strategy:**
- Key: `binary:{tenant}:{build_id}`
- TTL: 1 hour (configurable)
- Invalidate on corpus update
- Cache hit target: > 80% for repeat scans
---
## Acceptance Criteria
1. **Scanner pipeline** includes binary lookup step
2. **Binary findings** appear in scan results
3. **Proof segments** generated with DSSE signatures
4. **OCI attestation** attached to image
5. **CLI commands** work for binary analysis
6. **UI displays** binary evidence tab
7. **Status badges** show backport status
8. **Cache hit rate** > 80% for repeat scans
9. **E2E tests** pass for complete workflow
10. **Determinism tests** pass for reproducibility
---
## Decisions & Risks
| ID | Decision/Risk | Status | Notes |
|----|---------------|--------|-------|
| D1 | Binary lookup runs in parallel with package scan | DECIDED | No blocking |
| D2 | Default to buildid_catalog method first | DECIDED | Fastest path |
| R1 | Large images may have many binaries | OPEN | Add binary count limit (1000) |
| R2 | Cache invalidation on corpus update | OPEN | Use pub/sub notification |
| R3 | Performance impact on scan time | OPEN | Target < 5% overhead |
---
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2025-12-26 | Sprint created from BinaryIndex MVP roadmap. | Project Mgmt |
---
## Related Documentation
- [BinaryIndex Architecture](../modules/binaryindex/architecture.md)
- [Scanner Architecture](../modules/scanner/architecture.md)
- [Attestor Architecture](../modules/attestor/architecture.md)
- [Proof Chain Specification](../modules/attestor/proof-chain-specification.md)

View File

@@ -0,0 +1,124 @@
# Sprint 20251226 · Triage UI Advisory and Documentation Consolidation
## Topic & Scope
- Consolidate 3 overlapping triage/visualization advisories into unified documentation.
- Create authoritative "Unified Triage Experience" specification.
- Update smart-diff-ui-architecture.md to reflect current sprint structure.
- Archive original advisories with cross-reference preservation.
- **Working directory:** `docs/product-advisories/`, `docs/modules/web/`
## Dependencies & Concurrency
- No technical dependencies; documentation-only sprint.
- Can run in parallel with: SPRINT_20251226_012_FE, SPRINT_20251226_013_FE.
- Should reference implementation status from UI sprints.
## Documentation Prerequisites
- All source advisories (listed below)
- Existing web module docs:
- `docs/modules/web/smart-diff-ui-architecture.md`
- `docs/modules/web/README.md`
## Advisories to Consolidate
| Advisory | Primary Concepts | Keep Verbatim |
|----------|------------------|---------------|
| `25-Dec-2025 - Triage UI Lessons from Competitors.md` | Snyk/Anchore/Prisma analysis, 4 recommendations | Competitor feature matrix |
| `25-Dec-2025 - Visual Diffs for Explainable Triage.md` | Side-by-side panes, evidence strip, micro-interactions | Data model sketch, UI concept |
| `26-Dec-2026 - Visualizing the Risk Budget.md` | Burn-up charts, heatmaps, exception ledger | Chart design, compute formulas |
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | TDOC-01 | TODO | None | Project Mgmt | Create master document structure: `docs/modules/web/unified-triage-specification.md` |
| 2 | TDOC-02 | TODO | TDOC-01 | Project Mgmt | Merge competitor analysis section from "Triage UI Lessons" |
| 3 | TDOC-03 | TODO | TDOC-01 | Project Mgmt | Merge visual diff concepts from "Visual Diffs for Explainable Triage" |
| 4 | TDOC-04 | TODO | TDOC-01 | Project Mgmt | Merge risk budget visualization from "Visualizing the Risk Budget" |
| 5 | TDOC-05 | TODO | TDOC-04 | Project Mgmt | Add implementation status matrix (what exists vs gaps) |
| 6 | TDOC-06 | TODO | TDOC-05 | Project Mgmt | Map advisory concepts to sprint tasks (SPRINT_012, SPRINT_013, SPRINT_004) |
| 7 | TDOC-07 | TODO | TDOC-06 | Project Mgmt | Update `smart-diff-ui-architecture.md` sprint references to current format |
| 8 | TDOC-08 | TODO | TDOC-07 | Project Mgmt | Create archive directory: `archived/2025-12-26-triage-advisories/` |
| 9 | TDOC-09 | TODO | TDOC-08 | Project Mgmt | Move 3 original advisories to archive |
| 10 | TDOC-10 | TODO | TDOC-09 | Project Mgmt | Add README in archive explaining consolidation |
| 11 | TDOC-11 | TODO | TDOC-05 | Frontend Guild | Create `docs/modules/web/triage-component-catalog.md` |
| 12 | TDOC-12 | TODO | TDOC-11 | Frontend Guild | Document all triage-related Angular components and their relationships |
| 13 | TDOC-13 | TODO | TDOC-11 | Frontend Guild | Add component interaction diagrams |
| 14 | TDOC-14 | TODO | TDOC-09 | Project Mgmt | Update cross-references in `docs/modules/web/README.md` |
| 15 | TDOC-15 | TODO | TDOC-09 | Project Mgmt | Update cross-references in `docs/modules/vulnexplorer/` if exists |
| 16 | TDOC-16 | TODO | All above | Project Mgmt | Final review of consolidated documentation |
## Consolidated Document Structure
```markdown
# Unified Triage Experience Specification
## 1. Executive Summary
- Problem: Disparate triage tools, siloed insights
- Solution: Unified canvas with evidence, VEX, and AI
## 2. Competitive Landscape (from "Triage UI Lessons")
- Snyk: reachability + continuous context
- Anchore: vulnerability annotations + VEX export
- Prisma Cloud: runtime defense
- Stella Ops differentiation
## 3. Core UI Concepts (from "Visual Diffs")
- Side-by-side panes: Before vs After
- Graph focus: dependency/reachability subgraph
- Evidence strip: human-readable facts
- Diff verdict header
- Filter chips
## 4. Risk Budget Visualization (from "Visualizing Risk Budget")
- Heatmap of Unknowns
- Delta Table (Risk Decay per Release)
- Exception Ledger
- Burn-Up Chart specification
- Computation formulas
## 5. Implementation Components
- Smart-Diff Compare View (SPRINT_012_FE)
- Unified Triage Canvas (SPRINT_013_FE)
- Risk Dashboard (SPRINT_004_FE)
## 6. Data Models
- GraphSnapshot
- PolicySnapshot
- Delta
- EvidenceItems[]
- SignedDeltaVerdict
## 7. API Integration
- VulnExplorer endpoints
- AdvisoryAI endpoints
- Delta computation endpoints
## 8. Implementation Status
- Complete components
- In-progress sprints
- Planned work
## 9. Testing Strategy
- Unit tests
- E2E tests
- Accessibility tests
## 10. References
- Sprint links
- Archived advisories
```
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from advisory analysis; consolidates 3 overlapping triage/visualization advisories. | Project Mgmt |
## Decisions & Risks
- Decision: Archive location. Recommend: `archived/2025-12-26-triage-advisories/` with README.
- Decision: Keep smart-diff-ui-architecture.md or merge into unified spec. Recommend: Keep as reference, add link to unified spec.
- Risk: Broken cross-references after archival. Mitigation: grep all docs for advisory filenames before archiving.
- Risk: Loss of nuance from individual advisories. Mitigation: preserve verbatim sections as noted.
## Next Checkpoints
- 2025-12-28 | TDOC-06 complete | All content merged with sprint mapping |
- 2025-12-29 | TDOC-10 complete | Advisories archived |
- 2025-12-30 | TDOC-16 complete | Final review and publication |

View File

@@ -0,0 +1,75 @@
# Sprint 20251226 · Zastava Companion (Evidence-Grounded Explainability)
## Topic & Scope
- Build AI-powered explanation service that answers "What is it?", "Why it matters here?", "What evidence supports exploitability?"
- All explanations must be anchored to evidence nodes (SBOM, reachability, runtime, VEX, patches)
- Produce OCI-attached "Explanation Attestation" with inputs' hashes + model digest for replayability
- **Working directory:** `src/AdvisoryAI/`, `src/Attestor/`, `src/Web/`
## Dependencies & Concurrency
- Depends on: Existing AdvisoryAI pipeline infrastructure (COMPLETE).
- Depends on: ProofChain library for attestation generation (COMPLETE).
- Can run in parallel with: SPRINT_20251226_016_AI_remedy_autopilot.
## Documentation Prerequisites
- `src/AdvisoryAI/AGENTS.md`
- `docs/modules/attestor/proof-chain-specification.md`
- AI Assistant Advisory (this sprint's source)
## Context: What Already Exists
The following components are **already implemented**:
| Component | Location | Status |
|-----------|----------|--------|
| Pipeline Orchestrator | `AdvisoryAI/Orchestration/AdvisoryPipelineOrchestrator.cs` | COMPLETE |
| Guardrail Pipeline | `AdvisoryAI/Guardrails/AdvisoryGuardrailPipeline.cs` | COMPLETE |
| Inference Client | `AdvisoryAI/Inference/AdvisoryInferenceClient.cs` | COMPLETE |
| SBOM Context Retrieval | `AdvisoryAI/Retrievers/SbomContextRetriever.cs` | COMPLETE |
| Vector Retrieval | `AdvisoryAI/Retrievers/AdvisoryVectorRetriever.cs` | COMPLETE |
| Structured Retrieval | `AdvisoryAI/Retrievers/AdvisoryStructuredRetriever.cs` | COMPLETE |
| Citation Enforcement | `AdvisoryGuardrailPipeline` (RequireCitations) | COMPLETE |
| Proof Bundle Generation | `Policy/TrustLattice/ProofBundleBuilder.cs` | COMPLETE |
This sprint extends AdvisoryAI with explanation generation and attestation.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | ZASTAVA-01 | TODO | None | AdvisoryAI Guild | Define `ExplanationRequest` model: finding_id, artifact_digest, scope, explanation_type (what/why/evidence/counterfactual) |
| 2 | ZASTAVA-02 | TODO | ZASTAVA-01 | AdvisoryAI Guild | Create `IExplanationGenerator` interface with `GenerateAsync(ExplanationRequest)` |
| 3 | ZASTAVA-03 | TODO | ZASTAVA-02 | AdvisoryAI Guild | Implement `EvidenceAnchoredExplanationGenerator` that retrieves evidence nodes before LLM call |
| 4 | ZASTAVA-04 | TODO | ZASTAVA-03 | AdvisoryAI Guild | Create evidence retrieval service combining: SBOM context, reachability subgraph, runtime facts, VEX claims, patch metadata |
| 5 | ZASTAVA-05 | TODO | ZASTAVA-04 | AdvisoryAI Guild | Define prompt templates for each explanation type (what/why/evidence/counterfactual) |
| 6 | ZASTAVA-06 | TODO | ZASTAVA-04 | AdvisoryAI Guild | Implement evidence anchor extraction from LLM response (parse citations, validate against input evidence) |
| 7 | ZASTAVA-07 | TODO | ZASTAVA-06 | AdvisoryAI Guild | Create `ExplanationResult` model with: content, citations[], confidence, evidence_refs[], metadata |
| 8 | ZASTAVA-08 | TODO | None | Attestor Guild | Define `AIExplanation` predicate type for in-toto statement |
| 9 | ZASTAVA-09 | TODO | ZASTAVA-08 | Attestor Guild | Create `ExplanationAttestationBuilder` producing DSSE-wrapped explanation attestations |
| 10 | ZASTAVA-10 | TODO | ZASTAVA-09 | Attestor Guild | Add `application/vnd.stellaops.explanation+json` media type for OCI referrers |
| 11 | ZASTAVA-11 | TODO | ZASTAVA-07 | AdvisoryAI Guild | Implement replay manifest for explanations: input_hashes, prompt_template_version, model_digest, decoding_params |
| 12 | ZASTAVA-12 | TODO | ZASTAVA-09 | ExportCenter Guild | Push explanation attestations as OCI referrers via `OciReferrerPushClient` |
| 13 | ZASTAVA-13 | TODO | ZASTAVA-07 | WebService Guild | API endpoint `POST /api/v1/advisory/explain` returning ExplanationResult |
| 14 | ZASTAVA-14 | TODO | ZASTAVA-13 | WebService Guild | API endpoint `GET /api/v1/advisory/explain/{id}/replay` for re-running explanation with same inputs |
| 15 | ZASTAVA-15 | TODO | ZASTAVA-13 | FE Guild | "Explain" button component triggering explanation generation |
| 16 | ZASTAVA-16 | TODO | ZASTAVA-15 | FE Guild | Explanation panel showing: plain language explanation, linked evidence nodes, confidence indicator |
| 17 | ZASTAVA-17 | TODO | ZASTAVA-16 | FE Guild | Evidence drill-down: click citation → expand to full evidence node detail |
| 18 | ZASTAVA-18 | TODO | ZASTAVA-16 | FE Guild | Toggle: "Explain like I'm new" expanding jargon to plain language |
| 19 | ZASTAVA-19 | TODO | ZASTAVA-11 | Testing Guild | Integration tests: explanation generation with mocked LLM, evidence anchoring validation |
| 20 | ZASTAVA-20 | TODO | ZASTAVA-19 | Testing Guild | Golden tests: deterministic explanation replay produces identical output |
| 21 | ZASTAVA-21 | TODO | All above | Docs Guild | Document explanation API, attestation format, replay semantics |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from AI Assistant Advisory analysis; extends existing AdvisoryAI with explanation generation. | Project Mgmt |
## Decisions & Risks
- Decision needed: LLM model for explanations (Claude/GPT-4/Llama). Recommend: configurable, default to Claude for quality.
- Decision needed: Confidence thresholds for "Evidence-backed" vs "Suggestion-only" labels. Recommend: ≥80% citations valid → evidence-backed.
- Risk: LLM hallucinations. Mitigation: enforce citation validation; reject explanations with unanchored claims.
- Risk: Latency for real-time explanations. Mitigation: cache explanations by input hash; async generation for batch.
## Next Checkpoints
- 2025-12-30 | ZASTAVA-07 complete | Explanation generation service functional |
- 2026-01-03 | ZASTAVA-12 complete | OCI-attached attestations working |
- 2026-01-06 | ZASTAVA-21 complete | Full documentation and tests |

View File

@@ -0,0 +1,81 @@
# Sprint 20251226 · Remedy Autopilot (Safe PRs)
## Topic & Scope
- Build AI-powered remediation service that generates actionable fix plans (dependency bumps, base image upgrades, config changes, backport guidance)
- Implement automated PR generation with reproducible build verification, tests, SBOM delta, and signed delta verdict
- Fallback to "suggestion-only" when build/tests fail
- **Working directory:** `src/AdvisoryAI/`, `src/Policy/`, `src/Attestor/`, `src/__Libraries/StellaOps.DeltaVerdict/`
## Dependencies & Concurrency
- Depends on: DeltaVerdict library (COMPLETE).
- Depends on: Existing RemediationHintsRegistry (COMPLETE).
- Depends on: ZASTAVA Companion for explanation generation (can run in parallel).
- Can run in parallel with: SPRINT_20251226_017_AI_policy_copilot.
## Documentation Prerequisites
- `src/Policy/__Libraries/StellaOps.Policy.Unknowns/Services/RemediationHintsRegistry.cs`
- `src/__Libraries/StellaOps.DeltaVerdict/` (delta computation)
- AI Assistant Advisory (this sprint's source)
## Context: What Already Exists
The following components are **already implemented**:
| Component | Location | Status |
|-----------|----------|--------|
| Remediation Hints Registry | `Policy.Unknowns/Services/RemediationHintsRegistry.cs` | COMPLETE |
| Delta Computation Engine | `StellaOps.DeltaVerdict/DeltaComputationEngine.cs` | COMPLETE |
| Delta Signing Service | `StellaOps.DeltaVerdict/Signing/DeltaSigningService.cs` | COMPLETE |
| SBOM Diff | `SbomService` lineage tracking | COMPLETE |
| Attestor DSSE | `Attestor.ProofChain/Signing/ProofChainSigner.cs` | COMPLETE |
| AdvisoryAI Pipeline | `AdvisoryAI/Orchestration/AdvisoryPipelineOrchestrator.cs` | COMPLETE |
This sprint extends the system with AI-generated remediation plans and automated PR integration.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | REMEDY-01 | TODO | None | AdvisoryAI Guild | Define `RemediationPlanRequest` model: finding_id, artifact_digest, remediation_type (bump/upgrade/config/backport) |
| 2 | REMEDY-02 | TODO | REMEDY-01 | AdvisoryAI Guild | Create `IRemediationPlanner` interface with `GeneratePlanAsync(RemediationPlanRequest)` |
| 3 | REMEDY-03 | TODO | REMEDY-02 | AdvisoryAI Guild | Implement `AiRemediationPlanner` using LLM with package registry context (npm, PyPI, NuGet, Maven) |
| 4 | REMEDY-04 | TODO | REMEDY-03 | AdvisoryAI Guild | Create package version resolver service to validate upgrade paths (check compatibility, breaking changes) |
| 5 | REMEDY-05 | TODO | REMEDY-04 | AdvisoryAI Guild | Define `RemediationPlan` model: steps[], expected_sbom_delta, risk_assessment, test_requirements |
| 6 | REMEDY-06 | TODO | None | Attestor Guild | Define `RemediationPlan` predicate type for in-toto statement |
| 7 | REMEDY-07 | TODO | REMEDY-06 | Attestor Guild | Create `RemediationPlanAttestationBuilder` for DSSE-wrapped plans |
| 8 | REMEDY-08 | TODO | REMEDY-05 | Integration Guild | Define `IPullRequestGenerator` interface for SCM integration |
| 9 | REMEDY-09 | TODO | REMEDY-08 | Integration Guild | Implement `GitHubPullRequestGenerator` for GitHub repositories |
| 10 | REMEDY-10 | TODO | REMEDY-08 | Integration Guild | Implement `GitLabMergeRequestGenerator` for GitLab repositories |
| 11 | REMEDY-11 | TODO | REMEDY-08 | Integration Guild | Implement `AzureDevOpsPullRequestGenerator` for Azure DevOps |
| 12 | REMEDY-12 | TODO | REMEDY-09 | Integration Guild | PR branch creation with remediation changes (package updates, config modifications) |
| 13 | REMEDY-13 | TODO | REMEDY-12 | Integration Guild | Build verification: trigger CI pipeline, capture build result |
| 14 | REMEDY-14 | TODO | REMEDY-13 | Integration Guild | Test verification: run test suite, capture pass/fail counts |
| 15 | REMEDY-15 | TODO | REMEDY-14 | DeltaVerdict Guild | SBOM delta computation: compare pre/post remediation SBOMs |
| 16 | REMEDY-16 | TODO | REMEDY-15 | DeltaVerdict Guild | Generate signed delta verdict for remediation PR |
| 17 | REMEDY-17 | TODO | REMEDY-16 | Integration Guild | PR description generator: include SBOM delta summary, delta verdict, risk assessment |
| 18 | REMEDY-18 | TODO | REMEDY-14 | AdvisoryAI Guild | Fallback logic: if build/tests fail, mark as "suggestion-only" with failure reason |
| 19 | REMEDY-19 | TODO | REMEDY-17 | WebService Guild | API endpoint `POST /api/v1/remediation/plan` returning RemediationPlan |
| 20 | REMEDY-20 | TODO | REMEDY-19 | WebService Guild | API endpoint `POST /api/v1/remediation/apply` triggering PR generation |
| 21 | REMEDY-21 | TODO | REMEDY-20 | WebService Guild | API endpoint `GET /api/v1/remediation/status/{pr_id}` for tracking PR status |
| 22 | REMEDY-22 | TODO | REMEDY-19 | FE Guild | "Auto-fix" button component initiating remediation workflow |
| 23 | REMEDY-23 | TODO | REMEDY-22 | FE Guild | Remediation plan preview: show proposed changes, expected delta, risk assessment |
| 24 | REMEDY-24 | TODO | REMEDY-23 | FE Guild | PR status tracker: build status, test results, delta verdict badge |
| 25 | REMEDY-25 | TODO | REMEDY-18 | Testing Guild | Integration tests: plan generation, PR creation (mocked SCM), fallback handling |
| 26 | REMEDY-26 | TODO | All above | Docs Guild | Document remediation API, SCM integration setup, delta verdict semantics |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from AI Assistant Advisory analysis; builds on existing RemediationHintsRegistry and DeltaVerdict. | Project Mgmt |
## Decisions & Risks
- Decision needed: SCM authentication (OAuth, PAT, GitHub App). Recommend: OAuth for UI, PAT for CLI, GitHub App for org-wide.
- Decision needed: Auto-merge policy. Recommend: never auto-merge; always require human approval.
- Decision needed: Breaking change detection threshold. Recommend: flag any major version bump as "needs review".
- Risk: Generated changes may introduce new vulnerabilities. Mitigation: always run full scan on remediation branch before PR.
- Risk: CI pipeline costs. Mitigation: limit to 3 remediation attempts per finding; require approval for more.
- Risk: Repository access scope creep. Mitigation: request minimum permissions; audit access logs.
## Next Checkpoints
- 2025-12-30 | REMEDY-05 complete | Remediation plan generation functional |
- 2026-01-03 | REMEDY-17 complete | PR generation with delta verdicts working |
- 2026-01-06 | REMEDY-26 complete | Full documentation and SCM integrations |

View File

@@ -0,0 +1,80 @@
# Sprint 20251226 · Policy Studio Copilot (NL → Lattice Rules)
## Topic & Scope
- Build AI-powered policy authoring that converts natural language intent to lattice rules
- Generate test cases for policy validation
- Compile to deterministic policy code with signed policy snapshots
- **Working directory:** `src/AdvisoryAI/`, `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/`, `src/Web/`
## Dependencies & Concurrency
- Depends on: TrustLatticeEngine and K4Lattice (COMPLETE).
- Depends on: PolicyBundle compilation (COMPLETE).
- Can run in parallel with: SPRINT_20251226_015_AI_zastava_companion.
## Documentation Prerequisites
- `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/TrustLatticeEngine.cs`
- `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/K4Lattice.cs`
- AI Assistant Advisory (this sprint's source)
## Context: What Already Exists
The following components are **already implemented**:
| Component | Location | Status |
|-----------|----------|--------|
| K4 Lattice | `Policy/TrustLattice/K4Lattice.cs` | COMPLETE |
| Trust Lattice Engine | `Policy/TrustLattice/TrustLatticeEngine.cs` | COMPLETE |
| Policy Bundle | `Policy/TrustLattice/PolicyBundle.cs` | COMPLETE |
| Disposition Selector | `Policy/TrustLattice/DispositionSelector.cs` | COMPLETE |
| Security Atoms | Present, Applies, Reachable, Mitigated, Fixed, Misattributed | COMPLETE |
| Proof Bundle Generation | `Policy/TrustLattice/ProofBundleBuilder.cs` | COMPLETE |
| VEX Normalizers | CycloneDX, OpenVEX, CSAF | COMPLETE |
This sprint adds NL→rule conversion, test synthesis, and an interactive policy authoring UI.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | POLICY-01 | TODO | None | AdvisoryAI Guild | Define policy intent taxonomy: override_rules, escalation_rules, exception_conditions, merge_precedence |
| 2 | POLICY-02 | TODO | POLICY-01 | AdvisoryAI Guild | Create `IPolicyIntentParser` interface with `ParseAsync(natural_language_input)` |
| 3 | POLICY-03 | TODO | POLICY-02 | AdvisoryAI Guild | Implement `AiPolicyIntentParser` using LLM with few-shot examples of valid policy intents |
| 4 | POLICY-04 | TODO | POLICY-03 | AdvisoryAI Guild | Define `PolicyIntent` model: intent_type, conditions[], actions[], scope, priority |
| 5 | POLICY-05 | TODO | POLICY-04 | Policy Guild | Create `IPolicyRuleGenerator` interface converting PolicyIntent to lattice rules |
| 6 | POLICY-06 | TODO | POLICY-05 | Policy Guild | Implement `LatticeRuleGenerator` producing K4Lattice-compatible rule definitions |
| 7 | POLICY-07 | TODO | POLICY-06 | Policy Guild | Rule validation: check for conflicts, unreachable conditions, infinite loops |
| 8 | POLICY-08 | TODO | POLICY-06 | Testing Guild | Create `ITestCaseSynthesizer` interface for generating policy test cases |
| 9 | POLICY-09 | TODO | POLICY-08 | Testing Guild | Implement `PropertyBasedTestSynthesizer` generating edge-case inputs for policy validation |
| 10 | POLICY-10 | TODO | POLICY-09 | Testing Guild | Generate positive tests: inputs that should match the rule and produce expected disposition |
| 11 | POLICY-11 | TODO | POLICY-09 | Testing Guild | Generate negative tests: inputs that should NOT match (boundary conditions) |
| 12 | POLICY-12 | TODO | POLICY-10 | Testing Guild | Generate conflict tests: inputs that trigger multiple conflicting rules |
| 13 | POLICY-13 | TODO | POLICY-07 | Policy Guild | Policy compilation: bundle rules into versioned, signed PolicyBundle |
| 14 | POLICY-14 | TODO | POLICY-13 | Attestor Guild | Define `PolicyDraft` predicate type for in-toto statement |
| 15 | POLICY-15 | TODO | POLICY-14 | Attestor Guild | Create `PolicyDraftAttestationBuilder` for DSSE-wrapped policy snapshots |
| 16 | POLICY-16 | TODO | POLICY-13 | WebService Guild | API endpoint `POST /api/v1/policy/studio/parse` for NL→intent parsing |
| 17 | POLICY-17 | TODO | POLICY-16 | WebService Guild | API endpoint `POST /api/v1/policy/studio/generate` for intent→rule generation |
| 18 | POLICY-18 | TODO | POLICY-17 | WebService Guild | API endpoint `POST /api/v1/policy/studio/validate` for rule validation with test cases |
| 19 | POLICY-19 | TODO | POLICY-18 | WebService Guild | API endpoint `POST /api/v1/policy/studio/compile` for final policy compilation |
| 20 | POLICY-20 | TODO | POLICY-16 | FE Guild | Policy Studio UI: natural language input panel with autocomplete for policy entities |
| 21 | POLICY-21 | TODO | POLICY-20 | FE Guild | Live preview: show generated rules as user types, highlight syntax |
| 22 | POLICY-22 | TODO | POLICY-21 | FE Guild | Test case panel: show generated tests, allow manual additions, run validation |
| 23 | POLICY-23 | TODO | POLICY-22 | FE Guild | Conflict visualizer: highlight conflicting rules with resolution suggestions |
| 24 | POLICY-24 | TODO | POLICY-23 | FE Guild | Version history: show policy versions, diff between versions |
| 25 | POLICY-25 | TODO | POLICY-12 | Testing Guild | Integration tests: NL→rule→test round-trip, conflict detection |
| 26 | POLICY-26 | TODO | All above | Docs Guild | Document Policy Studio API, rule syntax, test case format |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from AI Assistant Advisory analysis; extends TrustLatticeEngine with AI policy authoring. | Project Mgmt |
## Decisions & Risks
- Decision needed: Policy DSL format (YAML, JSON, custom syntax). Recommend: YAML for readability, JSON for API.
- Decision needed: Maximum rule complexity. Recommend: limit to 10 conditions per rule initially.
- Decision needed: Approval workflow for policy changes. Recommend: require 2 approvers for production policies.
- Risk: Generated rules may have unintended consequences. Mitigation: mandatory test coverage, dry-run mode.
- Risk: NL ambiguity leading to wrong rules. Mitigation: clarifying questions in UI, explicit examples.
## Next Checkpoints
- 2025-12-30 | POLICY-07 complete | NL→rule generation functional |
- 2026-01-03 | POLICY-15 complete | Policy compilation with attestations |
- 2026-01-06 | POLICY-26 complete | Full Policy Studio with tests |

View File

@@ -0,0 +1,78 @@
# Sprint 20251226 · AI Artifact Attestations
## Topic & Scope
- Define and implement standardized attestation types for all AI-generated artifacts
- Ensure all AI outputs are replayable, inspectable, and clearly marked as Suggestion-only vs Evidence-backed
- Integrate with existing ProofChain infrastructure for OCI attachment
- **Working directory:** `src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/`, `src/ExportCenter/`
## Dependencies & Concurrency
- Depends on: ProofChain library (COMPLETE).
- Depends on: OCI Referrer infrastructure (COMPLETE).
- Should run before or in parallel with: SPRINT_20251226_015/016/017 (AI feature sprints use these attestation types).
## Documentation Prerequisites
- `docs/modules/attestor/proof-chain-specification.md`
- `src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/Statements/`
- AI Assistant Advisory (this sprint's source)
## Context: What Already Exists
The following predicate types are **already implemented**:
| Predicate | Type URI | Status |
|-----------|----------|--------|
| Build Provenance | `StellaOps.BuildProvenance@1` | COMPLETE |
| SBOM Attestation | `StellaOps.SBOMAttestation@1` | COMPLETE |
| Scan Results | `StellaOps.ScanResults@1` | COMPLETE |
| Policy Evaluation | `StellaOps.PolicyEvaluation@1` | COMPLETE |
| VEX Attestation | `StellaOps.VEXAttestation@1` | COMPLETE |
| Risk Profile Evidence | `StellaOps.RiskProfileEvidence@1` | COMPLETE |
| Reachability Witness | `StellaOps.ReachabilityWitness@1` | COMPLETE |
| Reachability Subgraph | `StellaOps.ReachabilitySubgraph@1` | COMPLETE |
| Proof Spine | `StellaOps.ProofSpine@1` | COMPLETE |
This sprint adds AI-specific predicate types with replay metadata.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | AIATTEST-01 | TODO | None | Attestor Guild | Define `AIArtifactBase` predicate structure: model_id, weights_digest, prompt_template_version, decoding_params, inputs_hashes[] |
| 2 | AIATTEST-02 | TODO | AIATTEST-01 | Attestor Guild | Define `AIExplanation` predicate: extends AIArtifactBase + explanation_type, content, citations[], confidence_score |
| 3 | AIATTEST-03 | TODO | AIATTEST-01 | Attestor Guild | Define `AIRemediationPlan` predicate: extends AIArtifactBase + steps[], expected_delta, risk_assessment, verification_status |
| 4 | AIATTEST-04 | TODO | AIATTEST-01 | Attestor Guild | Define `AIVexDraft` predicate: extends AIArtifactBase + vex_statements[], justifications[], evidence_refs[] |
| 5 | AIATTEST-05 | TODO | AIATTEST-01 | Attestor Guild | Define `AIPolicyDraft` predicate: extends AIArtifactBase + rules[], test_cases[], validation_result |
| 6 | AIATTEST-06 | TODO | AIATTEST-01 | Attestor Guild | Define `AIArtifactAuthority` enum: Suggestion, EvidenceBacked, AuthorityThreshold (configurable threshold for each) |
| 7 | AIATTEST-07 | TODO | AIATTEST-06 | Attestor Guild | Authority classifier: rules for when artifact qualifies as EvidenceBacked (citation rate ≥ X, evidence refs valid, etc.) |
| 8 | AIATTEST-08 | TODO | AIATTEST-02 | ProofChain Guild | Implement `AIExplanationStatement` in ProofChain |
| 9 | AIATTEST-09 | TODO | AIATTEST-03 | ProofChain Guild | Implement `AIRemediationPlanStatement` in ProofChain |
| 10 | AIATTEST-10 | TODO | AIATTEST-04 | ProofChain Guild | Implement `AIVexDraftStatement` in ProofChain |
| 11 | AIATTEST-11 | TODO | AIATTEST-05 | ProofChain Guild | Implement `AIPolicyDraftStatement` in ProofChain |
| 12 | AIATTEST-12 | TODO | AIATTEST-08 | OCI Guild | Register `application/vnd.stellaops.ai.explanation+json` media type |
| 13 | AIATTEST-13 | TODO | AIATTEST-09 | OCI Guild | Register `application/vnd.stellaops.ai.remediation+json` media type |
| 14 | AIATTEST-14 | TODO | AIATTEST-10 | OCI Guild | Register `application/vnd.stellaops.ai.vexdraft+json` media type |
| 15 | AIATTEST-15 | TODO | AIATTEST-11 | OCI Guild | Register `application/vnd.stellaops.ai.policydraft+json` media type |
| 16 | AIATTEST-16 | TODO | AIATTEST-12 | ExportCenter Guild | Implement AI attestation push via `OciReferrerPushClient` |
| 17 | AIATTEST-17 | TODO | AIATTEST-16 | ExportCenter Guild | Implement AI attestation discovery via `OciReferrerDiscovery` |
| 18 | AIATTEST-18 | TODO | AIATTEST-01 | Replay Guild | Create `AIArtifactReplayManifest` capturing all inputs for deterministic replay |
| 19 | AIATTEST-19 | TODO | AIATTEST-18 | Replay Guild | Implement `IAIArtifactReplayer` for re-executing AI generation with pinned inputs |
| 20 | AIATTEST-20 | TODO | AIATTEST-19 | Replay Guild | Replay verification: compare output hash with original, flag divergence |
| 21 | AIATTEST-21 | TODO | AIATTEST-20 | Verification Guild | Add AI artifact verification to `VerificationPipeline` |
| 22 | AIATTEST-22 | TODO | All above | Testing Guild | Integration tests: attestation creation, OCI push/pull, replay verification |
| 23 | AIATTEST-23 | TODO | All above | Docs Guild | Document AI attestation schemas, replay semantics, authority classification |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from AI Assistant Advisory analysis; extends ProofChain with AI-specific attestation types. | Project Mgmt |
## Decisions & Risks
- Decision needed: Model digest format (SHA-256 of weights, version string, provider+model). Recommend: provider:model:version for cloud, SHA-256 for local.
- Decision needed: Evidence-backed threshold. Recommend: ≥80% citations valid AND all evidence_refs resolvable.
- Risk: Model version drift between attestation and replay. Mitigation: fail replay if model unavailable; document fallback.
- Risk: Large attestation sizes. Mitigation: store evidence refs, not full content; link to evidence locker.
## Next Checkpoints
- 2025-12-30 | AIATTEST-07 complete | All predicate types defined |
- 2026-01-03 | AIATTEST-17 complete | OCI integration working |
- 2026-01-06 | AIATTEST-23 complete | Full documentation and replay verification |

View File

@@ -0,0 +1,91 @@
# Sprint 20251226 · Sovereign/Offline AI Inference
## Topic & Scope
- Ship a local inference profile with permissive-license weights and pinned digests
- Enable full AI feature replay in air-gapped environments
- Support regional crypto requirements (eIDAS/FIPS/GOST/SM) for AI attestation signing
- **Working directory:** `src/AdvisoryAI/`, `src/Cryptography/`, `etc/`
## Dependencies & Concurrency
- Depends on: AdvisoryAI inference client (COMPLETE).
- Depends on: Cryptography module with regional crypto (COMPLETE).
- Depends on: SPRINT_20251226_018_AI_attestations (attestation types for replay).
- Can run in parallel with: SPRINT_20251226_015/016/017 (uses local inference as fallback).
## Documentation Prerequisites
- `src/AdvisoryAI/StellaOps.AdvisoryAI/Inference/AdvisoryInferenceClient.cs`
- `src/Cryptography/` (regional crypto plugins)
- `docs/24_OFFLINE_KIT.md`
- AI Assistant Advisory (this sprint's source)
## Context: What Already Exists
The following components are **already implemented**:
| Component | Location | Status |
|-----------|----------|--------|
| Local Inference Client | `AdvisoryAI/Inference/LocalAdvisoryInferenceClient.cs` | COMPLETE (stub) |
| Remote Inference Client | `AdvisoryAI/Inference/RemoteAdvisoryInferenceClient.cs` | COMPLETE |
| Inference Mode Config | `AdvisoryAiInferenceMode.Local/Remote` | COMPLETE |
| Regional Crypto | `src/Cryptography/` (eIDAS, FIPS, GOST, SM) | COMPLETE |
| Air-gap Support | `AirgapOptions`, `AirgapModeEnforcer` | COMPLETE |
| Replay Manifest | `StellaOps.Replay.Core/ReplayManifest.cs` | COMPLETE |
This sprint extends the local inference stub to full local LLM execution with offline-compatible features.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | OFFLINE-01 | TODO | None | AdvisoryAI Guild | Evaluate permissive-license LLM options: Llama 3, Mistral, Phi-3, Qwen2, Gemma 2 |
| 2 | OFFLINE-02 | TODO | OFFLINE-01 | AdvisoryAI Guild | Define model selection criteria: license (Apache/MIT/permissive), size (<30GB), performance, multilingual |
| 3 | OFFLINE-03 | TODO | OFFLINE-02 | AdvisoryAI Guild | Create `LocalLlmConfig` model: model_path, weights_digest, quantization, context_length, device (CPU/GPU/NPU) |
| 4 | OFFLINE-04 | TODO | OFFLINE-03 | AdvisoryAI Guild | Implement `ILocalLlmRuntime` interface for local model execution |
| 5 | OFFLINE-05 | TODO | OFFLINE-04 | AdvisoryAI Guild | Implement `LlamaCppRuntime` using llama.cpp bindings for CPU/GPU inference |
| 6 | OFFLINE-06 | TODO | OFFLINE-04 | AdvisoryAI Guild | Implement `OnnxRuntime` option for ONNX-exported models |
| 7 | OFFLINE-07 | TODO | OFFLINE-05 | AdvisoryAI Guild | Replace `LocalAdvisoryInferenceClient` stub with actual local LLM inference |
| 8 | OFFLINE-08 | TODO | OFFLINE-07 | AdvisoryAI Guild | Implement model loading with digest verification (SHA-256 of weights file) |
| 9 | OFFLINE-09 | TODO | OFFLINE-08 | AdvisoryAI Guild | Add inference caching: cache responses by input hash for deterministic replay |
| 10 | OFFLINE-10 | TODO | OFFLINE-09 | AdvisoryAI Guild | Implement temperature=0, fixed seed for deterministic outputs |
| 11 | OFFLINE-11 | TODO | None | Packaging Guild | Create offline model bundle packaging: weights + tokenizer + config + digest manifest |
| 12 | OFFLINE-12 | TODO | OFFLINE-11 | Packaging Guild | Define bundle format: tar.gz with manifest.json listing all files + digests |
| 13 | OFFLINE-13 | TODO | OFFLINE-12 | Packaging Guild | Implement `stella model pull --offline` CLI for downloading model bundles |
| 14 | OFFLINE-14 | TODO | OFFLINE-13 | Packaging Guild | Implement `stella model verify` CLI for verifying bundle integrity |
| 15 | OFFLINE-15 | TODO | OFFLINE-08 | Crypto Guild | Sign model bundles with regional crypto (allow eIDAS/FIPS/GOST/SM keys) |
| 16 | OFFLINE-16 | TODO | OFFLINE-15 | Crypto Guild | Verify model bundle signatures at load time |
| 17 | OFFLINE-17 | TODO | OFFLINE-10 | Replay Guild | Extend `AIArtifactReplayManifest` with local model info: path, digest, quantization |
| 18 | OFFLINE-18 | TODO | OFFLINE-17 | Replay Guild | Implement offline replay: re-run AI generation using local model bundle |
| 19 | OFFLINE-19 | TODO | OFFLINE-18 | Replay Guild | Divergence detection: flag when local and remote models produce different outputs for same input |
| 20 | OFFLINE-20 | TODO | OFFLINE-07 | Performance Guild | Benchmark local inference: throughput (tokens/sec), latency (first token, total), memory |
| 21 | OFFLINE-21 | TODO | OFFLINE-20 | Performance Guild | Optimize for low-memory environments: streaming, quantization, model sharding |
| 22 | OFFLINE-22 | TODO | OFFLINE-16 | Airgap Guild | Integrate with existing `AirgapModeEnforcer`: auto-select local inference in airgap mode |
| 23 | OFFLINE-23 | TODO | OFFLINE-22 | Airgap Guild | Document model bundle transfer for air-gapped environments (USB, sneakernet) |
| 24 | OFFLINE-24 | TODO | OFFLINE-22 | Config Guild | Add config: `AdvisoryAI:Inference:OfflineBundle:Path`, `AdvisoryAI:Inference:OfflineBundle:RequiredDigest` |
| 25 | OFFLINE-25 | TODO | All above | Testing Guild | Integration tests: local inference, bundle verification, offline replay |
| 26 | OFFLINE-26 | TODO | All above | Docs Guild | Document offline AI setup, model bundle format, performance tuning |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-26 | Sprint created from AI Assistant Advisory analysis; enables sovereign AI inference for air-gapped environments. | Project Mgmt |
## Decisions & Risks
- Decision needed: Primary model choice. Recommend: Llama 3 8B (Apache 2.0, good quality/size balance).
- Decision needed: Quantization level. Recommend: Q4_K_M for CPU, FP16 for GPU.
- Decision needed: Bundle distribution. Recommend: separate download, not in main installer.
- Risk: Model quality degradation with small models. Mitigation: tune prompts for local models; fallback to templates.
- Risk: High resource requirements. Mitigation: offer multiple model sizes; document minimum specs.
- Risk: GPU compatibility. Mitigation: CPU fallback always available; test on common hardware.
## Hardware Requirements (Documented)
| Model Size | RAM | GPU VRAM | CPU Cores | Inference Speed |
|------------|-----|----------|-----------|-----------------|
| 7-8B Q4 | 8GB | N/A (CPU) | 4+ | ~10 tokens/sec |
| 7-8B FP16 | 16GB | 8GB | N/A | ~50 tokens/sec |
| 13B Q4 | 16GB | N/A (CPU) | 8+ | ~5 tokens/sec |
| 13B FP16 | 32GB | 16GB | N/A | ~30 tokens/sec |
## Next Checkpoints
- 2025-12-30 | OFFLINE-07 complete | Local LLM inference functional |
- 2026-01-03 | OFFLINE-16 complete | Signed model bundles with regional crypto |
- 2026-01-06 | OFFLINE-26 complete | Full documentation and offline replay |

View File

@@ -0,0 +1,273 @@
# Keyless Signing Guide
## Overview
Keyless signing uses ephemeral X.509 certificates from Sigstore Fulcio, eliminating the need for persistent signing keys. This approach is ideal for CI/CD pipelines where key management is complex and error-prone.
### How It Works
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ CI Pipeline │────▶│ OIDC Provider│────▶│ Fulcio │────▶│ Rekor │
│ │ │ (GitHub/GL) │ │ (Sigstore) │ │ (Sigstore) │
│ 1. Get token │ │ 2. Issue JWT │ │ 3. Issue cert│ │ 4. Log entry │
│ │ │ (5 min) │ │ (10 min) │ │ (permanent) │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│ │
│ │
└───────────── Attestation with cert + Rekor proof ───────────┘
```
1. **OIDC Token**: Pipeline requests identity token from CI platform
2. **Fulcio Certificate**: Token exchanged for short-lived signing certificate (~10 min)
3. **Ephemeral Key**: Private key exists only in memory during signing
4. **Rekor Logging**: Signature logged to transparency log for verification after cert expiry
### Key Benefits
| Benefit | Description |
|---------|-------------|
| **Zero Key Management** | No secrets to rotate, store, or protect |
| **Identity Binding** | Signatures tied to OIDC identity (repo, branch, workflow) |
| **Audit Trail** | All signatures logged to Rekor transparency log |
| **Short-lived Certs** | Minimizes exposure window (~10 minutes) |
| **Industry Standard** | Adopted by Kubernetes, npm, PyPI, and major ecosystems |
## Quick Start
### Prerequisites
1. StellaOps CLI installed
2. CI platform with OIDC support (GitHub Actions, GitLab CI, Gitea)
3. Network access to Fulcio and Rekor (or private instances)
### GitHub Actions Example
```yaml
name: Sign Container Image
on:
push:
branches: [main]
jobs:
build-and-sign:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Build and Push Image
id: build
run: |
docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
echo "digest=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/${{ github.repository }}:${{ github.sha }} | cut -d@ -f2)" >> $GITHUB_OUTPUT
- name: Keyless Sign
uses: stella-ops/sign-action@v1
with:
artifact-digest: ${{ steps.build.outputs.digest }}
artifact-type: image
```
### CLI Usage
```bash
# Sign with ambient OIDC token (in CI environment)
stella attest sign --keyless --artifact sha256:abc123...
# Sign with explicit token
STELLAOPS_OIDC_TOKEN="..." stella attest sign --keyless --artifact sha256:abc123...
# Verify signature (checks Rekor proof)
stella attest verify \
--artifact sha256:abc123... \
--certificate-identity "repo:myorg/myrepo:ref:refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
```
## Configuration
### Signer Configuration
```yaml
# etc/signer.yaml
signer:
signing:
mode: "keyless"
keyless:
enabled: true
fulcio:
url: "https://fulcio.sigstore.dev"
timeout: 30s
retries: 3
oidc:
issuer: "https://authority.internal"
clientId: "signer-keyless"
useAmbientToken: true
algorithms:
preferred: "ECDSA_P256"
allowed: ["ECDSA_P256", "Ed25519"]
certificate:
rootBundlePath: "/etc/stellaops/fulcio-roots.pem"
validateChain: true
requireSCT: true
```
### Private Fulcio Instance
For air-gapped or high-security environments, deploy a private Fulcio instance:
```yaml
signer:
signing:
keyless:
fulcio:
url: "https://fulcio.internal.example.com"
oidc:
issuer: "https://keycloak.internal.example.com/realms/stellaops"
certificate:
rootBundlePath: "/etc/stellaops/private-fulcio-roots.pem"
```
## Identity Verification
### Identity Constraints
When verifying signatures, specify which identities are trusted:
```bash
stella attest verify \
--artifact sha256:abc123... \
--certificate-identity "repo:myorg/myrepo:ref:refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
```
### Platform Identity Patterns
#### GitHub Actions
| Pattern | Matches |
|---------|---------|
| `repo:org/repo:.*` | Any ref in repository |
| `repo:org/repo:ref:refs/heads/main` | Main branch only |
| `repo:org/repo:ref:refs/tags/v.*` | Version tags |
| `repo:org/repo:environment:production` | Production environment |
**Issuer:** `https://token.actions.githubusercontent.com`
#### GitLab CI
| Pattern | Matches |
|---------|---------|
| `project_path:group/project:.*` | Any ref in project |
| `project_path:group/project:ref_type:branch:ref:main` | Main branch |
| `project_path:group/project:ref_protected:true` | Protected refs only |
**Issuer:** `https://gitlab.com` (or self-hosted URL)
## Long-Term Verification
### The Problem
Fulcio certificates expire in ~10 minutes. How do you verify signatures months later?
### The Solution: Rekor Proofs
```
At signing time:
┌──────────────────────────────────────────────────────────────┐
│ Signature + Certificate + Signed-Certificate-Timestamp (SCT) │
│ ↓ │
│ Logged to Rekor │
│ ↓ │
│ Merkle Inclusion Proof returned │
└──────────────────────────────────────────────────────────────┘
At verification time (even years later):
┌──────────────────────────────────────────────────────────────┐
│ 1. Check signature is valid (using cert public key) │
│ 2. Check SCT proves cert was logged when valid │
│ 3. Check Rekor inclusion proof (entry was logged) │
│ 4. Check signing time was within cert validity window │
│ ↓ │
│ Signature is valid! ✓ │
└──────────────────────────────────────────────────────────────┘
```
### Attestation Bundles
For air-gapped verification, StellaOps bundles attestations with proofs:
```bash
# Export bundle with Rekor proofs
stella attest export-bundle \
--image sha256:abc123... \
--include-proofs \
--output attestation-bundle.json
# Verify offline
stella attest verify --offline \
--bundle attestation-bundle.json \
--artifact sha256:abc123...
```
## Troubleshooting
### Common Errors
| Error | Cause | Solution |
|-------|-------|----------|
| `OIDC token expired` | Token older than 5 minutes | Re-acquire token before signing |
| `Fulcio unavailable` | Network issues | Check connectivity, increase timeout |
| `Certificate chain invalid` | Wrong Fulcio roots | Update root bundle |
| `Identity mismatch` | Wrong verify constraints | Check issuer and identity patterns |
| `Rekor proof missing` | Logging failed | Retry signing, check Rekor status |
### Debug Mode
```bash
# Enable verbose logging
STELLAOPS_LOG_LEVEL=debug stella attest sign --keyless --artifact sha256:...
# Inspect certificate details
stella attest inspect --artifact sha256:... --show-cert
```
## Security Considerations
### Best Practices
1. **Always verify identity**: Never accept `.*` as the full identity pattern
2. **Require Rekor proofs**: Use `--require-rekor` for production verification
3. **Pin OIDC issuers**: Only trust expected issuers
4. **Use environment constraints**: More specific than branch names
5. **Monitor signing activity**: Alert on unexpected identities
### Threat Model
| Threat | Mitigation |
|--------|------------|
| Stolen OIDC token | Short lifetime (~5 min), audience binding |
| Fulcio compromise | Certificate Transparency (SCT), multiple roots |
| Rekor compromise | Multiple witnesses, checkpoints, consistency proofs |
| Private key theft | Ephemeral keys, never persisted |
## Related Documentation
- [Signer Architecture](../architecture.md)
- [Attestor Bundle Format](../../attestor/bundle-format.md)
- [Air-Gap Verification](../../../airgap/attestation-verification.md)
- [CI/CD Integration](../../../guides/cicd-signing.md)
## External Resources
- [Sigstore Documentation](https://docs.sigstore.dev/)
- [Fulcio Overview](https://docs.sigstore.dev/certificate_authority/overview/)
- [Rekor Transparency Log](https://docs.sigstore.dev/logging/overview/)
- [cosign Keyless Signing](https://docs.sigstore.dev/signing/quickstart/)

View File

@@ -0,0 +1,348 @@
# Unified Triage Experience Specification
**Version:** 1.0
**Status:** Active
**Last Updated:** 2025-12-26
**Consolidated From:** 3 product advisories (see References)
## 1. Executive Summary
### The Problem
Modern container security generates overwhelming vulnerability data. Competitors offer fragmented solutions: Snyk provides reachability analysis, Anchore offers VEX annotations, Prisma Cloud delivers runtime signals. Security teams must context-switch between tools, losing precious time and context.
### The Stella Ops Solution
A **unified triage canvas** that combines:
- Rich evidence visualization with proof-carrying verdicts
- VEX decisioning as first-class policy objects
- AI-assisted analysis via AdvisoryAI
- Attestable exceptions with audit trails
- Offline-first architecture for air-gapped parity
## 2. Competitive Landscape
### Snyk — Reachability + Continuous Context
- Implements reachability analysis building call graphs
- Factors reachability into priority scores
- Uses static analysis + AI + expert curation
- Tracks issues over time without re-scanning unchanged images
### Anchore — Vulnerability Annotations + VEX Export
- Vulnerability annotation workflows via UI/API
- Labels: "not applicable", "mitigated", "under investigation"
- Export as OpenVEX and CycloneDX VEX
- Downstream consumers receive curated exploitability state
### Prisma Cloud — Runtime Defense
- Continuous behavioral profiling
- Process, file, and network rule enforcement
- Learning models baseline expected behavior
- Runtime context during operational incidents
### Stella Ops Differentiation
| Feature | Snyk | Anchore | Prisma | Stella Ops |
|---------|------|---------|--------|------------|
| Reachability analysis | Yes | Partial | No | Yes (static + binary + runtime) |
| VEX as policy objects | No | Export only | No | **First-class** |
| Attestable exceptions | No | No | No | **Yes (DSSE)** |
| Offline replay | No | No | No | **Yes** |
| AI-assisted triage | Yes | No | No | Yes (AdvisoryAI) |
| Evidence graphs | Partial | No | Partial | **Full chain** |
## 3. Core UI Concepts
### 3.1 Visual Diff Pattern
Every policy decision or reachability change is treated as a **visual diff**, enabling quick, explainable triage.
#### Side-by-Side Panes
- **Before** (previous scan/policy) vs **After** (current)
- Show dependency/reachability subgraph
- Highlight added/removed/changed nodes/edges
#### Evidence Strip (Right Rail)
Human-readable facts used by the engine:
- Feature flag status (e.g., "feature flag OFF")
- Code path analysis (e.g., "code path unreachable")
- Runtime traces (e.g., "kernel eBPF trace absent")
#### Diff Verdict Header
```
Risk ↓ from Medium → Low (policy v1.8 → v1.9)
```
#### Filter Chips
Scope by: component, package, CVE, policy rule, environment
### 3.2 Data Models
```typescript
interface GraphSnapshot {
nodes: GraphNode[];
edges: GraphEdge[];
metadata: { component: string; version: string; tags: string[] };
}
interface PolicySnapshot {
version: string;
rulesHash: string;
inputs: { flags: Record<string, boolean>; env: string; vexSources: string[] };
}
interface Delta {
added: DeltaItem[];
removed: DeltaItem[];
changed: DeltaItem[];
ruleOutcomes: RuleOutcomeDelta[];
}
interface EvidenceItem {
type: 'trace_hit' | 'sbom_line' | 'vex_claim' | 'config_value';
source: string;
digest: string;
excerpt: string;
timestamp: string;
}
interface SignedDeltaVerdict {
status: 'routine' | 'review' | 'block';
signatures: Signature[];
producer: string;
}
```
### 3.3 Micro-Interactions
| Interaction | Behavior |
|-------------|----------|
| Hover changed node | Inline badge explaining "why it changed" |
| Click rule in rail | Spotlight the exact subgraph affected |
| Toggle "explain like I'm new" | Expands jargon into plain language |
| One-click "copy audit bundle" | Exports delta + evidence as attachment |
### 3.4 Keyboard Shortcuts
| Key | Action |
|-----|--------|
| `1` | Focus changes only |
| `2` | Show full graph |
| `E` | Expand evidence |
| `A` | Export audit bundle |
| `N` | Next item in queue |
| `P` | Previous item |
| `M` | Mark not affected |
## 4. Risk Budget Visualization
### 4.1 Concept
- **Risk budget** = allowable unresolved risk for a release (e.g., 100 "risk points")
- **Burn** = consumption rate as alerts appear, minus "payback" from fixes
### 4.2 Dashboard Components
#### Heatmap of Unknowns
| Component | Vulns | Compliance | Perf | Data | Supply Chain |
|-----------|-------|------------|------|------|--------------|
| Service A | 🟡 12 | 🟢 0 | 🟡 3 | 🔴 8 | 🟡 5 |
| Service B | 🔴 24 | 🟡 2 | 🟢 1 | 🟡 4 | 🟢 0 |
Cell value = unknowns count × severity weight
#### Delta Table (Risk Decay per Release)
| Release | Before | After | Retired | Shifted | Unknowns |
|---------|--------|-------|---------|---------|----------|
| v2.3.1 | 85 | 67 | -22 | +4 | 12 |
| v2.3.0 | 92 | 85 | -15 | +8 | 18 |
#### Exception Ledger
Every accepted risk has: ID, owner, expiry, evidence note, auto-reminder.
### 4.3 Risk Budget Burn-Up Chart
```
Risk Points
^
100 |__________ Budget Line (flat or stepped)
| \
80 | \ ← Actual Risk (cumulative)
| \
60 | \_____ Headroom (green)
| \
40 | \__ Target by release
|
+---------------------------------> Time
T-30 T-14 T-7 T-2 Release
```
- **X-axis:** Calendar dates to code freeze
- **Y-axis:** Risk points
- **Two lines:** Budget (flat/stepped) + Actual Risk (daily)
- **Shaded area:** Headroom (green) or Overrun (red)
- **Markers:** Feature freeze, pen-test, dependency bumps
### 4.4 Computation Formulas
```typescript
// Risk points per issue
risk_points = severity_weight × exposure_factor × evidence_freshness_penalty
// Unknown penalty (no evidence ≤ N days)
if (days_since_evidence > threshold) {
risk_points *= 1.5; // multiplier
}
// Decay on fix
if (fix_landed && evidence_refreshed) {
subtract_points(issue.risk_points);
}
// Guardrails
if (unknowns > K || actual_risk > budget) {
fail_gate();
}
```
## 5. Implementation Components
### 5.1 Component Hierarchy
```
TriageCanvasComponent
├── TriageListComponent
│ ├── SeverityFilterComponent
│ ├── VulnerabilityRowComponent
│ └── BulkActionBarComponent
├── TriageDetailComponent
│ ├── AffectedPackagesPanel
│ ├── AdvisoryRefsPanel
│ ├── ReachabilityContextComponent
│ └── EvidenceProvenanceComponent
├── AiRecommendationPanel
│ ├── ReachabilityExplanation
│ ├── SuggestedJustification
│ └── SimilarVulnsComponent
├── VexDecisionModalComponent
│ ├── StatusSelector
│ ├── JustificationTypeSelector
│ ├── EvidenceRefInput
│ └── ScopeSelector
└── VexHistoryComponent
CompareViewComponent
├── BaselineSelectorComponent
├── TrustIndicatorsComponent
├── DeltaSummaryStripComponent
├── ThreePaneLayoutComponent
│ ├── CategoriesPaneComponent
│ ├── ItemsPaneComponent
│ └── ProofPaneComponent
├── ActionablesPanelComponent
└── ExportActionsComponent
RiskDashboardComponent
├── BurnUpChartComponent
├── UnknownsHeatmapComponent
├── DeltaTableComponent
├── ExceptionLedgerComponent
└── KpiTilesComponent
```
### 5.2 Service Layer
```typescript
// Core services
TriageService // Vulnerability list + filtering
VexDecisionService // CRUD for VEX decisions
AdvisoryAiService // AI recommendations
CompareService // Baseline + delta computation
RiskBudgetService // Budget + burn tracking
EvidenceService // Evidence retrieval
```
## 6. API Integration
### VulnExplorer Endpoints
```
GET /api/v1/vulnerabilities // List with filters
GET /api/v1/vulnerabilities/{id} // Detail
GET /api/v1/vulnerabilities/{id}/reachability // Call graph slice
POST /api/v1/vex-decisions // Create VEX decision
PUT /api/v1/vex-decisions/{id} // Update VEX decision
GET /api/v1/vex-decisions?vulnId={id} // History for vuln
```
### AdvisoryAI Endpoints
```
POST /api/v1/advisory/plan // Get analysis plan
POST /api/v1/advisory/execute // Execute analysis
GET /api/v1/advisory/output/{taskId} // Get recommendations
```
### Delta/Compare Endpoints
```
GET /api/v1/baselines/recommendations/{digest}
POST /api/v1/delta/compute
GET /api/v1/delta/{id}/trust-indicators
GET /api/v1/actionables/delta/{id}
```
## 7. Implementation Status
| Component | Sprint | Status |
|-----------|--------|--------|
| Risk Dashboard Base | SPRINT_20251226_004_FE | TODO |
| Smart-Diff Compare View | SPRINT_20251226_012_FE | TODO |
| Unified Triage Canvas | SPRINT_20251226_013_FE | TODO |
| Documentation Consolidation | SPRINT_20251226_014_DOCS | TODO |
| VEX Decision Models | VulnExplorer/Models | **COMPLETE** |
| AdvisoryAI Pipeline | src/AdvisoryAI | **COMPLETE** |
| Confidence Badge | Web/shared/components | **COMPLETE** |
| Release Flow | Web/features/releases | **COMPLETE** |
## 8. Testing Strategy
### Unit Tests
- Component behavior (selection, filtering, expansion)
- Signal/computed derivations
- Role-based view switching
- Form validation (VEX decisions)
### Integration Tests
- API service calls and response handling
- Navigation and routing
- State persistence across route changes
### E2E Tests
- Full triage workflow: list → detail → VEX decision
- Comparison workflow: select baseline → compute delta → export
- Risk budget: view charts → create exception → see update
### Accessibility Tests
- Keyboard navigation completeness
- Screen reader announcements
- Color contrast compliance
## 9. Success Metrics
| Metric | Definition | Target |
|--------|------------|--------|
| Mean Time to Triage (MTTT) | Time from vuln notification to VEX decision | < 5 min |
| Mean Time to Explain (MTTE) | Time from "why did this change?" to "Understood" click | < 2 min |
| Triage Queue Throughput | Vulns triaged per hour per analyst | > 20 |
| AI Recommendation Acceptance | % of AI suggestions accepted without modification | > 60% |
## 10. References
### Archived Advisories (Consolidated Here)
- `archived/2025-12-26-triage-advisories/25-Dec-2025 - Triage UI Lessons from Competitors.md`
- `archived/2025-12-26-triage-advisories/25-Dec-2025 - Visual Diffs for Explainable Triage.md`
- `archived/2025-12-26-triage-advisories/26-Dec-2026 - Visualizing the Risk Budget.md`
### Related Documentation
- `docs/modules/web/smart-diff-ui-architecture.md`
- `docs/implplan/SPRINT_20251226_004_FE_risk_dashboard.md`
- `docs/implplan/SPRINT_20251226_012_FE_smart_diff_compare.md`
- `docs/implplan/SPRINT_20251226_013_FE_triage_canvas.md`
### External References
- [Snyk Reachability Analysis](https://docs.snyk.io/manage-risk/prioritize-issues-for-fixing/reachability-analysis)
- [Anchore Vulnerability Annotations](https://docs.anchore.com/current/docs/vulnerability_management/vuln_annotations/)
- [Prisma Cloud Runtime Defense](https://docs.prismacloud.io/en/compute-edition/30/admin-guide/runtime-defense/)

View File

@@ -1,104 +1,146 @@
Heres a tight, practical blueprint for evolving StellaOpss policy engine into a **fully deterministic verdict engine**—so the *same SBOM + VEX + reachability subgraph ⇒ the exact same, replayable verdict* every time, with auditorgrade trails and signed “delta verdicts.”
# Building a Deterministic Verdict Engine
# Why this matters (quick)
> **Status:** PLANNED — Implementation in progress
> **Date:** 2025-12-25
> **Updated:** 2025-12-26
> **Related Sprints:** [`SPRINT_20251226_007_BE_determinism_gaps.md`](../implplan/SPRINT_20251226_007_BE_determinism_gaps.md)
> **Merged Advisories:** [`25-Dec-2025 - Enforcing Canonical JSON for Stable Verdicts.md`](./25-Dec-2025%20-%20Enforcing%20Canonical%20JSON%20for%20Stable%20Verdicts.md) (SUPERSEDED)
---
## 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 DET-GAP-01..04 |
| Keyless Signing | TODO | SPRINT_20251226_001 |
| Cross-Platform Testing | TODO | SPRINT_20251226_007 DET-GAP-11..13 |
**Overall Progress:** ~85% complete
---
## Advisory Content
Here's a tight, practical blueprint for evolving Stella Ops's policy engine into a **fully deterministic verdict engine**—so the *same SBOM + VEX + reachability subgraph ⇒ the exact same, replayable verdict* every time, with auditorgrade trails and signed "delta verdicts."
## Why this matters (quick)
* **Reproducibility:** auditors can replay any scan and get identical results.
* **Trust & scale:** crossagent consensus via contentaddressed inputs and signed outputs.
* **Operational clarity:** diffs between builds become crisp, machineverifiable artifacts.
# Core principles
## Core principles
* **Determinism-first:** no wallclock time, no random iteration order, no network during evaluation.
* **Contentaddressing:** hash every *input* (SBOM, VEX docs, reachability subgraph, policy set, rule versions, feed snapshots).
* **Declarative state:** a compact **Scan Manifest** lists input hashes + policy bundle hash + engine version.
* **Pure evaluation:** the verdict function is referentially transparent: `Verdict = f(Manifest)`.
# Data artifacts
## Canonical JSON (Merged from Canonical JSON Advisory)
All JSON artifacts must use **RFC 8785 JCS** canonicalization with optional **Unicode NFC** normalization:
```csharp
// Existing implementation
using StellaOps.Canonical.Json;
var canonical = CanonJson.Canonicalize(myObject);
var hash = CanonJson.Hash(myObject);
var versionedHash = CanonJson.HashVersioned(myObject, CanonVersion.V1);
```
**Canonicalization Rules:**
1. Object keys sorted lexicographically (Ordinal)
2. No whitespace or formatting variations
3. UTF-8 encoding without BOM
4. IEEE 754 number formatting
5. Version markers for migration safety (`_canonVersion: "stella:canon:v1"`)
## Data artifacts
* **Scan Manifest (`manifest.jsonc`)**
* `sbom_sha256`, `vex_set_sha256[]`, `reach_subgraph_sha256`, `feeds_snapshot_sha256`, `policy_bundle_sha256`, `engine_version`, `policy_semver`, `options_hash`
* **Verdict (`verdict.json`)**
* canonical JSON (stable key order); includes:
* `risk_score`, `status` (pass/warn/fail), `unknowns_count`
* **evidence_refs:** content IDs for cited VEX statements, nodes/edges from reachability, CVE records, featureflags, envguards
* **explanations:** stable, templatedriven strings (+ machine reasons)
* **Delta Verdict (`delta.json`)**
* computed between two manifests/verdicts:
* `added_findings[]`, `removed_findings[]`, `severity_shift[]`, `unknowns_delta`, `policy_effects[]`
* signed (DSSE/COSE/JWS), timestamped, and linkable to both verdicts
# Engine architecture (deterministic path)
## Engine architecture (deterministic path)
1. **Normalize inputs**
* SBOM: sort by `packageUrl`/`name@version`; resolve aliases; freeze semver comparison rules.
* VEX: normalize provider → `vex_id`, `product_ref`, `status` (`affected`, `not_affected`, …), *with* source trust score precomputed from a **trust registry** (strict, versioned).
* Reachability: store subgraph as adjacency lists sorted by node ID; hash after topological stable ordering.
* Feeds: lock to a **snapshot** (timestamp + commit/hash); no live calls.
2. **Policy bundle**
2. **Policy bundle**
* Declarative rules (e.g., lattice/merge semantics), compiled to a **canonical IR** (e.g., OPARego → sorted DNF).
* Merge precedence is explicit (e.g., `vendor > distro > internal` can be replaced by a latticemerge table).
* Unknowns policy baked in: e.g., `fail_if_unknowns > N in prod`.
3. **Evaluation**
3. **Evaluation**
* Build a **finding set**: `(component, vuln, context)` tuples with deterministic IDs.
* Apply **latticebased VEX merge** (proofcarrying): each suppression must carry an evidence pointer (feature flag off, code path unreachable, patchedbackport proof).
* Compute final `status` and `risk_score` using fixedprecision math; round rules are part of the bundle.
4. **Emit**
4. **Emit**
* Canonicalize verdict JSON; attach **evidence map** (content IDs only).
* Sign verdict; attach as **OCI attestation** to image/digest.
# APIs (minimal but complete)
## APIs (minimal but complete)
* `POST /evaluate` → returns `verdict.json` + attestation
* `POST /delta` with `{base_verdict, head_verdict}``delta.json` (signed)
* `GET /replay?manifest_sha=` → reexecutes using cached snapshot bundles, returns the same `verdict_sha`
* `GET /evidence/:cid` → fetches immutable evidence blobs (offlineready)
# Storage & indexing
## Storage & indexing
* **CAS (contentaddressable store):** `/evidence/<sha256>` for SBOM/VEX/graphs/feeds/policies.
* **Verdict registry:** keyed by `(image_digest, manifest_sha, engine_version)`.
* **Delta ledger:** appendonly, signed; supports crossagent consensus (multiple engines can cosign identical deltas).
# UI slices (where it lives)
## UI slices (where it lives)
* **Run details → Verdict tab:** status, risk score, unknowns, top evidence links.
* **Diff tab:** render **Delta Verdict** (added/removed/changed), with drilldown to proofs.
* **Replay button:** shows the exact manifest & engine version; oneclick reevaluation (offline possible).
* **Run details → "Verdict" tab:** status, risk score, unknowns, top evidence links.
* **"Diff" tab:** render **Delta Verdict** (added/removed/changed), with drilldown to proofs.
* **"Replay" button:** shows the exact manifest & engine version; oneclick reevaluation (offline possible).
* **Audit export:** zip of `manifest.jsonc`, `verdict.json`, `delta.json` (if any), attestation, and referenced evidence.
# Testing & QA (musthave)
## Testing & QA (musthave)
* **Golden tests:** fixtures of manifests → frozen verdict JSONs (byteforbyte).
* **Chaos determinism tests:** vary thread counts, env vars, map iteration seeds; assert identical verdicts.
* **Crossengine roundtrips:** two independent builds of the engine produce the same verdict for the same manifest.
* **Timetravel tests:** replay older feed snapshots to ensure stability.
# Rollout plan
## Rollout plan
1. **Phase 1:** Introduce Manifest + canonical verdict format alongside existing policy engine (shadow mode).
2. **Phase 2:** Make verdicts the **firstclass artifact** (OCIattached); ship UI Verdict/Diff.
2. **Phase 2:** Make verdicts the **firstclass artifact** (OCIattached); ship UI "Verdict/Diff".
3. **Phase 3:** Enforce **deltagates** in CI/CD (risk budgets + exception packs referenceable by content ID).
4. **Phase 4:** Open **consensus mode**—accept externally signed identical delta verdicts to strengthen trust.
# Notes for Stella modules
## Notes for Stella modules
* **scanner.webservice:** keep lattice algorithms here (per your standing rule). Concelier/Excitors preserveprune source.
* **scanner.webservice:** keep lattice algorithms here (per your standing rule). Concelier/Excitors "preserveprune source."
* **Authority/Attestor:** handle DSSE signing, key management, regional crypto profiles (eIDAS/FIPS/GOST/SM).
* **Feedser/Vexer:** produce immutable **snapshot bundles**; never query live during evaluation.
* **Router/Scheduler:** schedule replay jobs; cache manifests to speed up audits.
* **Db:** Postgres as SoR; Valkey only for ephemeral queues/caches (per your BSDonly profile).
If you want, I can generate:
* a sample **Manifest + Verdict + Delta** trio,
* the **canonical JSON schema**,
* and a **.NET10** reference evaluator (deterministic LINQ pipeline + fixedprecision math) you can drop into `scanner.webservice`.

View File

@@ -1,10 +1,46 @@
Heres a small but highimpact practice to make your hashes/signatures and “same inputs → same verdict” truly stable across services: **pick one canonicalization and enforce it at the resolver boundary.**
# Enforcing Canonical JSON for Stable Verdicts
> **Status:** SUPERSEDED — Already implemented in codebase
> **Date:** 2025-12-25
> **Updated:** 2025-12-26
> **Superseded By:** Existing implementation in `StellaOps.Canonical.Json`
> **Related:** Merged into `25-Dec-2025 - Building a Deterministic Verdict Engine.md`
---
## Implementation Status
This advisory's recommendations are **already implemented** in the codebase:
| Recommendation | Implementation | Location |
|----------------|----------------|----------|
| RFC 8785 JCS canonicalization | `Rfc8785JsonCanonicalizer` | `src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/Json/` |
| Unicode NFC normalization | `NfcStringNormalizer` | `src/__Libraries/StellaOps.Resolver/` |
| Canonical JSON library | `CanonJson` | `src/__Libraries/StellaOps.Canonical.Json/` |
| Version markers | `CanonVersion` (stella:canon:v1) | `src/__Libraries/StellaOps.Canonical.Json/` |
| Content-addressed IDs | `ContentAddressedIdGenerator` | `src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/Identifiers/` |
| Determinism testing | `DeterminismGate` | `src/__Libraries/StellaOps.TestKit/Determinism/` |
### Remaining Gap Tasks
Minor enforcement gaps are tracked in [`SPRINT_20251226_007_BE_determinism_gaps.md`](../implplan/SPRINT_20251226_007_BE_determinism_gaps.md):
- DET-GAP-17: Optional NFC pass in canonicalizers
- DET-GAP-18: Roslyn analyzer for resolver boundary enforcement
- DET-GAP-19: Pre-canonical hash debug logging
- DET-GAP-20: Document resolver boundary pattern in CONTRIBUTING.md
---
## Original Advisory Content
Here's a small but highimpact practice to make your hashes/signatures and "same inputs → same verdict" truly stable across services: **pick one canonicalization and enforce it at the resolver boundary.**
---
### Why this matters (in plain words)
Two JSONs that *look* the same can serialize differently (key order, spacing, Unicode forms). If one producer emits slightly different bytes, your REG/verdict hash changes—even though the meaning didnt—breaking dedup, cache hits, attestations, and audits.
Two JSONs that *look* the same can serialize differently (key order, spacing, Unicode forms). If one producer emits slightly different bytes, your REG/verdict hash changes—even though the meaning didn't—breaking dedup, cache hits, attestations, and audits.
---
@@ -24,11 +60,52 @@ Two JSONs that *look* the same can serialize differently (key order, spacing, Un
2. Resolver **normalizes strings (NFC)** and **reemits JSON in JCS**.
3. **REG hash** is computed from **JCScanonical UTF8 bytes** only.
4. Any signature/attestation (DSSE/OCI) MUST cover those same bytes.
5. Any module that cant speak JCS must pass raw data to the resolver; only the resolver serializes.
5. Any module that can't speak JCS must pass raw data to the resolver; only the resolver serializes.
---
### Practical .NET 10 snippet (dropin utility)
### Existing Implementation (supersedes sample code)
The codebase already provides a more robust 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);
```
---
### Dropin checklist (pin on your wall)
- [x] One canonicalization policy: **UTF8 + NFC + JCS**. *(Implemented: `CanonJson`, `NfcStringNormalizer`)*
- [x] Resolver owns canonicalization (single chokepoint). *(Pattern documented)*
- [x] **REG hash/signatures always over canonical bytes.** *(Implemented: `ContentAddressedIdGenerator`)*
- [ ] CI gate: reject outputs that aren't JCS; fuzz keys/order/whitespace in tests. *(In progress: SPRINT_20251226_007)*
- [ ] Log both the precanonical and canonical SHA256 for audits. *(Planned: DET-GAP-19)*
- [x] Backwardcompat path: migrate legacy verdicts by recanonicalizing once, store "old_hash → new_hash" map. *(Implemented: `CanonVersion` with version markers)*
---
### Original Sample Code (archived for reference)
<details>
<summary>Click to expand original sample code</summary>
```csharp
using System.Text;
@@ -110,26 +187,4 @@ public static class Canon
}
```
**Usage (hash/sign):**
```csharp
var inputBytes = File.ReadAllBytes("input.json");
var canon = Canon.CanonicalizeUtf8(inputBytes);
var sha256 = System.Security.Cryptography.SHA256.HashData(canon);
// sign `canon` bytes; attach hash to verdict/attestation
```
---
### Dropin checklist (pin on your wall)
* [ ] One canonicalization policy: **UTF8 + NFC + JCS**.
* [ ] Resolver owns canonicalization (single chokepoint).
* [ ] **REG hash/signatures always over canonical bytes.**
* [ ] CI gate: reject outputs that arent JCS; fuzz keys/order/whitespace in tests.
* [ ] Log both the precanonical and canonical SHA256 for audits.
* [ ] Backwardcompat path: migrate legacy verdicts by recanonicalizing once, store “old_hash → new_hash” map.
---
If you want, I can wrap this into a tiny **`StellaOps.Canonicalizer`** NuGet (net10.0) and a Git precommit hook + CI check so your agents and services cant drift.
</details>

View File

@@ -1,4 +1,37 @@
Heres a practical, lowfriction way to modernize how you sign and verify build “verdicts” in CI/CD using Sigstore—no longlived keys, offlinefriendly, and easy to audit.
# Planning Keyless Signing for Verdicts
> **Status:** PLANNED — Implementation sprints created
> **Date:** 2025-12-25
> **Updated:** 2025-12-26
> **Related:** Extends `25-Dec-2025 - Building a Deterministic Verdict Engine.md`
---
## Implementation Sprints
This advisory has been decomposed into the following implementation sprints:
| Sprint | Module | Topic | Priority |
|--------|--------|-------|----------|
| [`SPRINT_20251226_001_SIGNER_fulcio_keyless_client.md`](../implplan/SPRINT_20251226_001_SIGNER_fulcio_keyless_client.md) | Signer | Fulcio keyless signing client | P0 |
| [`SPRINT_20251226_002_ATTESTOR_bundle_rotation.md`](../implplan/SPRINT_20251226_002_ATTESTOR_bundle_rotation.md) | Attestor | Monthly bundle rotation | P1 |
| [`SPRINT_20251226_003_ATTESTOR_offline_verification.md`](../implplan/SPRINT_20251226_003_ATTESTOR_offline_verification.md) | Attestor | Offline/air-gap verification | P2 |
| [`SPRINT_20251226_004_BE_cicd_signing_templates.md`](../implplan/SPRINT_20251226_004_BE_cicd_signing_templates.md) | Backend | CI/CD integration templates | P2 |
**Total Tasks:** 98 across 4 sprints
---
## Documentation Created
- [`docs/modules/signer/guides/keyless-signing.md`](../modules/signer/guides/keyless-signing.md) — Keyless signing guide
- [`src/Signer/AGENTS.md`](../../src/Signer/AGENTS.md) — Signer module charter
---
## Advisory Content
Here's a practical, lowfriction way to modernize how you sign and verify build "verdicts" in CI/CD using Sigstore—no longlived keys, offlinefriendly, and easy to audit.
---

View File

@@ -1,56 +0,0 @@
Heres a simple, highleverage UX pattern you can borrow from top observability tools: **treat every policy decision or reachability change as a visual diff.**
---
### Why this helps
* Turns opaque “why is this verdict different?” moments into **quick, explainable triage**.
* Reduces backandforth between Security, Dev, and Audit—**everyone sees the same before/after evidence**.
### Core UI concept
* **Sidebyside panes**: **Before** (previous scan/policy) vs **After** (current).
* **Graph focus**: show the dependency/reachability subgraph; **highlight added/removed/changed nodes/edges**.
* **Evidence strip** (right rail): humanreadable facts used by the engine (e.g., *feature flag OFF*, *code path unreachable*, *kernel eBPF trace absent*).
* **Diff verdict header**: “Risk ↓ from *Medium → Low* (policy v1.8 → v1.9)”.
* **Filter chips**: Scope by component, package, CVE, policy rule, environment.
### Minimal data model (so UI is easy)
* `GraphSnapshot`: nodes, edges, metadata (component, version, tags).
* `PolicySnapshot`: version, rules hash, inputs (flags, env, VEX sources).
* `Delta`: `added/removed/changed` for nodes, edges, and rule outcomes.
* `EvidenceItems[]`: typed facts (trace hits, SBOM lines, VEX claims, config values) with source + timestamp.
* `SignedDeltaVerdict`: final status + signatures (who/what produced it).
### Microinteractions that matter
* Hover a changed node ⇒ **inline badge** explaining *why it changed* (e.g., “now gated by `--no-xml` runtime flag”).
* Click a rule change in the right rail ⇒ **spotlight** the exact subgraph it affected.
* Toggle **“explain like Im new”** ⇒ expands jargon into plain language.
* Oneclick **“copy audit bundle”** ⇒ exports the delta + evidence as an attachment.
### Where this belongs in your product
* **Primary**: in the **Triage** view for any new finding/regression.
* **Secondary**: in **Policy history** (compare vX vs vY) and **Release gates** (compare build A vs build B).
* **Inline surfaces**: small “diff pills” next to every verdict in tables; click opens the big sidebyside.
### Quick build checklist (dev & PM)
* Compute a stable **graph hash** per scan; store **snapshots**.
* Add a **delta builder** that outputs `added/removed/changed` at node/edge + rule outcome levels.
* Normalize **evidence items** (source, digest, excerpt) so the UI can render consistent cards.
* Ship a **Signed Delta Verdict** (OCIattached) so audits can replay the view from the artifact alone.
* Include **hotkeys**: `1` focus changes only, `2` show full graph, `E` expand evidence, `A` export audit.
### Empty state & failure modes
* If evidence is incomplete: show a **yellow “Unknowns present” ribbon** with a count and a button to collect missing traces.
* If graphs are huge: default to **“changed neighborhood only”** with a minimap to pan.
### Success metric (simple)
* **Mean time to explain (MTTE)**: time from “why did this change?” to user clicking *“Understood”*. Track trend ↓.
If you want, I can sketch a quick wireframe (header, graph panes, evidence rail, and the export action) or generate a JSON schema for the `Delta` and `EvidenceItem` objects you can hand to your frontend.

View File

@@ -0,0 +1,178 @@
# AI Assistant as Proof-Carrying Evidence Engine
**Status:** ANALYZED - Sprints Created
**Date:** 2025-12-26
**Type:** Strategic AI Feature Advisory
**Implementation Sprints:** SPRINT_20251226_015 through 019
---
## Executive Summary
This advisory proposes building Stella Ops AI as a **proof-carrying assistant** that:
- Copies best UX outcomes from competitors (Snyk: speed to fix; JFrog/Docker: context reduces noise)
- Keeps authority in deterministic, replayable engines and signed evidence packs
- Extends into Stella Ops' moats: lattice merge semantics, deterministic replay, sovereign/offline cryptography
## Advisory Content
### 1) What to Copy: Competitor AI Patterns
#### A. Snyk-style: "developer-time" intelligence
- Fast, developer-local explanation of "why this is a problem" and "what change fixes it"
- Reachability-informed prioritization (not just CVSS)
- Autofix PRs where safe
**Stella Ops takeaway:** Make "time-to-understanding" and "time-to-first-fix" first-class KPIs.
#### B. JFrog-style: contextual exploitability filtering
- "Is this vulnerability exploitable in *this* app?" filtering
- Runtime loaded-code validation to reduce noise
**Stella Ops takeaway:** Treat exploitability as an evidence question; label uncertainty explicitly.
#### C. Aqua-style: AI-guided remediation
- Prescriptive remediation steps in human language (and as patches/PRs)
- Integrate into CI/CD and ticketing
**Stella Ops takeaway:** The assistant must be operational: PR creation, change plans, risk acceptance packages.
#### D. Docker Scout-style: operational context
- Use runtime telemetry to prioritize vulnerabilities that can actually bite
**Stella Ops takeaway:** Runtime evidence as attestable evidence beats "black box AI prioritization."
#### E. Grype/Trivy reality: deterministic scanners win trust
- Strong data hygiene, VEX ingestion, deterministic outputs
**Stella Ops takeaway:** AI layer must never undermine deterministic trust; must be additive, signed, replayable.
### 2) Where Competitors Are Weak (Stella Ops Openings)
1. **Audit-grade reproducibility:** AI explanations often non-replayable
2. **Offline/sovereign operations:** Air-gapped + local inference rare
3. **Proof-carrying verdicts:** Most risk scores are opaque
4. **Merge semantics for VEX:** Few ship policy-controlled lattice merge
5. **Time-travel replay + delta verdicts:** Rare as first-class artifacts
6. **Network effects for proofs:** Proof-market ledger concepts largely absent
### 3) Core Principle: "AI is an assistant; evidence is the authority"
**Every AI output must be either:**
- **Pure suggestion** (non-authoritative), or
- **Evidence-backed** (authoritative only when evidence pack suffices)
### 4) Proposed Features
#### Feature 1: Zastava Companion
Evidence-grounded explainability answering: What is it? Why it matters? What evidence supports?
- Output anchored to evidence nodes
- OCI-attached "Explanation Attestation" with hashes + model digest
#### Feature 2: Exploitability Confidence Engine
- Deterministic classification: Confirmed/Likely/Unknown/Likely Not/Not exploitable
- AI proposes "cheapest additional evidence" to reduce Unknown
#### Feature 3: Remedy Autopilot
- AI generates remediation plans
- Automated PRs with reproducible build, tests, SBOM delta, signed delta verdict
- Fallback to "suggestion-only" if build/tests fail
#### Feature 4: Auto-VEX Drafting
- Generate VEX drafts from evidence
- Lattice-aware merge preview
#### Feature 5: Advisory Ingestion Copilot
- Convert unstructured advisories to structured records
- Cross-check multiple sources, require corroboration for "trusted" status
#### Feature 6: Policy Studio Copilot
- NL → lattice rules
- Test case generation
- Compile to deterministic policy with signed snapshots
### 5) Architecture
- **scanner.webservice:** lattice merges, deterministic verdict engine (authoritative)
- **zastava.webservice (new):** LLM inference + RAG; non-authoritative suggestions
- **Feedser/Vexer:** immutable feed snapshots for replay
- **Postgres:** system of record
- **Valkey:** ephemeral caching (never authoritative)
- **Offline profile:** Postgres-only + local inference bundle
### 6) Deterministic, Replayable AI
Record and hash:
- Prompt template version
- Retrieved evidence node IDs + content hashes
- Model identifier + weights digest
- Decoding parameters (temperature=0, fixed seed)
Emit as OCI-attached attestation: AIExplanation, RemediationPlan, VEXDraft, PolicyDraft.
### 7) Roadmap
- **Phase 1:** Deterministic confidence states + Zastava "Explain with evidence"
- **Phase 2:** Remedy Autopilot + Auto-VEX drafting
- **Phase 3:** Sovereign/offline AI bundle
- **Phase 4:** Proof-market + trust economics
### 8) KPIs
- Mean time to triage (MTTT)
- Mean time to remediate (MTTR)
- Noise rate (% findings that end up "not exploitable")
- "Unknown" reduction speed
- Reproducibility (% AI artifacts replayed to identical output)
- Audit extraction time
### 9) Risks and Mitigations
1. Hallucinations → enforce evidence citation
2. Prompt injection → sanitize, isolate untrusted text
3. Data exfiltration → offline profile, strict egress
4. Bad patches → require build+tests+policy gates
5. Model drift → pin model digests, snapshot outputs
---
## Implementation Assessment
### Existing Infrastructure (Substantial)
| Component | Coverage | Location |
|-----------|----------|----------|
| AdvisoryAI Pipeline | 90% | `src/AdvisoryAI/` |
| Guardrail Pipeline | 100% | `AdvisoryAI/Guardrails/` |
| Evidence Retrieval | 80% | SBOM context, vector/structured retrieval |
| TrustLatticeEngine | 100% | `Policy/TrustLattice/` |
| SourceTrustScoreCalculator | 100% | `VexLens/Trust/` |
| Remediation Hints | 30% | `Policy.Unknowns/Services/` |
| ProofChain/Attestations | 100% | `Attestor/ProofChain/` |
| DeltaVerdict | 100% | `StellaOps.DeltaVerdict/` |
| Offline/Airgap | 80% | Various modules |
### Gaps Requiring New Development
1. **LLM-generated explanations** - Feature 1
2. **Remedy Autopilot with PRs** - Feature 3
3. **Policy NL→Rules** - Feature 6
4. **AI artifact attestation types** - All features
5. **Sovereign/offline LLM** - Phase 3
### Created Sprints
| Sprint | Topic | Tasks |
|--------|-------|-------|
| SPRINT_20251226_015_AI_zastava_companion | Explanation generation | 21 tasks |
| SPRINT_20251226_016_AI_remedy_autopilot | Automated remediation PRs | 26 tasks |
| SPRINT_20251226_017_AI_policy_copilot | NL→lattice rules | 26 tasks |
| SPRINT_20251226_018_AI_attestations | AI artifact attestation types | 23 tasks |
| SPRINT_20251226_019_AI_offline_inference | Sovereign/offline AI | 26 tasks |
**Total:** 5 sprints, 122 tasks
### Archived Advisory
- "Weighted Confidence for VEX Sources" → moved to `archived/2025-12-26-vex-scoring/`
(Substantially implemented in VexLens SourceTrustScoreCalculator)

View File

@@ -0,0 +1,233 @@
# Stella Ops vNext - SBOM Spine and Deterministic Evidence
> **Status:** IMPLEMENTED — Architecture overview document
> **Date:** 2025-12-26
> **Updated:** 2025-12-26
> **Type:** Vision Document / Architecture Summary
> **Implementation:** 100% complete in existing infrastructure
---
## Implementation Status
This advisory describes the **existing StellaOps architecture**. All proposed features are implemented:
### Core Infrastructure
| Component | Implementation | Location |
|-----------|----------------|----------|
| SBOM-first canonical graph | `SbomService` module | `src/SbomService/` |
| CycloneDX 1.6 + SPDX 3.x | `SbomNormalizationService` | `src/SbomService/.../Services/` |
| in-toto + DSSE attestations | `Attestor` module (6+ predicate types) | `src/Attestor/` |
| OCI referrers | `OciReferrerPushClient`, `OciReferrerDiscovery` | `src/ExportCenter/.../Oci/` |
| Cosign/Sigstore signatures | `Signer` module | `src/Signer/` |
| Regional crypto (eIDAS/FIPS/GOST/SM) | `Cryptography` module | `src/Cryptography/` |
| Evidence graph | `ProofChain` library | `src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/` |
| Smart-diff algorithm | `DeltaComputationEngine` | `src/__Libraries/StellaOps.DeltaVerdict/` |
| Signed delta verdicts | `DeltaSigningService` | `src/__Libraries/StellaOps.DeltaVerdict/Signing/` |
| Content-addressed IDs | `IContentAddressedIdGenerator` | `src/Attestor/__Libraries/.../Identifiers/` |
| Decision digest (Provcache) | `DecisionDigest`, `VeriKey` | `src/__Libraries/StellaOps.Provcache/` |
| Merkle proof verification | `MerkleProofVerifier` | `src/Attestor/__Libraries/.../Merkle/` |
| Deterministic replay | `ReplaySeed`, `FrozenEpoch` | `src/__Libraries/StellaOps.Provcache/` |
| PostgreSQL + Valkey | All modules | Per-module storage |
### Predicate Types (All Implemented)
| Predicate | Type URI | Implementation |
|-----------|----------|----------------|
| Build Provenance | `StellaOps.BuildProvenance@1` | `Attestor.ProofChain` |
| SBOM Attestation | `StellaOps.SBOMAttestation@1` | `Attestor.ProofChain` |
| Scan Results | `StellaOps.ScanResults@1` | `Attestor.ProofChain` |
| Policy Evaluation | `StellaOps.PolicyEvaluation@1` | `Attestor.ProofChain` |
| VEX Attestation | `StellaOps.VEXAttestation@1` | `Attestor.ProofChain` |
| Risk Profile Evidence | `StellaOps.RiskProfileEvidence@1` | `Attestor.ProofChain` |
### Implementation Checklist (All Complete)
**Pipelines:**
- [x] Build: emit SBOM (CDX + SPDX), SLSA provenance (in-toto/DSSE), sign all
- [x] Scan: OS + language + config; one attestation per tool
- [x] Policy: evaluate rules -> signed verdict attestation; include unknowns count
- [x] Publish: push all as OCI referrers; enable verification gate
**Schema & IDs:**
- [x] Normalize component IDs (PURL/CPE) + strong hashes
- [x] Evidence graph store: Postgres (authoritative) + cache (Valkey)
- [x] Index by image digest; maintain as-of snapshots
**Determinism:**
- [x] Lock feeds, rule versions, tool versions; record all input digests
- [x] Provide replay manifest capturing inputs -> expected verdict hash
**Security & Sovereignty:**
- [x] Pluggable crypto: eIDAS/FIPS/GOST/SM; offline bundle export/import
- [x] Air-gapped profile: Postgres-only with documented trade-offs
---
## Documentation References
- **SbomService Architecture:** `docs/modules/sbomservice/architecture.md`
- **Attestor Architecture:** `docs/modules/attestor/architecture.md`
- **Signer Keyless Guide:** `docs/modules/signer/guides/keyless-signing.md`
- **ProofChain Specification:** `docs/modules/attestor/proof-chain-specification.md`
- **Determinism Gates:** `docs/testing/determinism-gates.md`
---
## Advisory Content (Original Vision)
Here's a simple, practical way to think about a **SBOM-first, VEX-ready supply-chain spine** and the **evidence graph + smart-diff** you can build on top of it—starting from zero and ending with reproducible, signed decisions.
### SBOM-first spine (VEX-ready)
**Goal:** make the SBOM the canonical graph of "what's inside," then layer signed evidence (build, scans, policy) so every verdict is portable, replayable, and auditable across registries.
**Core choices:**
* **Canonical graph:** treat **CycloneDX 1.6** and **SPDX 3.x** as first-class. Keep both in sync; normalize component IDs (PURL/CPE), hashes, licenses, and relationships.
* **Attestations:** use **in-toto + DSSE** for all lifecycle facts:
* build (SLSA provenance),
* scan results (vuln, secrets, IaC, reachability),
* policy evaluation (allow/deny, risk budgets, exceptions).
* **Storage/transport:** publish everything as **OCI-attached artifacts** via **OCI Referrers**:
* `image:tag` -> SBOM (spdx/cdx), VEX, SARIF, provenance, policy verdicts, exception notes—each a referrer with media type + signature.
* **Signatures:** cosign/sigstore (or your regional crypto: eIDAS/FIPS/GOST/SM) for **content-addressed** blobs.
**Minimum viable workflow:**
1. **Build step**
* Produce identical SBOMs in CycloneDX and SPDX.
* Emit SLSA-style provenance attestation.
2. **Scan step(s)**
* OS + language deps + container layers; add **reachability proofs** where possible.
* Emit one **scan attestation per tool** (don't conflate).
3. **Policy step**
* Evaluate policies (e.g., OPA/Rego or your lattice rules) **against the SBOM graph + scan evidence**.
* Emit a **signed policy verdict attestation** (pass/fail + reasons + unknowns count).
4. **Publish**
* Push image, then push SBOMs, VEX, scan attestations, policy verdicts as **OCI referrers**.
5. **Verify / consume**
* Pull the image's **referrer set**; verify signatures; reconstruct graph locally; **replay** the policy evaluation deterministically.
**Data model tips:**
* Stable identifiers: PURLs for packages, digests for layers, Build-ID for binaries.
* Edges: `component->dependsOn`, `component->vulnerability`, `component->evidence(attestation)`, `component->policyClaim`.
* Keep **time (as-of)** and **source** on every node/edge for replay.
### Evidence graph + smart-diff
**Goal:** persist an **explainability graph** (findings <-> components <-> provenance <-> policies) and compute **signed delta-verdicts** on diffs to drive precise impact analysis and quiet noise.
**What to store:**
* **Provenance:** who built it, from what, when (commit, builder, materials).
* **Findings:** CVEs, misconfigs, secrets, license flags, each with source tool, version, rule, confidence, timestamp.
* **Policies & verdicts:** rule set version, inputs' hashes, outcome, rationale.
* **Reachability subgraphs:** the minimal path proving exploitability (e.g., symbol -> function -> package -> process start).
**Smart-diff algorithm (high level):**
* Compare two images (or SBOM graphs) **by component identity + version + hash**.
* For each change class:
* **Added/removed/changed component**
* **New/cleared/changed finding**
* **Changed reachability path**
* **Changed policy version/inputs**
* Re-evaluate only affected subgraph; produce a **Delta Verdict**:
* `status`: safer / risk-equal / risk-higher
* `why`: list of net-new reachable vulns, removed reachable vulns, policy/exception impacts
* `evidenceRefs`: hashes of attestations used
* **Sign the delta verdict (DSSE)** and publish it as an **OCI referrer** too.
**UX essentials:**
* Artifact page shows: **"Evidence Stack"** (SBOM, scans, VEX, policy, provenance) with green checks for signatures.
* **Smart-diff view:** left vs right image -> "net-new reachable CVEs (+3)", "downgraded risk (-1)" with drill-downs to the exact path/evidence.
* **Explain button:** expands to show **why** a CVE is (not) applicable (feature flag off, code path unreachable, kernel mitigation present, etc.).
* **Replay badge:** "Deterministic ✓" (inputs' hashes match; verdict reproducible).
### APIs & types (implemented media types)
* `application/vnd.cyclonedx+json`
* `application/spdx+json`
* `application/vnd.in-toto+json; statement=provenance|scan|policy`
* `application/vnd.stella.verdict+json` (signed verdict/delta)
### Existing Implementation Examples
**Scan Attestation (StellaOps.ScanResults@1):**
```json
{
"type": "https://in-toto.io/Statement/v1",
"predicateType": "https://stella.dev/scan/v1",
"subject": [{"name": "registry/app@sha256:...", "digest": {"sha256": "..."}}],
"predicate": {
"tool": {"name": "scannerX", "version": "1.4.2"},
"inputs": {"sbom": "sha256:...", "db": "sha256:..."},
"findings": [{"id": "CVE-2025-1234", "component": "pkg:pypi/xyz@1.2.3", "severity": "HIGH"}]
}
}
```
**Policy Verdict (StellaOps.PolicyEvaluation@1):**
```json
{
"type": "https://in-toto.io/Statement/v1",
"predicateType": "https://stella.dev/verdict/v1",
"subject": [{"name": "registry/app@sha256:..."}],
"predicate": {
"policy": {"id": "prod.v1.7", "hash": "sha256:..."},
"inputs": {"sbom": "sha256:...", "scans": ["sha256:...","sha256:..."]},
"unknowns": 2,
"decision": "allow",
"reasons": [
"CVE-2025-1234 not reachable (path pruned)",
"License policy ok"
]
}
}
```
**Delta Verdict (stella.dev/delta-verdict/v1):**
```json
{
"predicateType": "https://stella.dev/delta-verdict/v1",
"predicate": {
"from": "sha256:old", "to": "sha256:new",
"impact": "risk-higher",
"changes": {
"componentsAdded": ["pkg:apk/openssl@3.2.1-r1"],
"reachableVulnsAdded": ["CVE-2025-2222"]
},
"evidenceRefs": ["sha256:scanA", "sha256:policyV1"]
}
}
```
### Operating rules (adopted)
* **Everything is evidence.** If it influenced a decision, it's an attestation you can sign and attach.
* **Same inputs -> same verdict.** If not, treat it as a bug.
* **Unknowns budgeted by policy.** E.g., "fail prod if unknowns > 0; warn in dev."
* **Diffs decide deployments.** Gate on the **delta verdict**, not raw CVE counts.
* **Portable by default.** If you move registries, your decisions move with the image via referrers.
---
## Related Implementation
| Module | Purpose | Documentation |
|--------|---------|---------------|
| `SbomService` | SBOM ledger, lineage, versioning | `docs/modules/sbomservice/` |
| `Attestor` | DSSE, in-toto, Rekor integration | `docs/modules/attestor/` |
| `Signer` | Keyless + KMS signing | `docs/modules/signer/` |
| `Provcache` | Decision digest, VeriKey | `src/__Libraries/StellaOps.Provcache/` |
| `DeltaVerdict` | Smart-diff engine | `src/__Libraries/StellaOps.DeltaVerdict/` |
| `ExportCenter` | OCI referrer publishing | `src/ExportCenter/` |
| `Policy` | Lattice evaluation, verdicts | `src/Policy/` |

View File

@@ -1,11 +1,49 @@
Heres a compact blueprint for a **binarylevel knowledge base** that maps ELF BuildIDs / PE signatures to vulnerable functions, patch lineage, and reachability hints—so your scanner can act like a provenanceaware “binary oracle,” not just a CVE lookup.
# Mapping a Binary Intelligence Graph
> **Status:** SUPERSEDED
> **Date:** 2026-12-26
> **Updated:** 2025-12-26
> **Superseded By:** BinaryIndex Module Architecture
> **Related Sprints:** [`SPRINT_20251226_011_BINIDX_known_build_catalog.md`](../implplan/SPRINT_20251226_011_BINIDX_known_build_catalog.md), [`SPRINT_20251226_012_BINIDX_backport_handling.md`](../implplan/SPRINT_20251226_012_BINIDX_backport_handling.md), [`SPRINT_20251226_013_BINIDX_fingerprint_factory.md`](../implplan/SPRINT_20251226_013_BINIDX_fingerprint_factory.md), [`SPRINT_20251226_014_BINIDX_scanner_integration.md`](../implplan/SPRINT_20251226_014_BINIDX_scanner_integration.md)
---
## Supersession Notice
This advisory has been **superseded** by the comprehensive BinaryIndex module architecture. All proposals in this advisory are covered by the existing design:
| Advisory Proposal | Implementation | Location |
|-------------------|----------------|----------|
| artifacts table | `binaries.binary_identity` | `docs/modules/binaryindex/architecture.md` |
| symbols table | `BinaryFeatures` in `IBinaryFeatureExtractor` | `src/BinaryIndex/__Libraries/.../Services/` |
| vuln_segments (byte_sig/patch_sig) | `VulnFingerprint` model | `src/BinaryIndex/__Libraries/.../Fingerprints/` |
| matches table | `FingerprintMatch` model | `src/BinaryIndex/__Libraries/.../Fingerprints/` |
| reachability_hints | `ReachabilityStatus` enum | `src/BinaryIndex/__Libraries/.../Models/` |
| Build-ID/PE indexer | `ElfFeatureExtractor`, `IBinaryFeatureExtractor` | `src/BinaryIndex/__Libraries/.../Services/` |
| Patch-aware handling | `FixEvidence`, changelog/patch parsers | `src/BinaryIndex/__Libraries/.../FixIndex/` |
| Corpus connectors | `DebianCorpusConnector`, `IBinaryCorpusConnector` | `src/BinaryIndex/__Libraries/.../Corpus/` |
### Related Archived Advisories
- `18-Dec-2025 - Building Better Binary Mapping and CallStack Reachability.md`
- `23-Dec-2026 - Binary Mapping as Attestable Proof.md`
### Related Active Advisories
- `25-Dec-2025 - Evolving Evidence Models for Reachability.md` - Runtime → build braid, eBPF sampling
---
## Original Advisory Content
Here's a compact blueprint for a **binarylevel knowledge base** that maps ELF BuildIDs / PE signatures to vulnerable functions, patch lineage, and reachability hints—so your scanner can act like a provenanceaware "binary oracle," not just a CVE lookup.
---
# Why this matters (in plain terms)
* **Same version ≠ same risk.** Distros (and vendors) frequently **backport** fixes without bumping versions. Only the **binary** tells the truth.
* **Functionlevel matching** turns noisy package has CVE into precise this exact function range is vulnerable in your binary.
* **Functionlevel matching** turns noisy "package has CVE" into precise "this exact function range is vulnerable in your binary."
* **Reachability hints** cut triage noise by ranking vulns the code path can actually hit at runtime.
---
@@ -40,7 +78,7 @@ Keep it tiny so it grows with real evidence:
* `patch_sig` (pattern from fixed hunk)
* `evidence_ref` (link to patch diff, commit, or NVD note)
* `backport_flag` (bool)
* `introduced_in`, `fixed_in` (semver-ish text; note backport when used)
* `introduced_in`, `fixed_in` (semver-ish text; note "backport" when used)
**matches**
@@ -57,7 +95,7 @@ Keep it tiny so it grows with real evidence:
---
# How the oracle answers Am I affected?
# How the oracle answers "Am I affected?"
1. **Identify**: Look up by BuildID / PE signature; fall back to file hash.
2. **Locate**: Map symbols → address ranges; scan for `byte_sig`/`patch_sig`.
@@ -81,10 +119,10 @@ Keep it tiny so it grows with real evidence:
---
# Deterministic verdicts (fit to StellaOps)
# Deterministic verdicts (fit to Stella Ops)
* **Inputs**: `(artifact fingerprint, vuln_segments@version, reachability@policy)`
* **Output**: **Signed OCI attestation** verdict.json (same inputs → same verdict).
* **Output**: **Signed OCI attestation** "verdict.json" (same inputs → same verdict).
* **Replay**: keep rule bundle & feed hashes for audit.
* **Backport precedence**: `patch_sig` beats package version claims every time.
@@ -94,7 +132,7 @@ Keep it tiny so it grows with real evidence:
* Add a **BuildID/PE indexer** to Scanner.
* Teach Feedser/Vexer to ingest `vuln_segments` (with `byte_sig`/`patch_sig`).
* Implement matching + verdict attestation; surface **Backported & Safe** vs **Affected & Reachable** badges in UI.
* Implement matching + verdict attestation; surface **"Backported & Safe"** vs **"Affected & Reachable"** badges in UI.
* Seed DB with 10 highimpact CVEs (OpenSSL, zlib, xz, glibc, libxml2, curl, musl, busybox, OpenSSH, sudo).
---
@@ -135,11 +173,3 @@ create table reachability_hints(
symbol_name text, hint_type text, weight int
);
```
---
If you want, I can:
* drop in a tiny **.NET 10** matcher (ELF/PE parsers + bytewindow scanner),
* wire verdicts as **OCI attestations** in your current pipeline,
* and prep the first **10 CVE byte/patch signatures** to seed the DB.

View File

@@ -0,0 +1,79 @@
# Archived Superseded Advisories
**Archived:** 2025-12-26
**Reason:** Concepts already implemented or covered by existing sprints
## Advisory Status
These advisories described features that are **already substantially implemented** in the codebase or covered by existing sprint files.
| Advisory | Status | Superseded By |
|----------|--------|---------------|
| `25-Dec-2025 - Implementing DiffAware Release Gates.md` | SUPERSEDED | SPRINT_20251226_001_BE through 006_DOCS |
| `26-Dec-2026 - DiffAware Releases and Auditable Exceptions.md` | SUPERSEDED | SPRINT_20251226_003_BE_exception_approval.md |
| `26-Dec-2026 - SmartDiff as a Core Evidence Primitive.md` | SUPERSEDED | Existing DeltaVerdict library |
| `26-Dec-2026 - Reachability as Cryptographic Proof.md` | SUPERSEDED | Existing ProofChain library + SPRINT_007/009/010/011 |
## Existing Implementation
The following components already implement the advisory concepts:
### DeltaVerdict & DeltaComputer
- `src/Policy/__Libraries/StellaOps.Policy/Deltas/DeltaVerdict.cs`
- `src/Policy/__Libraries/StellaOps.Policy/Deltas/DeltaComputer.cs`
- `src/__Libraries/StellaOps.DeltaVerdict/` (complete library)
### Exception Management
- `src/Policy/__Libraries/StellaOps.Policy.Storage.Postgres/Models/ExceptionEntity.cs`
- `src/Policy/StellaOps.Policy.Engine/Adapters/ExceptionAdapter.cs`
- `src/Policy/__Libraries/StellaOps.Policy.Exceptions/` (complete library)
### ProofChain & Reachability Proofs
- `src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/` (complete library):
- `Statements/ReachabilityWitnessStatement.cs` - Entry→sink proof chains
- `Statements/ReachabilitySubgraphStatement.cs` - Minimal subgraph attestation
- `Statements/ProofSpineStatement.cs` - Merkle-aggregated proof bundles
- `Predicates/ReachabilitySubgraphPredicate.cs` - Subgraph predicate
- `Identifiers/ContentAddressedIdGenerator.cs` - Content-addressed IDs
- `Merkle/DeterministicMerkleTreeBuilder.cs` - Merkle tree construction
- `Signing/ProofChainSigner.cs` - DSSE signing
- `Verification/VerificationPipeline.cs` - Proof verification
- `src/__Libraries/StellaOps.Replay.Core/ReplayManifest.cs` - Replay manifests
### Covering Sprints
- `docs/implplan/SPRINT_20251226_001_BE_cicd_gate_integration.md` - Gate endpoints, CI/CD
- `docs/implplan/SPRINT_20251226_002_BE_budget_enforcement.md` - Risk budget automation
- `docs/implplan/SPRINT_20251226_003_BE_exception_approval.md` - Exception workflows (21 tasks)
- `docs/implplan/SPRINT_20251226_004_FE_risk_dashboard.md` - Side-by-side UI
- `docs/implplan/SPRINT_20251226_005_SCANNER_reachability_extractors.md` - Language extractors
- `docs/implplan/SPRINT_20251226_006_DOCS_advisory_consolidation.md` - Documentation
- `docs/implplan/SPRINT_20251226_007_BE_determinism_gaps.md` - Determinism gaps, metrics (25 tasks)
- `docs/implplan/SPRINT_20251226_009_SCANNER_funcproof.md` - FuncProof generation (18 tasks)
- `docs/implplan/SPRINT_20251226_010_SIGNALS_runtime_stack.md` - eBPF stack capture (17 tasks)
- `docs/implplan/SPRINT_20251226_011_BE_auto_vex_downgrade.md` - Auto-VEX from runtime (16 tasks)
## Remaining Gaps Added to Sprints
Minor gaps from these advisories were added to existing sprints:
**Added to SPRINT_20251226_003_BE_exception_approval.md:**
- EXCEPT-16: Auto-revalidation job
- EXCEPT-17: Re-review gate flip on failure
- EXCEPT-18: Exception inheritance (repo→image→env)
- EXCEPT-19: Conflict surfacing for shadowed exceptions
- EXCEPT-20: OCI-attached exception attestation
- EXCEPT-21: CLI export command
**Added to SPRINT_20251226_007_BE_determinism_gaps.md:**
- DET-GAP-21: Proof generation rate metric
- DET-GAP-22: Median proof size metric
- DET-GAP-23: Replay success rate metric
- DET-GAP-24: Proof dedup ratio metric
- DET-GAP-25: "Unknowns" burn-down tracking
## Cross-References
If you arrived here via a broken link, see:
- `docs/implplan/SPRINT_20251226_*.md` for implementation tasks
- `src/Policy/__Libraries/StellaOps.Policy/Deltas/` for delta computation
- `src/__Libraries/StellaOps.DeltaVerdict/` for verdict models

View File

@@ -0,0 +1,105 @@
# Visual Diffs for Explainable Triage
> **Status:** PLANNED — Enhancement sprint created
> **Date:** 2025-12-25
> **Updated:** 2025-12-26
> **Implementation:** ~75-80% complete in existing infrastructure
> **Sprint:** [`SPRINT_20251226_010_FE_visual_diff_enhancements.md`](../implplan/SPRINT_20251226_010_FE_visual_diff_enhancements.md)
---
## Implementation Status
Most features proposed in this advisory are **already implemented**:
| Feature | Status | Location |
|---------|--------|----------|
| Three-pane layout (Categories/Items/Proof) | COMPLETE | `smart-diff-ui-architecture.md` |
| Delta summary strip | COMPLETE | `DeltaSummaryStripComponent` |
| Evidence rail with witness paths | COMPLETE | `ProofPaneComponent`, `WitnessPathComponent` |
| VEX merge explanations | COMPLETE | `VexMergeExplanationComponent` |
| Role-based views (Dev/Security/Audit) | COMPLETE | `CompareViewComponent` |
| Keyboard shortcuts | COMPLETE | `TriageShortcutsService` |
| Audit bundle export | COMPLETE | `ExportActionsComponent` |
| Delta computation engine | COMPLETE | `StellaOps.DeltaVerdict.Engine` |
| Signed delta verdicts | COMPLETE | `DeltaSigningService` |
| **Visual graph diff with highlights** | TODO | Sprint VD-ENH-01..04 |
| **"Explain like I'm new" toggle** | TODO | Sprint VD-ENH-05..07 |
| **Graph export (SVG/PNG)** | TODO | Sprint VD-ENH-08 |
### Existing Infrastructure
- `TriageWorkspaceComponent` (1042 lines) - Full triage workspace
- `ProofTreeComponent` (1009 lines) - Merkle tree visualization
- `docs/modules/web/smart-diff-ui-architecture.md` - Architecture specification
- `StellaOps.DeltaVerdict` library - Backend delta computation
---
## Advisory Content
Here's a simple, high-leverage UX pattern you can borrow from top observability tools: **treat every policy decision or reachability change as a visual diff.**
---
### Why this helps
* Turns opaque "why is this verdict different?" moments into **quick, explainable triage**.
* Reduces back-and-forth between Security, Dev, and Audit—**everyone sees the same before/after evidence**.
### Core UI concept
* **Side-by-side panes**: **Before** (previous scan/policy) vs **After** (current).
* **Graph focus**: show the dependency/reachability subgraph; **highlight added/removed/changed nodes/edges**.
* **Evidence strip** (right rail): human-readable facts used by the engine (e.g., *feature flag OFF*, *code path unreachable*, *kernel eBPF trace absent*).
* **Diff verdict header**: "Risk ↓ from *Medium → Low* (policy v1.8 → v1.9)".
* **Filter chips**: Scope by component, package, CVE, policy rule, environment.
### Minimal data model (so UI is easy)
* `GraphSnapshot`: nodes, edges, metadata (component, version, tags).
* `PolicySnapshot`: version, rules hash, inputs (flags, env, VEX sources).
* `Delta`: `added/removed/changed` for nodes, edges, and rule outcomes.
* `EvidenceItems[]`: typed facts (trace hits, SBOM lines, VEX claims, config values) with source + timestamp.
* `SignedDeltaVerdict`: final status + signatures (who/what produced it).
### Micro-interactions that matter
* Hover a changed node ⇒ **inline badge** explaining *why it changed* (e.g., "now gated by `--no-xml` runtime flag").
* Click a rule change in the right rail ⇒ **spotlight** the exact subgraph it affected.
* Toggle **"explain like I'm new"** ⇒ expands jargon into plain language.
* One-click **"copy audit bundle"** ⇒ exports the delta + evidence as an attachment.
### Where this belongs in your product
* **Primary**: in the **Triage** view for any new finding/regression.
* **Secondary**: in **Policy history** (compare vX vs vY) and **Release gates** (compare build A vs build B).
* **Inline surfaces**: small "diff pills" next to every verdict in tables; click opens the big side-by-side.
### Quick build checklist (dev & PM)
* [x] Compute a stable **graph hash** per scan; store **snapshots**. *(Implemented: `DeltaComputationEngine`)*
* [x] Add a **delta builder** that outputs `added/removed/changed` at node/edge + rule outcome levels. *(Implemented: `DeltaVerdictBuilder`)*
* [x] Normalize **evidence items** (source, digest, excerpt) so the UI can render consistent cards. *(Implemented: `ProofTreeComponent`)*
* [x] Ship a **Signed Delta Verdict** (OCI-attached) so audits can replay the view from the artifact alone. *(Implemented: `DeltaSigningService`)*
* [ ] Include **hotkeys**: `1` focus changes only, `2` show full graph, `E` expand evidence, `A` export audit. *(Partial: general shortcuts exist)*
### Empty state & failure modes
* If evidence is incomplete: show a **yellow "Unknowns present" ribbon** with a count and a button to collect missing traces.
* If graphs are huge: default to **"changed neighborhood only"** with a mini-map to pan.
### Success metric (simple)
* **Mean time to explain (MTTE)**: time from "why did this change?" to user clicking *"Understood"*. Track trend ↓.
---
## Related Advisories
| Advisory | Relationship |
|----------|--------------|
| [Triage UI Lessons from Competitors](./25-Dec-2025%20-%20Triage%20UI%20Lessons%20from%20Competitors.md) | Complementary - competitive UX patterns |
| [Implementing Diff-Aware Release Gates](./25-Dec-2025%20-%20Implementing%20Diff%E2%80%91Aware%20Release%20Gates.md) | Backend - IMPLEMENTED |
| [Smart-Diff as Core Evidence Primitive](./26-Dec-2026%20-%20Smart%E2%80%91Diff%20as%20a%20Core%20Evidence%20Primitive.md) | Data model - IMPLEMENTED |
| [Visualizing the Risk Budget](./26-Dec-2026%20-%20Visualizing%20the%20Risk%20Budget.md) | Related - Risk visualization |

View File

@@ -0,0 +1,33 @@
# Archived Triage/Visualization Advisories
**Archived:** 2025-12-26
**Reason:** Consolidated into unified specification
## Advisory Consolidation
These 3 advisories contained overlapping concepts about triage UI, visual diffs, and risk budget visualization. They have been consolidated into a single authoritative specification:
**Consolidated Into:** `docs/modules/web/unified-triage-specification.md`
## Archived Advisories
| Advisory | Primary Concepts | Preserved In |
|----------|------------------|--------------|
| `25-Dec-2025 - Triage UI Lessons from Competitors.md` | Snyk/Anchore/Prisma analysis, 4 recommendations | Section 2: Competitive Landscape |
| `25-Dec-2025 - Visual Diffs for Explainable Triage.md` | Side-by-side panes, evidence strip, micro-interactions | Section 3: Core UI Concepts |
| `26-Dec-2026 - Visualizing the Risk Budget.md` | Burn-up charts, heatmaps, exception ledger | Section 4: Risk Budget Visualization |
## Implementation Sprints
The consolidated specification is implemented by:
- `SPRINT_20251226_004_FE_risk_dashboard.md` - Risk budget visualization
- `SPRINT_20251226_012_FE_smart_diff_compare.md` - Smart-Diff Compare View
- `SPRINT_20251226_013_FE_triage_canvas.md` - Unified Triage Canvas
- `SPRINT_20251226_014_DOCS_triage_consolidation.md` - Documentation tasks
## Cross-References
If you arrived here via a broken link, the content you're looking for is now in:
- `docs/modules/web/unified-triage-specification.md`
- `docs/modules/web/smart-diff-ui-architecture.md`

View File

@@ -0,0 +1,59 @@
# Archived VEX Scoring Advisory
**Archived:** 2025-12-26
**Reason:** Concepts substantially implemented in VexLens module
## Advisory Status
The "Weighted Confidence for VEX Sources" advisory described a scoring lattice for VEX sources using the formula `Score(e) = C(e) × F(e) × S_claim(e)`. This is **substantially implemented** in the existing codebase.
## Existing Implementation
### SourceTrustScoreCalculator (VexLens)
Location: `src/VexLens/StellaOps.VexLens/Trust/SourceTrust/SourceTrustScoreCalculator.cs`
Implements multi-dimensional trust scoring:
- **Authority Score** - Source category (Vendor, Distributor, Community, Internal, Aggregator), trust tier, official source bonus
- **Accuracy Score** - Confirmation rate, false positive rate, revocation rate, consistency
- **Timeliness Score** - Response time, update frequency, freshness
- **Coverage Score** - CVE coverage ratio, product breadth, completeness
- **Verification Score** - Signature validity, provenance integrity, issuer verification
### TrustDecayService (VexLens)
Location: `src/VexLens/StellaOps.VexLens/Trust/SourceTrust/TrustDecayService.cs`
Implements freshness decay with configurable τ values per source class.
### TrustLatticeEngine (Policy)
Location: `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/TrustLatticeEngine.cs`
Implements:
- K4 lattice with security atoms (Present, Applies, Reachable, Mitigated, Fixed, Misattributed)
- VEX normalization (CycloneDX, OpenVEX, CSAF)
- Proof bundle generation with decision traces
- Lattice merge with claim precedence
### VexConsensusEngine (VexLens)
Location: `src/VexLens/StellaOps.VexLens/Consensus/VexConsensusEngine.cs`
Handles multi-source VEX consensus with configurable merge policies.
## Advisory Concepts → Implementation Mapping
| Advisory Concept | Implementation |
|------------------|----------------|
| Confidence C(e) factors | `SourceTrustScoreCalculator` with 5 component scores |
| Freshness F(e) decay | `TrustDecayService` with configurable τ per source |
| Claim strength S_claim | `TrustLatticeEngine` security atoms + disposition selector |
| Lattice merge ordering | `K4Lattice` with precedence rules |
| Signature strength | `VerificationScoreCalculator` with signature/provenance scoring |
| Consensus bonus | `VexConsensusEngine` with multi-source corroboration |
| Policy hooks | `PolicyBundle` with override rules |
| Replay/determinism | `ProofBundle` with decision traces |
## Cross-References
If you arrived here via a broken link, see:
- `src/VexLens/StellaOps.VexLens/Trust/` for trust scoring
- `src/Policy/__Libraries/StellaOps.Policy/TrustLattice/` for lattice logic
- `docs/modules/vexlens/` for VexLens documentation

71
src/Signer/AGENTS.md Normal file
View File

@@ -0,0 +1,71 @@
# Signer Module — Agent Charter
## Mission
Provide cryptographic signing services for StellaOps attestations:
- Sign DSSE envelopes for SBOMs, verdicts, and reports
- Support multiple signing modes: keyless (Fulcio), KMS, HSM, FIDO2
- Enforce entitlement (PoE), release integrity, and plan quotas
- Return verifiable bundles suitable for Rekor transparency logging
- Maintain audit trails for all signing operations
## Expectations
- Coordinate with Authority for OIDC tokens and DPoP/mTLS validation
- Coordinate with Attestor for downstream Rekor submission
- Maintain deterministic serialization for reproducible signatures
- Support offline operation with KMS/HSM modes for air-gapped deployments
- Provide REST APIs for signing operations and release verification
- Keep signing key management schema current with migrations
## Key Components
- **StellaOps.Signer.Core**: Core abstractions, pipeline, and contracts
- **StellaOps.Signer.Infrastructure**: Signing implementations, DI extensions
- **StellaOps.Signer.WebService**: REST API endpoints
- **StellaOps.Signer.Keyless**: Fulcio integration for keyless signing (Sprint 20251226_001)
- **__Libraries/StellaOps.Signer.KeyManagement**: Key rotation and trust anchor management
- **__Tests**: Unit and integration tests
## Required Reading
- `docs/modules/signer/architecture.md`
- `docs/modules/signer/README.md` (if exists)
- `docs/modules/platform/architecture-overview.md`
- `docs/product-advisories/25-Dec-2025 - Planning Keyless Signing for Verdicts.md`
- Sigstore Fulcio documentation: https://docs.sigstore.dev/certificate_authority/overview/
## Working Agreement
1. Update task status to `DOING`/`DONE` in both corresponding sprint file `/docs/implplan/SPRINT_*.md` and local `TASKS.md` when you start or finish work.
2. Review this charter and the Required Reading documents before coding; confirm prerequisites are met.
3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
## Signing Modes
- **Keyless (Fulcio)**: Ephemeral ECDSA/Ed25519 keys, short-lived X.509 certs from Fulcio, OIDC identity binding
- **KMS**: AWS KMS, GCP KMS, Azure Key Vault — hardware-backed, no key exposure
- **HSM (PKCS#11)**: On-premise HSM integration for sovereign/air-gapped environments
- **FIDO2**: WebAuthn authenticator for dual-control scenarios
- **File**: Encrypted key files for development/testing
## Predicate Types
- `stella.ops/sbom@v1`: SBOM attestation (CycloneDX/SPDX)
- `stella.ops/report@v1`: Final PASS/FAIL vulnerability report
- `stella.ops/vexDecision@v1`: OpenVEX decision with reachability evidence
- `verdict.stella/v1`: Policy verdict attestation (Sprint 20251226_001)
- `stella.ops/promotion@v1`: Promotion/release gate evidence
## Guardrails
- Ephemeral keys MUST NOT persist to disk; zero memory on disposal
- All timestamps in UTC ISO-8601
- Preserve determinism: canonical JSON (RFC 8785), stable ordering
- No bearer token fallbacks — DPoP/mTLS enforced for `aud=signer`
- Fulcio certificate chains MUST validate to configured roots
- Audit every signing decision; expose metrics
- Keep Offline Kit parity in mind — document air-gapped workflows for KMS/HSM modes
## Active Sprints
- `SPRINT_20251226_001_SIGNER_fulcio_keyless_client.md` — Fulcio keyless signing implementation
## Related Modules
- **Authority**: OIDC tokens, DPoP, mTLS validation
- **Attestor**: Rekor submission, attestation storage, verification
- **Cryptography**: Crypto profiles (ECDSA, Ed25519, SM2)
- **Scheduler**: Bundle rotation jobs