Files
compras/scripts/sgf-demo-8039.php
T
2026-11-02 20:27:11 +02:00

85 lines
8.4 KiB
PHP

<?php
// Explicitly authorised persistent synthetic demonstration only. No GRANT/REVOKE.
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Symfony\Component\Process\Process;
use Tempo\Purchasing\Delivery\CodeDeployment;
use Tempo\Purchasing\Delivery\Installation;
$root=dirname(__DIR__);
$host='C:/laragon/data/sgf-tempo/run/modular-regression-2576427d1939/development-app';
$action=$argv[1]??'';
$recovery='C:/laragon/data/sgf-tempo/run/modular-regression-2576427d1939/private/requisitions-recovery';
$proof=json_decode(file_get_contents($root.'/docs/proofs/sgf-corrected-delivery.json'),true,64,JSON_THROW_ON_ERROR);
$bundle=$proof['artifact']['directory'];
require $host.'/vendor/autoload.php';
$app=require $host.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$db=DB::connection();
$identity=$db->selectOne("select current_database() as db,current_user as role,current_setting('cluster_name') as cluster,inet_server_port() as port");
if ($app->basePath()!==str_replace('/',DIRECTORY_SEPARATOR,$host) && str_replace('\\','/',$app->basePath())!==$host) throw new RuntimeException('Wrong application folder');
if ($identity->db!=='sgf_modules_dev_2576427d1939'||$identity->role!=='sgf_modules_qa_2576427d1939'||$identity->cluster!=='sgf_modular_regression_2576427d1939'||(int)$identity->port!==55439||config('app.url')!=='http://127.0.0.1:8039') throw new RuntimeException('Wrong isolated identity');
if (!$db->table('units')->where(['id'=>1,'tenant_id'=>1,'company_id'=>1])->exists()) throw new RuntimeException('Wrong scope');
$private=json_decode(file_get_contents(dirname($host).'/private/development.json'),true,32,JSON_THROW_ON_ERROR);
if ([$private['tenant_id'],$private['company_id'],$private['unit_id']]!==[1,1,1]) throw new RuntimeException('Wrong synthetic provenance');
foreach([1=>'Preparador',2=>'Revisor',3=>'Consulta'] as $id=>$suffix) if(!str_ends_with($db->table('users')->where('id',$id)->value('name'),$suffix)) throw new RuntimeException('Wrong synthetic user');
if(!class_exists(Installation::class))require_once $bundle.'/integrations/sgf/operational/bootstrap.php';
require_once $bundle.'/integrations/sgf/operational/CodeDeployment.php';
$deploy=new CodeDeployment($host);
$mh=$proof['artifact']['archive']['manifest_sha256'];
if ($action==='prepare') {
if(is_dir($recovery)) throw new RuntimeException('Recovery already exists; inspect before retry');
$plan=$deploy->plan($bundle,$mh);
mkdir($recovery,0700,true);
$manifest=json_decode(file_get_contents($bundle.'/manifest.json'),true);
foreach([...array_keys($manifest['host_overlays']),'.env','config/modules.php','packages/purchasing/current.json'] as $file){
if(!is_dir(dirname($recovery.'/files/'.$file)))mkdir(dirname($recovery.'/files/'.$file),0700,true);
copy($host.'/'.$file,$recovery.'/files/'.$file);
}
$cfg=$db->getConfig();
$dump=new Process(['C:/Program Files/PostgreSQL/17/bin/pg_dump.exe','--format=custom','--file='.$recovery.'/before.dump','--dbname='.$identity->db],null,['PGHOST'=>'127.0.0.1','PGPORT'=>'55439','PGUSER'=>$identity->role,'PGPASSWORD'=>$cfg['password']],null,90);
$dump->mustRun();
(new Process(['C:/Program Files/PostgreSQL/17/bin/pg_restore.exe','--list',$recovery.'/before.dump']))->mustRun();
$baseline=['identity'=>$identity,'host'=>$host,'code_plan'=>$plan,'backup_sha256'=>hash_file('sha256',$recovery.'/before.dump'),'grants'=>$db->table('permission_grants')->orderBy('id')->get()->all(),'users_sha256'=>hash('sha256',json_encode($db->table('users')->orderBy('id')->get())),'pointer_sha256'=>hash_file('sha256',$host.'/packages/purchasing/current.json')];
file_put_contents($recovery.'/baseline.json',json_encode($baseline,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
echo json_encode(['prepared'=>true,'identity'=>$identity,'host'=>$host,'recovery'=>$recovery,'backup_sha256'=>$baseline['backup_sha256'],'code_plan'=>$plan],JSON_PRETTY_PRINT);
} elseif($action==='install') {
$baseline=json_decode(file_get_contents($recovery.'/baseline.json'),true,64,JSON_THROW_ON_ERROR);
if(!hash_equals($baseline['backup_sha256'],hash_file('sha256',$recovery.'/before.dump')))throw new RuntimeException('Backup changed');
if(json_decode(json_encode($db->table('permission_grants')->orderBy('id')->get()),true)!==$baseline['grants'])throw new RuntimeException('Grants changed since backup');
if(is_file($host.'/storage/framework/down'))throw new RuntimeException('Unexpected prior maintenance');
file_put_contents($host.'/storage/framework/down',json_encode(['time'=>time(),'retry'=>60]));
$migration=Installation::migrate($db,Installation::target($db),$baseline['backup_sha256'],'Owner-authorised synthetic 8039 setup');
$applied=$deploy->apply($bundle,$mh,$baseline['code_plan']['target_sha256'],'Owner-authorised synthetic 8039 setup',true);
file_put_contents($recovery.'/applied.json',json_encode($applied,JSON_PRETTY_PRINT));
$config=['enabled'=>true,'target'=>Installation::target($db),'scopes'=>['1:1:1']];
file_put_contents($host.'/config/purchasing-operational.php','<?php return '.var_export($config,true).';');
file_put_contents($host.'/config/purchasing-internal.php','<?php return ["candidate_enabled"=>true];');
file_put_contents($host.'/config/purchasing-access.php','<?php return ["initialisation_scopes"=>["1:1:1"]];');
// The development server reloads PHP for every request; keep normal uncached config.
foreach(['config.php','routes-v7.php','events.php'] as $file)if(is_file($host.'/bootstrap/cache/'.$file))throw new RuntimeException('Unexpected native cache; retain maintenance and reconcile');
unlink($host.'/storage/framework/down');
echo json_encode(['installed_synthetic_only'=>true,'migration'=>$migration,'deployment'=>$applied,'recovery'=>$recovery],JSON_PRETTY_PRINT);
} elseif($action==='verify') {
$baseline=json_decode(file_get_contents($recovery.'/baseline.json'),true,64,JSON_THROW_ON_ERROR);
$http=json_decode(file_get_contents($root.'/docs/proofs/sgf-demo-8039-http.json'),true,64,JSON_THROW_ON_ERROR);
$current=$db->table('permission_grants')->orderBy('id')->get()->all();
$oldById=[];foreach($current as $grant)$oldById[$grant->id]=json_decode(json_encode($grant),true);
foreach($baseline['grants'] as $grant)if(($oldById[$grant['id']]??null)!==$grant)throw new RuntimeException('Existing grant changed');
$oldIds=array_column($baseline['grants'],'id');
$added=array_values(array_filter($current,fn($g)=>!in_array($g->id,$oldIds,true)));
if(count($added)!==14)throw new RuntimeException('Expected exactly fourteen new grants');
foreach($added as $grant)if([$grant->tenant_id,$grant->company_id,$grant->unit_id]!==[1,1,1]||!in_array($grant->permission,$http['rights'][$grant->user_id]??[],true))throw new RuntimeException('Unapproved new grant');
if(hash('sha256',json_encode($db->table('users')->orderBy('id')->get()))!==$baseline['users_sha256'])throw new RuntimeException('Existing accounts changed');
if(hash_file('sha256',$host.'/packages/purchasing/current.json')!==$baseline['pointer_sha256'])throw new RuntimeException('Pointer changed');
$requests=$db->table('ir_requests')->where(['tenant_id'=>1,'company_id'=>1,'unit_id'=>1])->get();
if(count($requests)!==1||$requests[0]->status!=='approved'||$requests[0]->requester_id!==1)throw new RuntimeException('Unexpected request state');
if($db->table('cb_budget_entries')->where('kind','reserve')->count()!==1)throw new RuntimeException('Expected exactly one reservation');
$budget=$db->table('cb_budgets')->first();
$decision=$db->table('ir_steps')->first();
$report=['passed'=>true,'identity'=>$identity,'scope'=>'1:1:1','added_grants'=>$added,'existing_grants_preserved'=>true,'existing_accounts_preserved'=>true,'single_approved_request'=>true,'single_reservation'=>true,'reservation'=>$db->table('cb_budget_entries')->where('kind','reserve')->first(),'budget'=>$budget,'decision'=>$decision,'pointer_preserved'=>true,'backup_sha256'=>$baseline['backup_sha256'],'recovery_directory'=>$recovery,'checked_at'=>gmdate('c'),'owner_runtime_limitation'=>true,'visual_review'=>false,'read_only_record_visibility_limitation'=>true];
file_put_contents($root.'/docs/proofs/sgf-demo-8039-delivery.json',json_encode($report,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
file_put_contents($host.'/config/purchasing-access.php','<?php return ["initialisation_scopes"=>[]];');
echo json_encode($report,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR);
} else throw new RuntimeException('Use prepare, install or verify');