95 lines
7.8 KiB
PHP
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;
|