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

24 lines
3.1 KiB
PHP

<?php
// Identify only changed field names. Never export credentials, MFA ciphertext or row values.
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
$root=dirname(__DIR__);require $root.'/vendor/autoload.php';ini_set('zend.exception_ignore_args','1');
set_exception_handler(static function(Throwable $e):void{fwrite(STDERR,'User delta diagnostic stopped: '.$e->getMessage().PHP_EOL);exit(1);});
$app=require $root.'/bootstrap/app.php';(new LoadEnvironmentVariables)->bootstrap($app);(new LoadConfiguration)->bootstrap($app);
$dir=$root.'/storage/app/private/investmoz-v2/portal-audit';$read=static fn($p)=>json_decode(file_get_contents($p),true,512,JSON_THROW_ON_ERROR);
$proof=$read($read($dir.'/stability-active-backup-latest.json')['path']);$c=config('database.connections.'.config('database.default'));
throw_unless($c['driver']==='pgsql'&&empty($c['url'])&&(int)$c['port']===5432&&$c['database']==='investemoz',RuntimeException::class,'Active identity differs.');
$target=$proof['restored_target'];throw_unless((int)$target['port']===55441&&preg_match('/^country_candidate_\d{8}_\d{6}_test$/',$target['database']),RuntimeException::class,'Original restored clone identity differs.');
$active=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$clone=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$target['database'],'postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
foreach([$active,$clone] as $pdo)$pdo->exec('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');
$sql='SELECT row_to_json(t)::text FROM users t ORDER BY row_to_json(t)::text';$a=$active->query($sql)->fetchAll(PDO::FETCH_COLUMN);$b=$clone->query($sql)->fetchAll(PDO::FETCH_COLUMN);
throw_unless(hash('sha256',implode("\n",$b))===$proof['tables']['"public"."users"']['sha256'],RuntimeException::class,'Original clone users changed; refuse comparison.');
$index=static function($rows){$out=[];foreach($rows as $row){$data=json_decode($row,true,512,JSON_THROW_ON_ERROR);$out[$data['id']]=$data;}ksort($out);return $out;};
$old=$index($b);$new=$index($a);throw_unless(array_keys($old)===array_keys($new),RuntimeException::class,'Identity set changed.');$changes=[];
foreach($old as $id=>$data){$fields=[];foreach($data as $field=>$value)if($value!==$new[$id][$field])$fields[]=$field;if($fields!==[])$changes[]=['user_id'=>$id,'changed_fields'=>$fields];}
$actors=$active->query("SELECT DISTINCT actor_user_id FROM audit_events WHERE source_system='organization-country-installation'")->fetchAll(PDO::FETCH_COLUMN);
foreach([$active,$clone] as $pdo)$pdo->exec('ROLLBACK');
$out=['at'=>gmdate('c'),'active_read_only'=>true,'clone_read_only'=>true,'original_clone_users_sha256_matches_snapshot'=>true,'identity_set_preserved'=>true,'changed'=>$changes,'installer_actor_user_ids'=>$actors,'row_values_or_secrets_exported'=>false];
file_put_contents($dir.'/stability-active-user-delta-readonly.json',json_encode($out,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo json_encode($out,JSON_THROW_ON_ERROR).PHP_EOL;