## Summary
This commit completes Phase 2 of the configuration-driven crypto architecture, achieving
100% crypto compliance by eliminating all hardcoded cryptographic implementations.
## Key Changes
### Phase 1: Plugin Loader Infrastructure
- **Plugin Discovery System**: Created StellaOps.Cryptography.PluginLoader with manifest-based loading
- **Configuration Model**: Added CryptoPluginConfiguration with regional profiles support
- **Dependency Injection**: Extended DI to support plugin-based crypto provider registration
- **Regional Configs**: Created appsettings.crypto.{international,russia,eu,china}.yaml
- **CI Workflow**: Added .gitea/workflows/crypto-compliance.yml for audit enforcement
### Phase 2: Code Refactoring
- **API Extension**: Added ICryptoProvider.CreateEphemeralVerifier for verification-only scenarios
- **Plugin Implementation**: Created OfflineVerificationCryptoProvider with ephemeral verifier support
- Supports ES256/384/512, RS256/384/512, PS256/384/512
- SubjectPublicKeyInfo (SPKI) public key format
- **100% Compliance**: Refactored DsseVerifier to remove all BouncyCastle cryptographic usage
- **Unit Tests**: Created OfflineVerificationProviderTests with 39 passing tests
- **Documentation**: Created comprehensive security guide at docs/security/offline-verification-crypto-provider.md
- **Audit Infrastructure**: Created scripts/audit-crypto-usage.ps1 for static analysis
### Testing Infrastructure (TestKit)
- **Determinism Gate**: Created DeterminismGate for reproducibility validation
- **Test Fixtures**: Added PostgresFixture and ValkeyFixture using Testcontainers
- **Traits System**: Implemented test lane attributes for parallel CI execution
- **JSON Assertions**: Added CanonicalJsonAssert for deterministic JSON comparisons
- **Test Lanes**: Created test-lanes.yml workflow for parallel test execution
### Documentation
- **Architecture**: Created CRYPTO_CONFIGURATION_DRIVEN_ARCHITECTURE.md master plan
- **Sprint Tracking**: Created SPRINT_1000_0007_0002_crypto_refactoring.md (COMPLETE)
- **API Documentation**: Updated docs2/cli/crypto-plugins.md and crypto.md
- **Testing Strategy**: Created testing strategy documents in docs/implplan/SPRINT_5100_0007_*
## Compliance & Testing
- ✅ Zero direct System.Security.Cryptography usage in production code
- ✅ All crypto operations go through ICryptoProvider abstraction
- ✅ 39/39 unit tests passing for OfflineVerificationCryptoProvider
- ✅ Build successful (AirGap, Crypto plugin, DI infrastructure)
- ✅ Audit script validates crypto boundaries
## Files Modified
**Core Crypto Infrastructure:**
- src/__Libraries/StellaOps.Cryptography/CryptoProvider.cs (API extension)
- src/__Libraries/StellaOps.Cryptography/CryptoSigningKey.cs (verification-only constructor)
- src/__Libraries/StellaOps.Cryptography/EcdsaSigner.cs (fixed ephemeral verifier)
**Plugin Implementation:**
- src/__Libraries/StellaOps.Cryptography.Plugin.OfflineVerification/ (new)
- src/__Libraries/StellaOps.Cryptography.PluginLoader/ (new)
**Production Code Refactoring:**
- src/AirGap/StellaOps.AirGap.Importer/Validation/DsseVerifier.cs (100% compliant)
**Tests:**
- src/__Libraries/__Tests/StellaOps.Cryptography.Plugin.OfflineVerification.Tests/ (new, 39 tests)
- src/__Libraries/__Tests/StellaOps.Cryptography.PluginLoader.Tests/ (new)
**Configuration:**
- etc/crypto-plugins-manifest.json (plugin registry)
- etc/appsettings.crypto.*.yaml (regional profiles)
**Documentation:**
- docs/security/offline-verification-crypto-provider.md (600+ lines)
- docs/implplan/CRYPTO_CONFIGURATION_DRIVEN_ARCHITECTURE.md (master plan)
- docs/implplan/SPRINT_1000_0007_0002_crypto_refactoring.md (Phase 2 complete)
## Next Steps
Phase 3: Docker & CI/CD Integration
- Create multi-stage Dockerfiles with all plugins
- Build regional Docker Compose files
- Implement runtime configuration selection
- Add deployment validation scripts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
14 KiB
Verdict Attestation Implementation Status
Sprint: SPRINT_3000_0100_0001 - Signed Delta-Verdicts Status: Phase 1 Complete (Policy Engine + Evidence Locker), Phase 2 Blocked Last Updated: 2025-12-23
Completed Work
1. Policy Engine - Verdict Predicate & Attestation Service ✅
Location: src/Policy/StellaOps.Policy.Engine/Attestation/
Files Created:
-
VerdictPredicate.cs - Core predicate models
VerdictPredicate- Main predicate structure matching JSON schemaVerdictInfo- Verdict details (status/severity/score)VerdictRuleExecution- Rule chain execution traceVerdictEvidence- Evidence references (advisories, VEX, SBOM)VerdictVexImpact- VEX impact assessmentVerdictReachability- Call graph reachability data- Uses canonical JSON serialization with lexicographic key ordering
-
VerdictPredicateBuilder.cs - Predicate assembly service
Build(PolicyExplainTrace)- Converts existing trace to attestation predicateSerialize(VerdictPredicate)- Canonical JSON with sorted keysComputeDeterminismHash(VerdictPredicate)- SHA256 over sorted evidence + verdict- Maps all existing Policy Engine trace data to new attestation format
-
IVerdictAttestationService.cs - Service interface
AttestVerdictAsync(trace)- Orchestrates attestation creationVerdictAttestationRequest- Request DTO with predicate, subject, metadataVerdictAttestationResult- Response DTO with verdict ID and URI
-
VerdictAttestationService.cs - Service implementation
- Feature-flagged via
VerdictAttestationOptions.Enabled - Calls
VerdictPredicateBuilderto create predicate - Calls
HttpAttestorClientto request signing - Returns verdict ID for downstream tracking
- Feature-flagged via
-
HttpAttestorClient.cs - HTTP client for Attestor service
POST /internal/api/v1/attestations/verdict- Sends predicate JSON + subject descriptor
- Receives signed attestation metadata
Design Decisions:
- Predicate strictly matches
stellaops-policy-verdict.v1.schema.json - Determinism hash uses sorted evidence digests + verdict triple
- Offline-first: no hard dependencies on external services
- Feature flag allows gradual rollout
2. Evidence Locker - Verdict Storage & API ✅
Location: src/EvidenceLocker/StellaOps.EvidenceLocker/
Files Created:
-
Migrations/001_CreateVerdictAttestations.sql
- Table:
evidence_locker.verdict_attestations - Columns: verdict_id (PK), tenant_id, run_id, finding_id, policy metadata, verdict triple, envelope (JSONB), digests, rekor_log_index, timestamps
- Indexes: run_id, finding_id, tenant+evaluated_at
- CHECK constraint on verdict_status enum
- Audit trigger:
audit_verdict_attestations_changes
- Table:
-
Storage/IVerdictRepository.cs - Repository interface
StoreVerdictAsync(record)- Upsert verdict attestationGetVerdictAsync(verdictId)- Retrieve full record with envelopeListVerdictsForRunAsync(runId, options)- Query verdicts by run with filteringListVerdictsAsync(tenantId, options)- Query verdicts by tenantCountVerdictsForRunAsync(runId, options)- Pagination count- Records:
VerdictAttestationRecord,VerdictAttestationSummary,VerdictListOptions
-
Storage/PostgresVerdictRepository.cs - PostgreSQL implementation
- Uses Npgsql + Dapper for data access
- JSONB storage for DSSE envelope with GIN index
- ON CONFLICT handling for idempotent upserts
- Filtering by status/severity with pagination
- Tenant isolation via WHERE clauses
-
Api/VerdictContracts.cs - API response DTOs
GetVerdictResponse- Full verdict with envelopeListVerdictsResponse- Paged list of summariesVerdictSummary- Lightweight verdict metadataVerifyVerdictResponse- Signature verification resultsSignatureVerification,RekorVerification- Crypto details- JSON serialization with snake_case naming
-
Api/VerdictEndpoints.cs - Minimal API endpoints
GET /api/v1/verdicts/{verdictId}- Retrieve verdictGET /api/v1/runs/{runId}/verdicts- List verdicts for runPOST /api/v1/verdicts/{verdictId}/verify- Verify signature (TODO: implementation)- Structured logging for all operations
- Error handling with problem details
-
StellaOps.EvidenceLocker.csproj - Project file
- Dependencies: Npgsql 9.0.3, Dapper 2.1.35, OpenTelemetry, Serilog
- Project references: Scheduler.Models, Policy.Engine, Configuration, DependencyInjection, Auth, Telemetry
Integration Points:
-
DI Registration - Updated
EvidenceLockerInfrastructureServiceCollectionExtensions.cs- Registered
IVerdictRepository→PostgresVerdictRepository - Connection string from
EvidenceLockerOptions.Database.ConnectionString
- Registered
-
WebService Wiring - Updated
StellaOps.EvidenceLocker.WebService/Program.cs- Added
using StellaOps.EvidenceLocker.Api - Called
app.MapVerdictEndpoints()beforeapp.Run()
- Added
-
Project References - Updated
.csprojfilesWebService.csproj→ referencesStellaOps.EvidenceLocker.csprojInfrastructure.csproj→ referencesStellaOps.EvidenceLocker.csproj- Fixed package versions: Npgsql 9.0.3, Dapper 2.1.35
Design Decisions:
- PostgreSQL JSONB for envelope storage (queryable + compact)
- Separate verdict fields for efficient indexing without JSON extraction
- Determinism hash stored for replay verification
- Optional Rekor log index for transparency
- Repository pattern for testability
- Minimal APIs for lightweight endpoints
Blocked Work
3. Attestor - VerdictAttestationHandler ⚠️ BLOCKED
Blocking Issue: Pre-existing build errors in Attestor dependencies:
StellaOps.Replay.Core: Missing YamlDotNet assembly referenceStellaOps.Attestor.ProofChain: Missing Envelope namespace, ILogger references
Planned Implementation (when unblocked):
Location: src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/
Planned Files:
-
Handlers/VerdictAttestationHandler.cs
public class VerdictAttestationHandler { private readonly IAttestationSigningService _signingService; private readonly IVerdictRepository _verdictRepository; private readonly ITransparencyWitnessClient _transparencyClient; public async Task<VerdictAttestationResponse> HandleAsync( VerdictAttestationRequest request, CancellationToken cancellationToken) { // 1. Validate predicate schema // 2. Create AttestationSignRequest with predicate payload // 3. Sign with IAttestationSigningService // 4. Extract DSSE envelope from result // 5. Store in Evidence Locker via IVerdictRepository // 6. Optional: Submit to Rekor via ITransparencyWitnessClient // 7. Return verdict ID + attestation URI } } -
Endpoints - Add to WebService Program.cs
POST /internal/api/v1/attestations/verdict- Create verdict attestation- Accepts predicate JSON + subject descriptor
- Returns verdict ID + DSSE envelope URI
-
DI Registration
- Register
VerdictAttestationHandleras scoped service - Wire up dependencies: signing, storage, transparency
- Register
Dependencies:
- ✅
IAttestationSigningService- Existing - ✅
ITransparencyWitnessClient- Existing - ✅
IVerdictRepository- Implemented (Evidence Locker) - ❌ Build environment - BLOCKED
Pending Work
4. Policy Engine Integration ⏸️
Task: Wire Policy Engine to call VerdictAttestationService after verdict evaluation
Location: src/Policy/StellaOps.Policy.Engine/Evaluation/PolicyEvaluator.cs (or similar)
Changes Needed:
- Inject
IVerdictAttestationServiceinto evaluator - After successful policy evaluation, call
AttestVerdictAsync(trace) - Store returned verdict ID in evaluation metadata
- Ensure async context properly propagated
Depends On: Task 3 (Attestor Handler) completion
5. Unit Tests ⏸️
Location: src/Policy/StellaOps.Policy.Engine/__Tests/
Files to Create:
-
VerdictPredicateBuilderTests.cs
- Test: Schema validation (predicate matches JSON schema)
- Test: Determinism hash stability (same input → same hash)
- Test: Rule chain mapping accuracy
- Test: Evidence digest computation
- Test: VEX impact extraction
- Test: Reachability data mapping
- Test: Canonical JSON serialization (key ordering)
-
VerdictAttestationServiceTests.cs
- Test: Feature flag disabled (returns null)
- Test: Successful attestation flow
- Test: HTTP client failure handling
- Test: Predicate serialization errors
-
Integration Test
- Test: End-to-end policy run → verdict attestation → storage → retrieval
- Test: Deterministic replay (same inputs → same determinism hash)
- Test: Signature verification
Depends On: Task 3, 4 completion
6. CLI Commands ⏸️
Location: src/Cli/StellaOps.Cli/Commands/
Commands to Add:
stella verdict get <verdict-id>- Retrieve verdict attestationstella verdict verify <verdict-id>- Verify signaturestella verdict list --run <run-id>- List verdicts for runstella verdict download <verdict-id> --output <path>- Download DSSE bundle
Depends On: Task 3, 4, 5 completion
Architecture Summary
┌─────────────────┐
│ Policy Engine │
│ - Evaluates │
│ - Generates │
│ Trace │
└────────┬────────┘
│ PolicyExplainTrace
▼
┌────────────────────────────┐
│ VerdictPredicateBuilder │
│ - Converts Trace │
│ - Computes Determinism │
│ - Serializes Canonical │
└────────┬───────────────────┘
│ VerdictPredicate
▼
┌─────────────────────────────────┐
│ VerdictAttestationService │
│ - Orchestrates Signing │
│ - Calls Attestor │
└────────┬────────────────────────┘
│ HTTP POST /internal/api/v1/attestations/verdict
▼
┌────────────────────────────────────┐
│ Attestor │ ⚠️ BLOCKED
│ - VerdictAttestationHandler │
│ - IAttestationSigningService │
│ - Creates DSSE Envelope │
└────────┬───────────────────────────┘
│ VerdictAttestationRecord
▼
┌──────────────────────────────────┐
│ Evidence Locker │ ✅ COMPLETE
│ - PostgresVerdictRepository │
│ - Stores Attestations │
│ - Provides Query API │
└──────────────────────────────────┘
Next Steps
Immediate Actions Required:
-
Fix Attestor Build Errors (Infrastructure team)
- Add missing YamlDotNet package reference to Replay.Core
- Fix ProofChain namespace/using issues
- Verify all Attestor dependencies compile
-
Implement VerdictAttestationHandler (This sprint)
- Create handler class in Attestor.WebService
- Wire up signing service, storage, transparency
- Add endpoint to Program.cs
- Test end-to-end flow
-
Integrate Policy Engine (This sprint)
- Inject attestation service into evaluator
- Call after successful verdicts
- Store verdict IDs
-
Write Unit Tests (This sprint)
- VerdictPredicateBuilder schema/determinism tests
- Service integration tests
- End-to-end replay tests
-
CLI Commands (Next sprint)
- verdict get/verify/list/download
- Interactive verification UI
Success Criteria:
- Policy runs generate cryptographically-signed verdict attestations
- Verdicts stored in Evidence Locker with DSSE envelopes
- Determinism hashes enable bit-for-bit replay verification
- Optional Rekor anchoring for public auditability
- CLI commands for verdict inspection and verification
- Unit test coverage >80% for new code
- Integration tests validate end-to-end flow
Technical Debt
-
EvidenceLockerDataSource Integration
- Current: PostgresVerdictRepository uses connection string directly
- Future: Migrate to use EvidenceLockerDataSource.OpenConnectionAsync()
- Benefit: Unified session management, tenant scoping
-
Signature Verification Placeholder
- Current:
VerdictEndpoints.VerifyVerdictAsyncreturns placeholder response - Future: Implement actual DSSE signature verification
- Dependency: Integrate with Attestor verification service
- Current:
-
Pre-existing Attestor Errors
- EvidencePortableBundleService.cs static field access errors
- Blocking unrelated to verdict attestation work
- Needs separate investigation
Resources
- JSON Schema:
docs/schemas/stellaops-policy-verdict.v1.schema.json - Documentation:
docs/policy/verdict-attestations.md - Sprint Plan:
docs/implplan/SPRINT_3000_0100_0001_signed_verdicts.md - Evidence Pack Sprint:
docs/implplan/SPRINT_3000_0100_0002_evidence_packs.md
Status Legend:
- ✅ Complete
- ⚠️ Blocked
- ⏸️ Pending (blocked by dependencies)
- 🔄 In Progress