$ErrorActionPreference='Stop' $PSNativeCommandUseErrorActionPreference=$true $root=Split-Path -Parent $PSScriptRoot Set-Location -LiteralPath $root $suffix=[Guid]::NewGuid().ToString('N') $restoreDatabase="voice_restore_verify_$suffix" $dumpPath="/tmp/$restoreDatabase.dump" if($restoreDatabase-notmatch'^voice_restore_verify_[a-f0-9]{32}$'){throw 'Unsafe restore verification database name'} $started=[DateTime]::UtcNow function Pg([Parameter(ValueFromRemainingArguments=$true)][string[]]$arguments){ $output=docker compose exec -T postgres @arguments if($LASTEXITCODE-ne0){throw "PostgreSQL command failed: $($arguments -join ' ')"} return ($output|Out-String).Trim() } try{ Pg @('pg_dump','-U','voice','-d','voice_platform','-Fc','--no-owner','--no-acl','-f',$dumpPath)|Out-Null Pg @('createdb','-U','voice',$restoreDatabase)|Out-Null Pg @('pg_restore','-U','voice','-d',$restoreDatabase,'--no-owner','--no-acl',$dumpPath)|Out-Null $source=Pg @('psql','-U','voice','-d','voice_platform','-t','-A','-c',"SELECT version||'|'||dirty||'|'||(SELECT count(*) FROM tenant)||'|'||(SELECT count(*) FROM user_account) FROM schema_migrations") $restored=Pg @('psql','-U','voice','-d',$restoreDatabase,'-t','-A','-c',"SELECT version||'|'||dirty||'|'||(SELECT count(*) FROM tenant)||'|'||(SELECT count(*) FROM user_account) FROM schema_migrations") if($restored-ne$source){throw "Restored evidence mismatch. source=$source restored=$restored"} $tableEvidence=Pg @('psql','-U','voice','-d',$restoreDatabase,'-t','-A','-c',"SELECT count(*) FROM information_schema.tables WHERE table_schema='public'; SELECT count(*) FROM information_schema.table_constraints WHERE constraint_type='FOREIGN KEY';") $parts=@($tableEvidence-split"`n"|ForEach-Object{$_.Trim()}|Where-Object{$_}) if($parts.Count-ne2-or[int]$parts[0]-lt40-or[int]$parts[1]-lt30){throw "Restored schema inventory is incomplete: $tableEvidence"} $elapsed=[Math]::Round(([DateTime]::UtcNow-$started).TotalSeconds,2) Write-Host "PostgreSQL isolated restore passed: source/restored=$source, public_tables=$($parts[0]), foreign_keys=$($parts[1]), local_elapsed_seconds=$elapsed, database=$restoreDatabase" }finally{ try{Pg @('dropdb','-U','voice','--if-exists',$restoreDatabase)|Out-Null}catch{Write-Warning $_} try{Pg @('rm','-f',$dumpPath)|Out-Null}catch{Write-Warning $_} }