feat(crypto): Complete Phase 2 - Configuration-driven crypto architecture with 100% compliance

## 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>
This commit is contained in:
master
2025-12-23 18:20:00 +02:00
parent b444284be5
commit dac8e10e36
241 changed files with 22567 additions and 307 deletions

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Audits the codebase for direct usage of System.Security.Cryptography in production code.
.DESCRIPTION
This script scans the codebase for direct usage of System.Security.Cryptography namespace,
which should only be used within crypto provider plugin implementations, not in production code.
All cryptographic operations in production code should use the ICryptoProvider abstraction.
.PARAMETER RootPath
The root path of the StellaOps repository. Defaults to parent directory of this script.
.PARAMETER FailOnViolations
If set, the script will exit with code 1 when violations are found. Default: true.
.PARAMETER Verbose
Enable verbose output showing all scanned files.
.EXAMPLE
.\audit-crypto-usage.ps1
.EXAMPLE
.\audit-crypto-usage.ps1 -RootPath "C:\dev\git.stella-ops.org" -FailOnViolations $true
#>
param(
[Parameter(Mandatory=$false)]
[string]$RootPath = (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)),
[Parameter(Mandatory=$false)]
[bool]$FailOnViolations = $true,
[Parameter(Mandatory=$false)]
[switch]$Verbose
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# ANSI color codes for output
$Red = "`e[31m"
$Green = "`e[32m"
$Yellow = "`e[33m"
$Blue = "`e[34m"
$Reset = "`e[0m"
Write-Host "${Blue}==================================================================${Reset}"
Write-Host "${Blue}StellaOps Cryptography Usage Audit${Reset}"
Write-Host "${Blue}==================================================================${Reset}"
Write-Host ""
# Patterns to search for
$directCryptoPattern = "using System\.Security\.Cryptography"
# Allowed paths where direct crypto usage is permitted
$allowedPathPatterns = @(
"\\__Libraries\\StellaOps\.Cryptography\.Plugin\.", # All crypto plugins
"\\__Tests\\", # Test code
"\\third_party\\", # Third-party code
"\\bench\\", # Benchmark code
"\\.git\\" # Git metadata
)
# Compile regex for performance
$allowedRegex = ($allowedPathPatterns | ForEach-Object { [regex]::Escape($_) }) -join "|"
Write-Host "Scanning for direct crypto usage in production code..."
Write-Host "Root path: ${Blue}$RootPath${Reset}"
Write-Host ""
# Find all C# files
$allCsFiles = Get-ChildItem -Path $RootPath -Recurse -Filter "*.cs" -ErrorAction SilentlyContinue
$scannedCount = 0
$violations = @()
foreach ($file in $allCsFiles) {
$scannedCount++
# Check if file is in an allowed path
$relativePath = $file.FullName.Substring($RootPath.Length)
$isAllowed = $relativePath -match $allowedRegex
if ($isAllowed) {
if ($Verbose) {
Write-Host "${Green}[SKIP]${Reset} $relativePath (allowed path)"
}
continue
}
# Search for direct crypto usage
$matches = Select-String -Path $file.FullName -Pattern $directCryptoPattern -ErrorAction SilentlyContinue
if ($matches) {
foreach ($match in $matches) {
$violations += [PSCustomObject]@{
File = $relativePath
Line = $match.LineNumber
Content = $match.Line.Trim()
}
}
}
if ($Verbose) {
Write-Host "${Green}[OK]${Reset} $relativePath"
}
}
Write-Host ""
Write-Host "${Blue}==================================================================${Reset}"
Write-Host "Scan Results"
Write-Host "${Blue}==================================================================${Reset}"
Write-Host "Total C# files scanned: ${Blue}$scannedCount${Reset}"
Write-Host "Violations found: $(if ($violations.Count -gt 0) { "${Red}$($violations.Count)${Reset}" } else { "${Green}0${Reset}" })"
Write-Host ""
if ($violations.Count -gt 0) {
Write-Host "${Red}FAILED: Direct crypto usage detected in production code!${Reset}"
Write-Host ""
Write-Host "The following files use ${Yellow}System.Security.Cryptography${Reset} directly:"
Write-Host "Production code must use ${Green}ICryptoProvider${Reset} abstraction instead."
Write-Host ""
$groupedViolations = $violations | Group-Object -Property File
foreach ($group in $groupedViolations) {
Write-Host "${Red}${Reset} $($group.Name)"
foreach ($violation in $group.Group) {
Write-Host " Line $($violation.Line): $($violation.Content)"
}
Write-Host ""
}
Write-Host "${Yellow}How to fix:${Reset}"
Write-Host "1. Use ${Green}ICryptoProviderRegistry.ResolveSigner()${Reset} or ${Green}.ResolveHasher()${Reset}"
Write-Host "2. Inject ${Green}ICryptoProviderRegistry${Reset} via dependency injection"
Write-Host "3. For offline/airgap scenarios, use ${Green}OfflineVerificationCryptoProvider${Reset}"
Write-Host ""
Write-Host "Example refactoring:"
Write-Host "${Red}// BEFORE (❌ Not allowed)${Reset}"
Write-Host "using System.Security.Cryptography;"
Write-Host "var hash = SHA256.HashData(data);"
Write-Host ""
Write-Host "${Green}// AFTER (✅ Correct)${Reset}"
Write-Host "using StellaOps.Cryptography;"
Write-Host "var hasher = _cryptoRegistry.ResolveHasher(\"SHA-256\");"
Write-Host "var hash = hasher.Hasher.ComputeHash(data);"
Write-Host ""
if ($FailOnViolations) {
Write-Host "${Red}Audit failed. Exiting with code 1.${Reset}"
exit 1
} else {
Write-Host "${Yellow}Audit failed but FailOnViolations is false. Continuing...${Reset}"
}
} else {
Write-Host "${Green}✓ SUCCESS: No direct crypto usage found in production code!${Reset}"
Write-Host ""
Write-Host "All cryptographic operations correctly use the ${Green}ICryptoProvider${Reset} abstraction."
exit 0
}

