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:
@@ -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 |
|
||||||
@@ -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*
|
||||||
596
docs/implplan/SPRINT_20251226_002_ATTESTOR_bundle_rotation.md
Normal file
596
docs/implplan/SPRINT_20251226_002_ATTESTOR_bundle_rotation.md
Normal 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*
|
||||||
51
docs/implplan/SPRINT_20251226_002_BE_budget_enforcement.md
Normal file
51
docs/implplan/SPRINT_20251226_002_BE_budget_enforcement.md
Normal 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 |
|
||||||
@@ -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*
|
||||||
60
docs/implplan/SPRINT_20251226_003_BE_exception_approval.md
Normal file
60
docs/implplan/SPRINT_20251226_003_BE_exception_approval.md
Normal 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 |
|
||||||
621
docs/implplan/SPRINT_20251226_004_BE_cicd_signing_templates.md
Normal file
621
docs/implplan/SPRINT_20251226_004_BE_cicd_signing_templates.md
Normal 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*
|
||||||
56
docs/implplan/SPRINT_20251226_004_FE_risk_dashboard.md
Normal file
56
docs/implplan/SPRINT_20251226_004_FE_risk_dashboard.md
Normal 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 |
|
||||||
@@ -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 |
|
||||||
@@ -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 |
|
||||||
85
docs/implplan/SPRINT_20251226_007_BE_determinism_gaps.md
Normal file
85
docs/implplan/SPRINT_20251226_007_BE_determinism_gaps.md
Normal 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 |
|
||||||
@@ -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 |
|
||||||
98
docs/implplan/SPRINT_20251226_009_SCANNER_funcproof.md
Normal file
98
docs/implplan/SPRINT_20251226_009_SCANNER_funcproof.md
Normal 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 |
|
||||||
354
docs/implplan/SPRINT_20251226_010_FE_visual_diff_enhancements.md
Normal file
354
docs/implplan/SPRINT_20251226_010_FE_visual_diff_enhancements.md
Normal 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)
|
||||||
81
docs/implplan/SPRINT_20251226_010_SIGNALS_runtime_stack.md
Normal file
81
docs/implplan/SPRINT_20251226_010_SIGNALS_runtime_stack.md
Normal 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 |
|
||||||
103
docs/implplan/SPRINT_20251226_011_BE_auto_vex_downgrade.md
Normal file
103
docs/implplan/SPRINT_20251226_011_BE_auto_vex_downgrade.md
Normal 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 |
|
||||||
214
docs/implplan/SPRINT_20251226_011_BINIDX_known_build_catalog.md
Normal file
214
docs/implplan/SPRINT_20251226_011_BINIDX_known_build_catalog.md
Normal 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)
|
||||||
234
docs/implplan/SPRINT_20251226_012_BINIDX_backport_handling.md
Normal file
234
docs/implplan/SPRINT_20251226_012_BINIDX_backport_handling.md
Normal 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/)
|
||||||
99
docs/implplan/SPRINT_20251226_012_FE_smart_diff_compare.md
Normal file
99
docs/implplan/SPRINT_20251226_012_FE_smart_diff_compare.md
Normal 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 |
|
||||||
240
docs/implplan/SPRINT_20251226_013_BINIDX_fingerprint_factory.md
Normal file
240
docs/implplan/SPRINT_20251226_013_BINIDX_fingerprint_factory.md
Normal 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)
|
||||||
117
docs/implplan/SPRINT_20251226_013_FE_triage_canvas.md
Normal file
117
docs/implplan/SPRINT_20251226_013_FE_triage_canvas.md
Normal 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 |
|
||||||
274
docs/implplan/SPRINT_20251226_014_BINIDX_scanner_integration.md
Normal file
274
docs/implplan/SPRINT_20251226_014_BINIDX_scanner_integration.md
Normal 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)
|
||||||
124
docs/implplan/SPRINT_20251226_014_DOCS_triage_consolidation.md
Normal file
124
docs/implplan/SPRINT_20251226_014_DOCS_triage_consolidation.md
Normal 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 |
|
||||||
75
docs/implplan/SPRINT_20251226_015_AI_zastava_companion.md
Normal file
75
docs/implplan/SPRINT_20251226_015_AI_zastava_companion.md
Normal 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 |
|
||||||
81
docs/implplan/SPRINT_20251226_016_AI_remedy_autopilot.md
Normal file
81
docs/implplan/SPRINT_20251226_016_AI_remedy_autopilot.md
Normal 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 |
|
||||||
80
docs/implplan/SPRINT_20251226_017_AI_policy_copilot.md
Normal file
80
docs/implplan/SPRINT_20251226_017_AI_policy_copilot.md
Normal 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 |
|
||||||
78
docs/implplan/SPRINT_20251226_018_AI_attestations.md
Normal file
78
docs/implplan/SPRINT_20251226_018_AI_attestations.md
Normal 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 |
|
||||||
91
docs/implplan/SPRINT_20251226_019_AI_offline_inference.md
Normal file
91
docs/implplan/SPRINT_20251226_019_AI_offline_inference.md
Normal 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 |
|
||||||
273
docs/modules/signer/guides/keyless-signing.md
Normal file
273
docs/modules/signer/guides/keyless-signing.md
Normal 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/)
|
||||||
348
docs/modules/web/unified-triage-specification.md
Normal file
348
docs/modules/web/unified-triage-specification.md
Normal 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/)
|
||||||
@@ -1,104 +1,146 @@
|
|||||||
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 auditor‑grade 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 auditor‑grade trails and signed "delta verdicts."
|
||||||
|
|
||||||
|
## Why this matters (quick)
|
||||||
|
|
||||||
* **Reproducibility:** auditors can replay any scan and get identical results.
|
* **Reproducibility:** auditors can replay any scan and get identical results.
|
||||||
* **Trust & scale:** cross‑agent consensus via content‑addressed inputs and signed outputs.
|
* **Trust & scale:** cross‑agent consensus via content‑addressed inputs and signed outputs.
|
||||||
* **Operational clarity:** diffs between builds become crisp, machine‑verifiable artifacts.
|
* **Operational clarity:** diffs between builds become crisp, machine‑verifiable artifacts.
|
||||||
|
|
||||||
# Core principles
|
## Core principles
|
||||||
|
|
||||||
* **Determinism-first:** no wall‑clock time, no random iteration order, no network during evaluation.
|
* **Determinism-first:** no wall‑clock time, no random iteration order, no network during evaluation.
|
||||||
* **Content‑addressing:** hash every *input* (SBOM, VEX docs, reachability subgraph, policy set, rule versions, feed snapshots).
|
* **Content‑addressing:** 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.
|
* **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)`.
|
* **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`)**
|
* **Scan Manifest (`manifest.jsonc`)**
|
||||||
|
|
||||||
* `sbom_sha256`, `vex_set_sha256[]`, `reach_subgraph_sha256`, `feeds_snapshot_sha256`, `policy_bundle_sha256`, `engine_version`, `policy_semver`, `options_hash`
|
* `sbom_sha256`, `vex_set_sha256[]`, `reach_subgraph_sha256`, `feeds_snapshot_sha256`, `policy_bundle_sha256`, `engine_version`, `policy_semver`, `options_hash`
|
||||||
|
|
||||||
* **Verdict (`verdict.json`)**
|
* **Verdict (`verdict.json`)**
|
||||||
|
|
||||||
* canonical JSON (stable key order); includes:
|
* canonical JSON (stable key order); includes:
|
||||||
|
|
||||||
* `risk_score`, `status` (pass/warn/fail), `unknowns_count`
|
* `risk_score`, `status` (pass/warn/fail), `unknowns_count`
|
||||||
* **evidence_refs:** content IDs for cited VEX statements, nodes/edges from reachability, CVE records, feature‑flags, env‑guards
|
* **evidence_refs:** content IDs for cited VEX statements, nodes/edges from reachability, CVE records, feature‑flags, env‑guards
|
||||||
* **explanations:** stable, template‑driven strings (+ machine reasons)
|
* **explanations:** stable, template‑driven strings (+ machine reasons)
|
||||||
|
|
||||||
* **Delta Verdict (`delta.json`)**
|
* **Delta Verdict (`delta.json`)**
|
||||||
|
|
||||||
* computed between two manifests/verdicts:
|
* computed between two manifests/verdicts:
|
||||||
|
|
||||||
* `added_findings[]`, `removed_findings[]`, `severity_shift[]`, `unknowns_delta`, `policy_effects[]`
|
* `added_findings[]`, `removed_findings[]`, `severity_shift[]`, `unknowns_delta`, `policy_effects[]`
|
||||||
* signed (DSSE/COSE/JWS), time‑stamped, and linkable to both verdicts
|
* signed (DSSE/COSE/JWS), time‑stamped, and linkable to both verdicts
|
||||||
|
|
||||||
# Engine architecture (deterministic path)
|
## Engine architecture (deterministic path)
|
||||||
|
|
||||||
1. **Normalize inputs**
|
1. **Normalize inputs**
|
||||||
|
|
||||||
* SBOM: sort by `packageUrl`/`name@version`; resolve aliases; freeze semver comparison rules.
|
* 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).
|
* 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.
|
* 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.
|
* 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., OPA‑Rego → sorted DNF).
|
* Declarative rules (e.g., lattice/merge semantics), compiled to a **canonical IR** (e.g., OPA‑Rego → sorted DNF).
|
||||||
* Merge precedence is explicit (e.g., `vendor > distro > internal` can be replaced by a lattice‑merge table).
|
* Merge precedence is explicit (e.g., `vendor > distro > internal` can be replaced by a lattice‑merge table).
|
||||||
* Unknowns policy baked in: e.g., `fail_if_unknowns > N in prod`.
|
* 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.
|
* Build a **finding set**: `(component, vuln, context)` tuples with deterministic IDs.
|
||||||
* Apply **lattice‑based VEX merge** (proof‑carrying): each suppression must carry an evidence pointer (feature flag off, code path unreachable, patched‑backport proof).
|
* Apply **lattice‑based VEX merge** (proof‑carrying): each suppression must carry an evidence pointer (feature flag off, code path unreachable, patched‑backport proof).
|
||||||
* Compute final `status` and `risk_score` using fixed‑precision math; round rules are part of the bundle.
|
* Compute final `status` and `risk_score` using fixed‑precision math; round rules are part of the bundle.
|
||||||
4. **Emit**
|
|
||||||
|
|
||||||
|
4. **Emit**
|
||||||
* Canonicalize verdict JSON; attach **evidence map** (content IDs only).
|
* Canonicalize verdict JSON; attach **evidence map** (content IDs only).
|
||||||
* Sign verdict; attach as **OCI attestation** to image/digest.
|
* Sign verdict; attach as **OCI attestation** to image/digest.
|
||||||
|
|
||||||
# APIs (minimal but complete)
|
## APIs (minimal but complete)
|
||||||
|
|
||||||
* `POST /evaluate` → returns `verdict.json` + attestation
|
* `POST /evaluate` → returns `verdict.json` + attestation
|
||||||
* `POST /delta` with `{base_verdict, head_verdict}` → `delta.json` (signed)
|
* `POST /delta` with `{base_verdict, head_verdict}` → `delta.json` (signed)
|
||||||
* `GET /replay?manifest_sha=` → re‑executes using cached snapshot bundles, returns the same `verdict_sha`
|
* `GET /replay?manifest_sha=` → re‑executes using cached snapshot bundles, returns the same `verdict_sha`
|
||||||
* `GET /evidence/:cid` → fetches immutable evidence blobs (offline‑ready)
|
* `GET /evidence/:cid` → fetches immutable evidence blobs (offline‑ready)
|
||||||
|
|
||||||
# Storage & indexing
|
## Storage & indexing
|
||||||
|
|
||||||
* **CAS (content‑addressable store):** `/evidence/<sha256>` for SBOM/VEX/graphs/feeds/policies.
|
* **CAS (content‑addressable store):** `/evidence/<sha256>` for SBOM/VEX/graphs/feeds/policies.
|
||||||
* **Verdict registry:** keyed by `(image_digest, manifest_sha, engine_version)`.
|
* **Verdict registry:** keyed by `(image_digest, manifest_sha, engine_version)`.
|
||||||
* **Delta ledger:** append‑only, signed; supports cross‑agent consensus (multiple engines can co‑sign identical deltas).
|
* **Delta ledger:** append‑only, signed; supports cross‑agent consensus (multiple engines can co‑sign identical deltas).
|
||||||
|
|
||||||
# UI slices (where it lives)
|
## UI slices (where it lives)
|
||||||
|
|
||||||
* **Run details → “Verdict” tab:** status, risk score, unknowns, top evidence links.
|
* **Run details → "Verdict" tab:** status, risk score, unknowns, top evidence links.
|
||||||
* **“Diff” tab:** render **Delta Verdict** (added/removed/changed), with drill‑down to proofs.
|
* **"Diff" tab:** render **Delta Verdict** (added/removed/changed), with drill‑down to proofs.
|
||||||
* **“Replay” button:** shows the exact manifest & engine version; one‑click re‑evaluation (offline possible).
|
* **"Replay" button:** shows the exact manifest & engine version; one‑click re‑evaluation (offline possible).
|
||||||
* **Audit export:** zip of `manifest.jsonc`, `verdict.json`, `delta.json` (if any), attestation, and referenced evidence.
|
* **Audit export:** zip of `manifest.jsonc`, `verdict.json`, `delta.json` (if any), attestation, and referenced evidence.
|
||||||
|
|
||||||
# Testing & QA (must‑have)
|
## Testing & QA (must‑have)
|
||||||
|
|
||||||
* **Golden tests:** fixtures of manifests → frozen verdict JSONs (byte‑for‑byte).
|
* **Golden tests:** fixtures of manifests → frozen verdict JSONs (byte‑for‑byte).
|
||||||
* **Chaos determinism tests:** vary thread counts, env vars, map iteration seeds; assert identical verdicts.
|
* **Chaos determinism tests:** vary thread counts, env vars, map iteration seeds; assert identical verdicts.
|
||||||
* **Cross‑engine round‑trips:** two independent builds of the engine produce the same verdict for the same manifest.
|
* **Cross‑engine round‑trips:** two independent builds of the engine produce the same verdict for the same manifest.
|
||||||
* **Time‑travel tests:** replay older feed snapshots to ensure stability.
|
* **Time‑travel 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).
|
1. **Phase 1:** Introduce Manifest + canonical verdict format alongside existing policy engine (shadow mode).
|
||||||
2. **Phase 2:** Make verdicts the **first‑class artifact** (OCI‑attached); ship UI “Verdict/Diff”.
|
2. **Phase 2:** Make verdicts the **first‑class artifact** (OCI‑attached); ship UI "Verdict/Diff".
|
||||||
3. **Phase 3:** Enforce **delta‑gates** in CI/CD (risk budgets + exception packs referenceable by content ID).
|
3. **Phase 3:** Enforce **delta‑gates** 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.
|
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 “preserve‑prune source.”
|
* **scanner.webservice:** keep lattice algorithms here (per your standing rule). Concelier/Excitors "preserve‑prune source."
|
||||||
* **Authority/Attestor:** handle DSSE signing, key management, regional crypto profiles (eIDAS/FIPS/GOST/SM).
|
* **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.
|
* **Feedser/Vexer:** produce immutable **snapshot bundles**; never query live during evaluation.
|
||||||
* **Router/Scheduler:** schedule replay jobs; cache manifests to speed up audits.
|
* **Router/Scheduler:** schedule replay jobs; cache manifests to speed up audits.
|
||||||
* **Db:** Postgres as SoR; Valkey only for ephemeral queues/caches (per your BSD‑only profile).
|
* **Db:** Postgres as SoR; Valkey only for ephemeral queues/caches (per your BSD‑only profile).
|
||||||
|
|
||||||
If you want, I can generate:
|
|
||||||
|
|
||||||
* a sample **Manifest + Verdict + Delta** trio,
|
|
||||||
* the **canonical JSON schema**,
|
|
||||||
* and a **.NET 10** reference evaluator (deterministic LINQ pipeline + fixed‑precision math) you can drop into `scanner.webservice`.
|
|
||||||
|
|||||||
@@ -1,10 +1,46 @@
|
|||||||
Here’s a small but high‑impact 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 high‑impact 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)
|
### 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 didn’t—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 **re‑emits JSON in JCS**.
|
2. Resolver **normalizes strings (NFC)** and **re‑emits JSON in JCS**.
|
||||||
3. **REG hash** is computed from **JCS‑canonical UTF‑8 bytes** only.
|
3. **REG hash** is computed from **JCS‑canonical UTF‑8 bytes** only.
|
||||||
4. Any signature/attestation (DSSE/OCI) MUST cover those same bytes.
|
4. Any signature/attestation (DSSE/OCI) MUST cover those same bytes.
|
||||||
5. Any module that can’t speak JCS must pass raw data to the resolver; 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 (drop‑in 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);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Drop‑in checklist (pin on your wall)
|
||||||
|
|
||||||
|
- [x] One canonicalization policy: **UTF‑8 + NFC + JCS**. *(Implemented: `CanonJson`, `NfcStringNormalizer`)*
|
||||||
|
- [x] Resolver owns canonicalization (single choke‑point). *(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 pre‑canonical and canonical SHA‑256 for audits. *(Planned: DET-GAP-19)*
|
||||||
|
- [x] Backward‑compat path: migrate legacy verdicts by re‑canonicalizing 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
|
```csharp
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -110,26 +187,4 @@ public static class Canon
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Usage (hash/sign):**
|
</details>
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Drop‑in checklist (pin on your wall)
|
|
||||||
|
|
||||||
* [ ] One canonicalization policy: **UTF‑8 + NFC + JCS**.
|
|
||||||
* [ ] Resolver owns canonicalization (single choke‑point).
|
|
||||||
* [ ] **REG hash/signatures always over canonical bytes.**
|
|
||||||
* [ ] CI gate: reject outputs that aren’t JCS; fuzz keys/order/whitespace in tests.
|
|
||||||
* [ ] Log both the pre‑canonical and canonical SHA‑256 for audits.
|
|
||||||
* [ ] Backward‑compat path: migrate legacy verdicts by re‑canonicalizing 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 pre‑commit hook + CI check so your agents and services can’t drift.
|
|
||||||
|
|||||||
@@ -1,4 +1,37 @@
|
|||||||
Here’s a practical, low‑friction way to modernize how you sign and verify build “verdicts” in CI/CD using Sigstore—no long‑lived keys, offline‑friendly, 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, low‑friction way to modernize how you sign and verify build "verdicts" in CI/CD using Sigstore—no long‑lived keys, offline‑friendly, and easy to audit.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
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)
|
|
||||||
|
|
||||||
* 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** (OCI‑attached) 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 mini‑map 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.
|
|
||||||
@@ -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)
|
||||||
@@ -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/` |
|
||||||
@@ -1,11 +1,49 @@
|
|||||||
Here’s a compact blueprint for a **binary‑level knowledge base** that maps ELF Build‑IDs / PE signatures to vulnerable functions, patch lineage, and reachability hints—so your scanner can act like a provenance‑aware “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 Call‑Stack 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 **binary‑level knowledge base** that maps ELF Build‑IDs / PE signatures to vulnerable functions, patch lineage, and reachability hints—so your scanner can act like a provenance‑aware "binary oracle," not just a CVE lookup.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Why this matters (in plain terms)
|
# 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.
|
* **Same version ≠ same risk.** Distros (and vendors) frequently **backport** fixes without bumping versions. Only the **binary** tells the truth.
|
||||||
* **Function‑level matching** turns noisy “package has CVE” into precise “this exact function range is vulnerable in your binary.”
|
* **Function‑level 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.
|
* **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)
|
* `patch_sig` (pattern from fixed hunk)
|
||||||
* `evidence_ref` (link to patch diff, commit, or NVD note)
|
* `evidence_ref` (link to patch diff, commit, or NVD note)
|
||||||
* `backport_flag` (bool)
|
* `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**
|
**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 Build‑ID / PE signature; fall back to file hash.
|
1. **Identify**: Look up by Build‑ID / PE signature; fall back to file hash.
|
||||||
2. **Locate**: Map symbols → address ranges; scan for `byte_sig`/`patch_sig`.
|
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 Stella Ops)
|
# Deterministic verdicts (fit to Stella Ops)
|
||||||
|
|
||||||
* **Inputs**: `(artifact fingerprint, vuln_segments@version, reachability@policy)`
|
* **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.
|
* **Replay**: keep rule bundle & feed hashes for audit.
|
||||||
* **Backport precedence**: `patch_sig` beats package version claims every time.
|
* **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 **Build‑ID/PE indexer** to Scanner.
|
* Add a **Build‑ID/PE indexer** to Scanner.
|
||||||
* Teach Feedser/Vexer to ingest `vuln_segments` (with `byte_sig`/`patch_sig`).
|
* 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 high‑impact CVEs (OpenSSL, zlib, xz, glibc, libxml2, curl, musl, busybox, OpenSSH, sudo).
|
* Seed DB with 10 high‑impact 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
|
symbol_name text, hint_type text, weight int
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
If you want, I can:
|
|
||||||
|
|
||||||
* drop in a tiny **.NET 10** matcher (ELF/PE parsers + byte‑window scanner),
|
|
||||||
* wire verdicts as **OCI attestations** in your current pipeline,
|
|
||||||
* and prep the first **10 CVE byte/patch signatures** to seed the DB.
|
|
||||||
|
|||||||
@@ -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 Diff‑Aware Release Gates.md` | SUPERSEDED | SPRINT_20251226_001_BE through 006_DOCS |
|
||||||
|
| `26-Dec-2026 - Diff‑Aware Releases and Auditable Exceptions.md` | SUPERSEDED | SPRINT_20251226_003_BE_exception_approval.md |
|
||||||
|
| `26-Dec-2026 - Smart‑Diff 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
|
||||||
@@ -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 |
|
||||||
@@ -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`
|
||||||
@@ -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
71
src/Signer/AGENTS.md
Normal 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
|
||||||
Reference in New Issue
Block a user