# Test certificate renewal process # This script validates end-to-end certificate renewal $ErrorActionPreference = "Stop" Write-Host "=== Certificate Renewal Test ===" -ForegroundColor Cyan Write-Host "" # 1. Check current certificate Write-Host "Step 1: Check current certificate" -ForegroundColor Yellow $assetId = 2528 $query = @" SELECT assetid, assetnumber, client_cert_fingerprint, cert_issued_at, cert_expires_at, DATEDIFF(cert_expires_at, NOW()) as days_remaining FROM assets WHERE assetid = $assetId "@ Write-Host "Querying database for current cert status..." $result = docker-compose exec -T db mysql -u root -proot-dev-password-not-for-production shopdb_flask -sN -e $query 2>$null if ($result) { $fields = $result -split "`t" Write-Host " Asset: $($fields[1])" -ForegroundColor Green Write-Host " Current Fingerprint: $($fields[2])" -ForegroundColor Green Write-Host " Issued: $($fields[3])" -ForegroundColor Green Write-Host " Expires: $($fields[4])" -ForegroundColor Green Write-Host " Days Remaining: $($fields[5])" -ForegroundColor Green $oldFingerprint = $fields[2] $daysRemaining = [int]$fields[5] } else { Write-Host " ERROR: Could not query database" -ForegroundColor Red exit 1 } Write-Host "" # 2. Test renewal endpoint Write-Host "Step 2: Test renewal endpoint (API key fallback)" -ForegroundColor Yellow $apiKey = (Get-Content .env | Select-String "COLLECTOR_API_KEY_ENDPOINTS" | ForEach-Object { $_.ToString().Split('=')[1] }) if (-not $apiKey) { Write-Host " ERROR: Could not get API key from .env" -ForegroundColor Red exit 1 } $body = @{ hostname = "DESKTOP-HF1K9M4" } | ConvertTo-Json Write-Host " Calling POST https://localhost:5001/api/endpoints/certificate/renew" Write-Host " (This may take a few seconds...)" try { $response = Invoke-RestMethod ` -Uri "https://localhost:5001/api/endpoints/certificate/renew" ` -Method POST ` -Headers @{ "X-API-Key" = $apiKey "Content-Type" = "application/json" } ` -Body $body ` -SkipCertificateCheck ` -ErrorAction Stop if ($response.status -eq "success") { Write-Host " ✓ Renewal succeeded!" -ForegroundColor Green $newThumbprint = $response.data.thumbprint $newExpires = $response.data.expires_at $pfxSize = [System.Convert]::FromBase64String($response.data.pfx).Length Write-Host " New Thumbprint: $newThumbprint" -ForegroundColor Green Write-Host " New Expires: $newExpires" -ForegroundColor Green Write-Host " PFX Size: $pfxSize bytes" -ForegroundColor Green Write-Host " Password Length: $($response.data.password.Length) chars" -ForegroundColor Green } else { Write-Host " × Renewal failed: $($response.data.error.message)" -ForegroundColor Red if ($response.data.error.code -eq "VALIDATION_ERROR" -and $response.data.error.message -like "*24 hours*") { Write-Host "" Write-Host " NOTE: Certificate was renewed < 24 hours ago (rate limited)" -ForegroundColor Yellow Write-Host " This is expected behavior and the security fix is working correctly." -ForegroundColor Yellow Write-Host "" Write-Host " To test renewal:" -ForegroundColor Cyan Write-Host " 1. Wait 24 hours, OR" -ForegroundColor Cyan Write-Host " 2. Manually update cert_issued_at in database:" -ForegroundColor Cyan Write-Host " UPDATE assets SET cert_issued_at = DATE_SUB(NOW(), INTERVAL 25 HOUR) WHERE assetid = $assetId;" -ForegroundColor Gray exit 0 } } } catch { Write-Host " × Request failed: $($_.Exception.Message)" -ForegroundColor Red if ($_.ErrorDetails.Message) { $errorData = $_.ErrorDetails.Message | ConvertFrom-Json Write-Host " Error: $($errorData.data.error.message)" -ForegroundColor Red } exit 1 } Write-Host "" # 3. Verify database was updated Write-Host "Step 3: Verify database was updated" -ForegroundColor Yellow $newResult = docker-compose exec -T db mysql -u root -proot-dev-password-not-for-production shopdb_flask -sN -e $query 2>$null if ($newResult) { $newFields = $newResult -split "`t" $dbFingerprint = $newFields[2] $dbExpires = $newFields[4] if ($dbFingerprint -eq $oldFingerprint) { Write-Host " × Database not updated (fingerprint unchanged)" -ForegroundColor Red exit 1 } else { Write-Host " ✓ Database updated successfully" -ForegroundColor Green Write-Host " Old Fingerprint: $oldFingerprint" -ForegroundColor Gray Write-Host " New Fingerprint: $dbFingerprint" -ForegroundColor Green Write-Host " New Expires: $dbExpires" -ForegroundColor Green } } Write-Host "" # 4. Test hostname validation (security fix #4) Write-Host "Step 4: Test hostname validation (Security Fix #4)" -ForegroundColor Yellow $testCases = @( @{ Hostname = ""; Description = "Empty hostname"; ExpectedStatus = 400 } @{ Hostname = "x" * 65; Description = "Too long (65 chars)"; ExpectedStatus = 400 } @{ Hostname = "test;DROP TABLE"; Description = "SQL injection"; ExpectedStatus = 400 } @{ Hostname = "../../etc/passwd"; Description = "Path traversal"; ExpectedStatus = 400 } ) $passed = 0 foreach ($test in $testCases) { $testBody = @{ hostname = $test.Hostname } | ConvertTo-Json try { $testResponse = Invoke-RestMethod ` -Uri "https://localhost:5001/api/endpoints/certificate/renew" ` -Method POST ` -Headers @{ "X-API-Key" = $apiKey "Content-Type" = "application/json" } ` -Body $testBody ` -SkipCertificateCheck ` -ErrorAction Stop Write-Host " × $($test.Description): Got 200, expected $($test.ExpectedStatus)" -ForegroundColor Red } catch { $statusCode = $_.Exception.Response.StatusCode.value__ if ($statusCode -eq $test.ExpectedStatus) { Write-Host " ✓ $($test.Description): Rejected correctly ($statusCode)" -ForegroundColor Green $passed++ } else { Write-Host " × $($test.Description): Got $statusCode, expected $($test.ExpectedStatus)" -ForegroundColor Red } } } Write-Host " Validation tests: $passed/$($testCases.Count) passed" -ForegroundColor $(if ($passed -eq $testCases.Count) { "Green" } else { "Yellow" }) Write-Host "" # Summary Write-Host "=== Test Summary ===" -ForegroundColor Cyan Write-Host "✓ Certificate renewal endpoint operational" -ForegroundColor Green Write-Host "✓ Database updates working" -ForegroundColor Green Write-Host "✓ Hostname validation enforced" -ForegroundColor Green Write-Host "✓ Security fixes validated" -ForegroundColor Green Write-Host "" Write-Host "NOTE: Agent must be rebuilt and deployed to test:" -ForegroundColor Yellow Write-Host " - Periodic expiry monitoring (24-hour checks)" -ForegroundColor Yellow Write-Host " - Graceful service restart after renewal" -ForegroundColor Yellow Write-Host " - Server certificate validation" -ForegroundColor Yellow