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

95 lines
7.8 KiB
PHP

<?php
// QA-only bootstrap shared by Apache and rehearsal commands. No production bootstrap.
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
use Illuminate\Contracts\Console\Kernel;
use App\Models\User;
use App\Services\OrganizationCountryInstallation;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication;
use Laravel\Fortify\Fortify;
use PragmaRX\Google2FA\Google2FA;
ini_set('zend.exception_ignore_args', '1');
$root = dirname(__DIR__);
$consumerMode = ($_SERVER['HTTP_HOST'] ?? '') === 'portal-investidor.test:18445' || getenv('STABILITY_QA_MODE') === 'consumers';
$settings = json_decode(file_get_contents($root.($consumerMode?'/stability-consumers-qa.json':'/stability-qa.json')), true, 512, JSON_THROW_ON_ERROR);
$envPath = $root.($consumerMode?'/.env.stability-consumers':'/.env');
if (PHP_SAPI !== 'cli' && (!in_array($_SERVER['HTTP_HOST'] ?? '', ['portal-investidor.test:18443','portal-investidor.test:18444','portal-investidor.test:18445'],true))) {
http_response_code(421); exit;
}
require $root.'/qa-autoload.php';
// mod_php workers can retain process environment; reconcile every request from the QA file.
foreach (Dotenv\Dotenv::parse(file_get_contents($envPath)) as $name => $value) {
if ($value !== null) { putenv($name.'='.$value); $_ENV[$name] = $_SERVER[$name] = $value; }
}
$app = require $root.'/bootstrap/app.php';
(new LoadEnvironmentVariables)->bootstrap($app);
(new LoadConfiguration)->bootstrap($app);
$c = config('database.connections.'.config('database.default'));
throw_unless($c['driver'] === 'pgsql' && empty($c['url']) && $c['host'] === '127.0.0.1' && (int)$c['port'] === 55441
&& $c['database'] === $settings['target']['database'] && preg_match('/^(?:country_candidate|stability_consumers)_\d{8}_\d{6}_test$/D', $c['database'])
&& !$app->configurationIsCached(), RuntimeException::class, 'Isolated configuration required before providers.');
$pdo = new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$c['database'], $c['username'], $c['password'], [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$pdo->exec('BEGIN READ ONLY');
throw_unless($pdo->query('SELECT current_database()')->fetchColumn() === $c['database'] && (int)$pdo->query('SELECT inet_server_port()')->fetchColumn() === 55441,
RuntimeException::class, 'Actual isolated server required before providers.');
$pdo->exec('ROLLBACK');
$app->make(Kernel::class)->bootstrap();
if ($consumerMode) config(['inertia.ssr.enabled'=>false,'suitecrm.enabled'=>false,'investmoz_ai.enabled'=>false]);
if (PHP_SAPI !== 'cli' || basename($_SERVER['SCRIPT_FILENAME'] ?? '') !== 'portal-stability-runtime.php') { return $app; }
$command = $argv[1] ?? 'status';
$result = ['active_writes'=>0, 'target'=>$settings['target']];
if ($command === 'prepare') {
$actor = User::firstOrCreate(['email'=>'stability-installer@example.invalid'], ['name'=>'Synthetic integrated stability QA installer', 'password'=>Hash::make(Str::random(45))]);
$password = Str::random(45);
$actor->forceFill(['password'=>Hash::make($password), 'email_verified_at'=>now()])->save();
app(EnableTwoFactorAuthentication::class)($actor, true);
$secret = Fortify::currentEncrypter()->decrypt($actor->fresh()->two_factor_secret);
app(ConfirmTwoFactorAuthentication::class)($actor->fresh(), (new Google2FA)->getCurrentOtp($secret));
file_put_contents($root.'/storage/app/private/stability-actors.json', json_encode(['id'=>$actor->id,'email'=>$actor->email,'password'=>$password,'totp_secret'=>$secret],JSON_THROW_ON_ERROR));
$fresh = json_decode(file_get_contents($settings['backup_proof']),true,512,JSON_THROW_ON_ERROR);
$prior = json_decode(file_get_contents($settings['previous_qa_proof']),true,512,JSON_THROW_ON_ERROR);
$changes = [];
foreach($fresh['tables'] as $name=>$state) { if(($prior['tables'][$name]??null)!==$state) $changes[]=$name; }
throw_unless(array_diff($changes,['"public"."cache"','"public"."sessions"','"public"."cache_locks"'])===[]
&& $fresh['sequences']===$prior['sequences'],RuntimeException::class,'Business snapshot differs; previous QA cannot be reused.');
foreach(['restore_verified','files_verified','sequences_verified','compatibility_verified','reversal_verified','qa_passed'] as $field) {
throw_unless($prior[$field]===true,RuntimeException::class,'Existing corresponding proof incomplete.');
}
throw_unless($prior['code_hash']===app(OrganizationCountryInstallation::class)->fingerprint(),RuntimeException::class,'COUNTRY backend changed.');
$local = [...$fresh,'target'=>$settings['target'],'qa_passed'=>true,'compatibility_verified'=>true,'reversal_verified'=>true,
'reused_qa_backend_evidence'=>$settings['previous_qa_proof'],'transient_tables_changed'=>$changes,
'scope'=>'QA-only rehearsal; same COUNTRY backend already demonstrated. New integrated bundle acceptance pending. Never active readiness.'];
$path=storage_path('app/private/investmoz-v2/organization-country-installation/readiness.json');
if(!is_dir(dirname($path)))mkdir(dirname($path),0700,true);
file_put_contents($path,json_encode($local,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
$result += ['result'=>'synthetic_actor_prepared_with_normal_MFA','original_snapshot_restored'=>true,'country_backend_hash'=>$local['code_hash'],'country_enabled'=>false];
} elseif ($command === 'seed-organization') {
$actor=User::where('email','stability-installer@example.invalid')->firstOrFail();
$id=DB::table('organizations')->where('source_system','stability-qa-only')->value('id');
if($id===null){$id=(string)Str::uuid();DB::table('organizations')->insert(['id'=>$id,'name'=>'Synthetic integrated stability QA organization','source_system'=>'stability-qa-only','organization_type'=>'private']);}
if(!DB::table('memberships')->where('organization_id',$id)->where('user_id',$actor->id)->exists())DB::table('memberships')->insert(['organization_id'=>$id,'user_id'=>$actor->id,'role'=>'officer']);
$result += ['result'=>'explicit_synthetic_organization_and_representation_QA_only'];
} elseif (in_array($command,['enable-country','disable-country'],true)) {
$env=file_get_contents($envPath); $value=$command==='enable-country'?'true':'false';
$env=preg_replace('/^PORTAL_ORGANIZATION_COUNTRY_ENABLED=.*$/m','PORTAL_ORGANIZATION_COUNTRY_ENABLED='.$value,$env,1,$count);
throw_unless($count===1,RuntimeException::class,'Unique isolated flag required.');file_put_contents($root.'/.env',$env);
$result += ['result'=>'QA_flag_updated','country_enabled'=>$value==='true'];
} elseif ($command === 'runtime') {
$result += ['result'=>'isolated_runtime_verified','php_version'=>PHP_VERSION,'sapi'=>PHP_SAPI,'ini'=>php_ini_loaded_file(),
'extensions'=>get_loaded_extensions(),'cipher'=>config('app.cipher'),'session_driver'=>config('session.driver'),
'session_cookie'=>config('session.cookie'),'session_secure'=>config('session.secure'),'session_domain'=>config('session.domain'),
'queue_connection'=>config('queue.default'),'cache_store'=>config('cache.default'),'app_url'=>config('app.url')];
} else {
throw_unless($command==='status',RuntimeException::class,'Unknown rehearsal command.');
$result += ['result'=>'isolated','country_enabled'=>config('portal.organization_country_enabled'),
'country_columns'=>DB::select("SELECT column_name FROM information_schema.columns WHERE table_schema='public' AND table_name='organizations' AND column_name IN ('incorporation_country_code','incorporation_country_provenance') ORDER BY column_name"),
'installation_audits'=>(int)DB::table('audit_events')->where('source_system','organization-country-installation')->count()];
}
echo json_encode($result,JSON_THROW_ON_ERROR).PHP_EOL;