Files
Investidor-V2/tools/portal-stability-post-use-backup.php
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

20 lines
3.5 KiB
PHP

<?php
// Snapshot and restore only the already demonstrated QA clone; no active connection.
use Symfony\Component\Process\Process;
$root=dirname(__DIR__);require $root.'/vendor/autoload.php';ini_set('zend.exception_ignore_args','1');
$dir=$root.'/storage/app/private/investmoz-v2/portal-audit';$plan=json_decode(file_get_contents($dir.'/portal-stability-latest.json'),true,512,JSON_THROW_ON_ERROR);
$settings=json_decode(file_get_contents($plan['source'].'/stability-qa.json'),true,512,JSON_THROW_ON_ERROR);$db=$settings['target']['database'];
throw_unless((int)$settings['target']['port']===55441&&preg_match('/^country_candidate_\d{8}_\d{6}_test$/D',$db),RuntimeException::class,'QA source required.');
$connect=static fn($name)=>new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$name,'postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$source=$connect($db);throw_unless((int)$source->query('SELECT inet_server_port()')->fetchColumn()===55441,RuntimeException::class,'Actual QA port required.');
$snapshot=static function(PDO $pdo):array{$pdo->exec('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');$tables=[];foreach($pdo->query("SELECT schemaname,tablename FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema') ORDER BY schemaname,tablename")->fetchAll(PDO::FETCH_ASSOC) as $t){$name='"'.$t['schemaname'].'"."'.$t['tablename'].'"';$rows=$pdo->query('SELECT row_to_json(t)::text FROM '.$name.' t ORDER BY row_to_json(t)::text')->fetchAll(PDO::FETCH_COLUMN);$tables[$name]=['count'=>count($rows),'sha256'=>hash('sha256',implode("\n",$rows))];}$seq=$pdo->query("SELECT * FROM pg_sequences WHERE schemaname NOT IN ('pg_catalog','information_schema') ORDER BY schemaname,sequencename")->fetchAll(PDO::FETCH_ASSOC);$pdo->exec('ROLLBACK');return ['tables'=>$tables,'sequences'=>$seq];};
$before=$snapshot($source);$folder=$dir.'/stability-post-use-'.gmdate('Ymd_His');mkdir($folder,0700,true);$dump=$folder.'/qa.dump';
$run=static function(array $args):void{$p=new Process($args,null,['PGPASSWORD'=>'']);$p->setTimeout(180);$p->run();throw_unless($p->isSuccessful(),RuntimeException::class,'QA backup/restore failed.');};
$run(['C:/Program Files/PostgreSQL/17/bin/pg_dump.exe','-h','127.0.0.1','-p','55441','-U','postgres','-d',$db,'--format=custom','--file='.$dump]);
throw_unless($snapshot($source)===$before,RuntimeException::class,'QA changed during backup.');
$restored='country_candidate_'.gmdate('Ymd_His').'_test';$admin=$connect('postgres');$admin->exec('CREATE DATABASE "'.$restored.'"');
$run(['C:/Program Files/PostgreSQL/17/bin/pg_restore.exe','-h','127.0.0.1','-p','55441','-U','postgres','-d',$restored,'--exit-on-error','--no-owner','--no-privileges',$dump]);
throw_unless($snapshot($connect($restored))===$before,RuntimeException::class,'Post-use QA restoration differs.');
$receipt=['result'=>'passed','at'=>gmdate('c'),'source'=>['database'=>$db,'port'=>55441],'restored'=>['database'=>$restored,'port'=>55441],'dump_sha256'=>hash_file('sha256',$dump),'tables'=>count($before['tables']),'sequences'=>count($before['sequences']),'exact_rows_and_sequence_values'=>true,'preserves_new_country_and_encrypted_history'=>true,'scope'=>'QA post-use database; original file restoration covered by disaster-restore receipt','active_writes'=>0];
file_put_contents($folder.'/proof.json',json_encode([...$receipt,'dump_path'=>$dump,'snapshot'=>$before],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));file_put_contents($dir.'/portal-stability-post-use-backup.json',json_encode($receipt,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo json_encode($receipt).PHP_EOL;