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

75 lines
3.9 KiB
PHP

<?php
use App\Services\VirtualDeskInstallation;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
$root = dirname(__DIR__);
$proof = json_decode(file_get_contents($root.'/storage/app/private/virtual-desk/backup-proof.json'), true, 512, JSON_THROW_ON_ERROR);
$target = $proof['restored_target'];
if (! preg_match('/^desk_restore_\d{8}_\d{6}_test$/', $target['database']) || (int) $target['port'] !== 55441) {
throw new RuntimeException('Isolated restore required.');
}
foreach (['APP_ENV' => 'testing', 'DB_CONNECTION' => 'pgsql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '55441',
'DB_DATABASE' => $target['database'], 'DB_USERNAME' => 'postgres', 'DB_PASSWORD' => '', 'DB_URL' => '',
'CACHE_STORE' => 'array', 'SESSION_DRIVER' => 'array', 'QUEUE_CONNECTION' => 'sync'] as $key => $value) {
putenv($key.'='.$value);
$_ENV[$key] = $_SERVER[$key] = $value;
}
require $root.'/vendor/autoload.php';
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$db = DB::connection();
$identity = $db->selectOne('select current_database() as database, inet_server_port() as port');
if ($identity->database !== $target['database'] || (int) $identity->port !== 55441) {
throw new RuntimeException('Actual QA identity rejected.');
}
$check = function (bool $extended) use ($db, $proof) {
foreach ($proof['table_hashes'] as $name => $hash) {
// Extension adds nullable columns to existing tasks; compare original columns explicitly.
$columns = '*';
if ($extended && $name === '"public"."tasks"') {
$columns = implode(',', array_map(fn ($r) => '"'.$r->column_name.'"', $db->select("select column_name from information_schema.columns where table_schema='public' and table_name='tasks' and column_name not in ('desk_case_id','desk_request_id','guidance_key','accepted_by','accepted_at','external_sync_status') order by ordinal_position")));
}
$rows = array_map(fn ($r) => $r->value, $db->select('select row_to_json(t)::text as value from (select '.$columns.' from '.$name.') t order by row_to_json(t)::text'));
if (hash('sha256', implode("\n", $rows)) !== $hash) {
throw new RuntimeException('Original contents changed: '.$name);
}
}
};
$check(false);
$migrations = array_map(fn ($name) => require $root.'/database/migrations/'.$name.'.php', VirtualDeskInstallation::MIGRATIONS);
$db->transaction(function () use ($migrations, $check) {
foreach ($migrations as $migration) {
$migration->up();
}
$check(true);
foreach (array_reverse($migrations) as $migration) {
$migration->down();
}
$check(false);
});
$archive = new ZipArchive;
$archive->open($proof['files_path']);
$restoreRoot = dirname($proof['files_path']).'/restored-files';
foreach ($proof['file_hashes'] as $name => $hash) {
if (str_contains($name, '..') || str_starts_with($name, '/')) {
throw new RuntimeException('Invalid archive entry.');
}
$path = $restoreRoot.'/'.$name;
if (! is_dir(dirname($path))) {
mkdir(dirname($path), 0700, true);
}
file_put_contents($path, $archive->getFromName($name));
if (hash_file('sha256', $path) !== $hash) {
throw new RuntimeException('Restored private bytes differ.');
}
}
$archive->close();
$result = ['passed' => true, 'verified_at' => gmdate('c'), 'database' => $target['database'], 'port' => 55441,
'migrations' => VirtualDeskInstallation::MIGRATIONS, 'original_tables_preserved' => count($proof['table_hashes']),
'empty_rollback_verified' => true, 'private_files_restored' => count($proof['file_hashes']),
'dump_sha256' => $proof['sha256'], 'code_hash' => app(VirtualDeskInstallation::class)->fingerprint()];
file_put_contents($root.'/storage/app/private/virtual-desk/activation-compatibility.json', json_encode($result, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
echo json_encode($result, JSON_THROW_ON_ERROR);