Files
Investidor-V2/tools/verify-investment-relations-backup.php
nala 1106509116
tests / ci (push) Canceled after 0s
vrsao 2
2026-10-08 14:02:01 +02:00

55 lines
3.0 KiB
PHP

<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
require dirname(__DIR__).'/vendor/autoload.php';
$app = require dirname(__DIR__).'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$active = DB::connection();
if ($active->getDatabaseName() !== 'investemoz' || (string) $active->getConfig('port') !== '5432') {
throw new RuntimeException('Unexpected active target.');
}
config(['database.connections.anchor_restore' => [...config('database.connections.pgsql'), 'host' => '127.0.0.1', 'port' => '55441',
'database' => 'anchor_restore_20261007_test', 'username' => 'postgres', 'password' => '', 'url' => null]]);
$restore = DB::connection('anchor_restore');
$identity = $restore->selectOne('select current_database() as database, inet_server_port() as port');
if ($identity->database !== 'anchor_restore_20261007_test' || (int) $identity->port !== 55441) {
throw new RuntimeException('Restore verification requires isolated QA.');
}
$report = $active->transaction(function () use ($active, $restore) {
$active->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ ONLY');
$counts = [];
foreach ($active->select("select tablename from pg_tables where schemaname='public' order by tablename") as $table) {
$name = $table->tablename;
$a = $active->table($name)->count();
$b = $restore->table($name)->count();
if ($a !== $b) {
throw new RuntimeException('Restore count differs for '.$name);
}
$counts[$name] = $a;
}
$hashes = [];
foreach (['projects', 'economic_clusters', 'investment_dossiers', 'project_locations', 'cluster_projects', 'opportunity_projects', 'opportunity_clusters', 'value_chains', 'value_chain_links', 'opportunities', 'geo_locations', 'geo_geometries'] as $table) {
$hash = function ($db) use ($table) {
$rows = array_map(fn ($row) => $row->value, $db->select('select row_to_json(t)::text as value from public.'.$table.' as t'));
sort($rows, SORT_STRING);
return hash('sha256', implode("\n", $rows));
};
$a = $hash($active);
if ($a !== $hash($restore)) {
throw new RuntimeException('Restore data differs for '.$table);
}
$hashes[$table] = $a;
}
return ['table_counts' => $counts, 'relation_table_hashes' => $hashes];
});
$directory = storage_path('app/private/anchor-project-reconciliation');
$dump = $directory.'/backup-20261007/database.dump';
$proof = [...$report, 'restore_verified' => true, 'verified_at' => date(DATE_ATOM), 'target' => ['database' => 'investemoz', 'port' => 5432],
'restored_target' => ['database' => $identity->database, 'port' => $identity->port], 'dump_path' => $dump, 'sha256' => hash_file('sha256', $dump)];
file_put_contents($directory.'/backup-proof.json', json_encode($proof, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
echo 'Restore verified: '.count($report['table_counts']).' table counts and '.count($report['relation_table_hashes']).' content hashes.'.PHP_EOL;