45
scripts/test-lane.ps1 Normal file
View File

@@ -0,0 +1,45 @@
# scripts/test-lane.ps1
# Runs tests filtered by lane (Unit, Contract, Integration, Security, Performance, Live)
#
# Usage:
# .\scripts\test-lane.ps1 Unit
# .\scripts\test-lane.ps1 Integration -ResultsDirectory .\test-results
# .\scripts\test-lane.ps1 Security -Logger "trx;LogFileName=security-tests.trx"
[CmdletBinding()]
param(
[Parameter(Mandatory=$true, Position=0)]
[ValidateSet('Unit', 'Contract', 'Integration', 'Security', 'Performance', 'Live')]
[string]$Lane,
[Parameter(ValueFromRemainingArguments=$true)]
[string[]]$DotNetTestArgs
)
$ErrorActionPreference = 'Stop'
Write-Host "Running tests for lane: $Lane" -ForegroundColor Cyan
# Build trait filter for xUnit
# Format: --filter "Lane=$Lane"
$filterArg = "--filter", "Lane=$Lane"
# Build full dotnet test command
$testArgs = @(
'test'
$filterArg
'--configuration', 'Release'
'--no-build'
) + $DotNetTestArgs
Write-Host "Executing: dotnet $($testArgs -join ' ')" -ForegroundColor Gray
# Execute dotnet test
& dotnet $testArgs
if ($LASTEXITCODE -ne 0) {
Write-Error "Tests failed with exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
Write-Host "Lane '$Lane' tests completed successfully" -ForegroundColor Green

35
scripts/test-lane.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# scripts/test-lane.sh
# Runs tests filtered by lane (Unit, Contract, Integration, Security, Performance, Live)
#
# Usage:
# ./scripts/test-lane.sh Unit
# ./scripts/test-lane.sh Integration --results-directory ./test-results
# ./scripts/test-lane.sh Security --logger "trx;LogFileName=security-tests.trx"
set -euo pipefail
LANE="${1:-Unit}"
shift || true
# Validate lane
case "$LANE" in
Unit|Contract|Integration|Security|Performance|Live)
;;
*)
echo "Error: Invalid lane '$LANE'. Must be one of: Unit, Contract, Integration, Security, Performance, Live"
exit 1
;;
esac
echo "Running tests for lane: $LANE"
# Build trait filter for xUnit
# Format: --filter "Lane=$LANE"
dotnet test \
--filter "Lane=$LANE" \
--configuration Release \
--no-build \
"$@"
echo "Lane '$LANE' tests completed"