#!/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 }