51 lines
3.8 KiB
PHP
51 lines
3.8 KiB
PHP
<?php
|
|
|
|
// Coordinator: provision disposable databases via maintenance DB, never migrate/read client data.
|
|
require __DIR__.'/../../vendor/autoload.php';
|
|
foreach (['APP_ENV'=>'budget-coordinator','DB_CONNECTION'=>'pgsql','CACHE_STORE'=>'array','SESSION_DRIVER'=>'array'] as $key=>$value) { putenv($key.'='.$value); $_ENV[$key]=$_SERVER[$key]=$value; }
|
|
$app=require __DIR__.'/../../bootstrap/app.php';
|
|
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
|
use Illuminate\Support\Facades\DB;
|
|
use Symfony\Component\Process\Process;
|
|
$source=DB::connection('pgsql')->getConfig();
|
|
if(($source['driver']??'')!=='pgsql'||($source['host']??'')!=='127.0.0.1')throw new LogicException('Local PostgreSQL maintenance connection required.');
|
|
$maintenance=[...$source,'database'=>'postgres','url'=>null];
|
|
config(['database.connections.budget_admin'=>$maintenance]);
|
|
$admin=DB::connection('budget_admin')->getPdo();
|
|
$sgf=realpath(base_path('../sgf-tempo'));
|
|
$script=$sgf.'/packages/budget-control/tests/run-host.php';
|
|
$report=['version'=>'COMMON-BUDGET-SYNTHETIC-v1','checked_at'=>gmdate('c'),'client_databases_touched'=>false,'hosts'=>[]];
|
|
$artifact=sys_get_temp_dir().'/common-budget-artifact-'.bin2hex(random_bytes(6));
|
|
if(!mkdir($artifact.'/src',0700,true))throw new RuntimeException('Cannot prepare isolated package artifact.');
|
|
$artifactFiles=['bootstrap.php','src/BudgetContext.php','src/BudgetFailure.php','src/BudgetControl.php'];
|
|
foreach($artifactFiles as $file)if(!copy($sgf.'/packages/budget-control/'.$file,$artifact.'/'.$file))throw new RuntimeException('Cannot build package artifact.');
|
|
try {
|
|
foreach(['compras','sgf'] as $mode){
|
|
$db=($mode==='compras'?'compras_receipts_test_':'budget_core_sgf_').bin2hex(random_bytes(6));
|
|
$created=false;
|
|
try{
|
|
$admin->exec('CREATE DATABASE "'.$db.'"');$created=true;
|
|
$environment=['APP_ENV'=>$mode==='compras'?'testing':'budget-testing','DB_CONNECTION'=>'pgsql','DB_DATABASE'=>$db,'DB_URL'=>'','DB_HOST'=>'127.0.0.1','DB_PORT'=>(string)$source['port'],'DB_USERNAME'=>$source['username'],'DB_PASSWORD'=>$source['password'],'CACHE_STORE'=>'array','SESSION_DRIVER'=>'array','QUEUE_CONNECTION'=>'sync','MAIL_MAILER'=>'array','BCRYPT_ROUNDS'=>'4','COMMON_BUDGET_PATH'=>$mode==='compras'?$artifact:$sgf.'/packages/budget-control'];
|
|
$php=$mode==='compras'?PHP_BINARY:'C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe';
|
|
$root=$mode==='compras'?base_path():$sgf;
|
|
$process=new Process([$php,$script,$root,$mode],$root,$environment);$process->setTimeout(120);$process->run();
|
|
if(!$process->isSuccessful())throw new RuntimeException('QA host failed: '.$process->getOutput().$process->getErrorOutput());
|
|
$report['hosts'][]=json_decode($process->getOutput(),true,64,JSON_THROW_ON_ERROR);
|
|
}finally{
|
|
if(isset($process)&&$process->isRunning())$process->stop();
|
|
if($created){
|
|
$stmt=$admin->prepare('SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname=? AND pid<>pg_backend_pid()');$stmt->execute([$db]);
|
|
$admin->exec('DROP DATABASE "'.$db.'"');
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
// Delete only the exact files created above, never a recursive or computed project path.
|
|
foreach($artifactFiles as $file)if(is_file($artifact.'/'.$file))unlink($artifact.'/'.$file);
|
|
rmdir($artifact.'/src');rmdir($artifact);
|
|
}
|
|
if($report['hosts'][0]['core_sha256']!==$report['hosts'][1]['core_sha256']||$report['hosts'][0]['steps']!==$report['hosts'][1]['steps'])throw new RuntimeException('Host equivalence failed.');
|
|
$report['equivalent']=true;$report['disposable_databases_dropped']=true;
|
|
file_put_contents($sgf.'/docs/proofs/common-budget-hosts.json',json_encode($report,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR).PHP_EOL);
|
|
echo "Two Laravel hosts passed the same core sequence and PostgreSQL concurrency checks. Disposable databases dropped.\n";
|