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

104 lines
8.3 KiB
PHP

<?php
// Inspect the active configuration without booting providers or sending messages.
// The optional test database creation is allowed ONLY on the separate 55441 cluster.
ini_set('zend.exception_ignore_args', '1');
set_exception_handler(static function (Throwable $e): void {
fwrite(STDERR, 'Onboarding inspection stopped: '.$e::class.' at '.basename($e->getFile()).':'.$e->getLine().PHP_EOL);
exit(1);
});
$root=dirname(__DIR__);$private=$root.'/storage/app/private/investmoz-v2/portal-audit';
require $root.'/vendor/autoload.php';
$app=require $root.'/bootstrap/app.php';
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);
(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$c=config('database.connections.'.config('database.default'));
throw_unless($c['driver']==='pgsql' && empty($c['url']) && $c['database']==='investemoz' && (int)$c['port']===5432
&& in_array($c['host'],['127.0.0.1','localhost'],true),RuntimeException::class,'Unexpected active target');
$pdo=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$pdo->exec('BEGIN READ ONLY');
$identity=$pdo->query("SELECT current_database() AS database,inet_server_port() AS port,current_setting('transaction_read_only') AS read_only")->fetch(PDO::FETCH_ASSOC);
throw_unless((int)$identity['port']===5432 && $identity['read_only']==='on',RuntimeException::class);
$counts=[];foreach(['users','portal_role_assignments','organizations','memberships','jobs','failed_jobs'] as $table){$counts[$table]=(int)$pdo->query('SELECT count(*) FROM "'.$table.'"')->fetchColumn();}
$designations=[];
if (($argv[1]??'inspect')==='designations') {
$lookup=$pdo->prepare('SELECT id, name, email, email_verified_at IS NOT NULL AS contact_verified, two_factor_confirmed_at IS NOT NULL AND two_factor_secret IS NOT NULL AS MFA_configured FROM users WHERE lower(email)=lower(:email)');
foreach ([
['Aurora Chachuaio','Aurora.chachuaio@tempo.co.mz','promoter','Tempo'],
['Palmira Uamusse','Palmira.matsinhe@tempo.co.mz','validator','all_organizations'],
['Mario Melembe','mario.melembe@tempo.co.mz','publisher','all_organizations'],
] as [$name,$email,$role,$scope]) {
$lookup->execute(['email'=>$email]);
$designations[]=['designated_name'=>$name,'email'=>$email,'role'=>$role,'scope'=>$scope,'existing_accounts'=>$lookup->fetchAll(PDO::FETCH_ASSOC),
'categories'=>['investment_project','real_estate','land_rights','business_sale','business_partnership','franchise']];
}
}
$pdo->exec('ROLLBACK');
$mailer=config('mail.default');$mail=config('mail.mailers.'.$mailer,[]);
$mailUrl=$mail['url']??null;$host=$mailUrl?parse_url($mailUrl,PHP_URL_HOST):($mail['host']??null);
$port=(int)($mailUrl?(parse_url($mailUrl,PHP_URL_PORT)?:($mail['port']??2525)):($mail['port']??2525));
$local=in_array($host,['127.0.0.1','localhost','::1'],true);$listening=null;$smtpGreeting=null;
// Local SMTP readiness, not delivery. No AUTH, recipient, message or secret is sent.
if(($mail['transport']??null)==='smtp' && $local){
$errno=0;$error='';$socket=@stream_socket_client('tcp://'.$host.':'.$port,$errno,$error,3);
$listening=is_resource($socket);
if($listening){stream_set_timeout($socket,3);$line=fgets($socket,512);$smtpGreeting=is_string($line)&&str_starts_with($line,'220');fclose($socket);}
}
$proof=['at'=>gmdate('c'),'target'=>$identity,'providers_booted'=>false,'active_writes'=>0,'emails_sent'=>0,
'registration_enabled'=>in_array('registration',config('fortify.features',[]),true),
'email_verification_enabled'=>in_array('email-verification',config('fortify.features',[]),true),
'MFA_enabled'=>in_array('two-factor-authentication',config('fortify.features',[]),true),
'workflow_flags'=>['profiles'=>(bool)config('portal.profile_access_enabled'),'dashboard'=>(bool)config('portal.opportunity_dashboard_access_enabled'),'specialized_drafts'=>(bool)config('portal.opportunity_specialized_drafts_enabled')],
'COUNTRY02_enabled'=>(bool)config('portal.organization_country_enabled'),'counts'=>$counts,
'mail'=>['mailer'=>$mailer,'transport'=>$mail['transport']??null,'endpoint_is_loopback'=>$local,'port'=>$port,
'local_TCP_available'=>$listening,'SMTP_greeting_220'=>$smtpGreeting,'credentials_configured'=>!empty($mail['username'])&&!empty($mail['password']),
'from_is_default_example'=>in_array(config('mail.from.address'),['hello@example.com',null,''],true),'real_contact_delivery_demonstrated'=>false],
'registration_depends_on_workflow_flag'=>false];
if ($designations!==[]) {$proof['designations']=$designations;}
if (($argv[1]??'inspect')==='smtp-check') {
// Open/authenticate the configured TLS transport; never send MAIL FROM, RCPT or DATA.
$proof['mail']['transport_test_attempted']=false;
if (($mail['transport']??null)==='smtp' && is_string($host) && $host!=='') {
$proof['mail']['transport_test_attempted']=true;
$transport=null;
try {
$transport=new Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport($host,$port,($mail['scheme']??null)==='smtps'?true:null);
$transport->getStream()->setTimeout(5);
$transport->setRequireTls(true);
$transport->setUsername((string)($mailUrl?rawurldecode(parse_url($mailUrl,PHP_URL_USER)??''):($mail['username']??'')));
$transport->setPassword((string)($mailUrl?rawurldecode(parse_url($mailUrl,PHP_URL_PASS)??''):($mail['password']??'')));
$transport->start();
$proof['mail']['TLS_required_handshake_completed']=true;
$proof['mail']['TLS_mode']=$transport->getStream()->isTLS()?'implicit':'STARTTLS';
$proof['mail']['SMTP_AUTH_235']=preg_match('/\b235[ -]/',$transport->getStream()->getDebug())===1;
$transport->stop();
} catch (Throwable $e) {
$proof['mail']['TLS_required_handshake_completed']=false;
$proof['mail']['transport_error_type']=$e::class;
// Deliberately omit the message, debug transcript and exception arguments.
}
}
}
if(($argv[1]??'inspect')==='prepare-tests'){
$name='onboarding_20261011_'.gmdate('His').'_test';
throw_unless(preg_match('/^onboarding_20261011_\d{6}_test$/D',$name),RuntimeException::class);
$qa=new PDO('pgsql:host=127.0.0.1;port=55441;dbname=postgres','postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
throw_unless((int)$qa->query('SELECT inet_server_port()')->fetchColumn()===55441,RuntimeException::class,'QA isolation required');
$qa->exec('CREATE DATABASE "'.$name.'" OWNER investmoz_test');
$proof['isolated_test_database']=['database'=>$name,'host'=>'127.0.0.1','port'=>55441,'role'=>'investmoz_test','created_empty'=>true];
$xml=file_get_contents($root.'/phpunit.xml');
$xml=str_replace('<env name="DB_DATABASE" value="investmoz_test"/>','<env name="DB_DATABASE" value="'.$name.'" force="true"/>',$xml);
$xml=str_replace('<env name="APP_ENV" value="testing"/>','<env name="APP_ENV" value="testing" force="true"/>',$xml);
$xml=str_replace('<php>','<php><env name="PORTAL_PROFILE_ACCESS_ENABLED" value="false" force="true"/><env name="PORTAL_OPPORTUNITY_DASHBOARD_ACCESS_ENABLED" value="false" force="true"/><env name="PORTAL_OPPORTUNITY_SPECIALIZED_DRAFTS_ENABLED" value="false" force="true"/>',$xml);
foreach(['DB_CONNECTION','DB_HOST','DB_PORT','DB_USERNAME','DB_PASSWORD','DB_URL','MAIL_MAILER','QUEUE_CONNECTION','SESSION_DRIVER'] as $environment){
$xml=preg_replace('/(<env name="'.preg_quote($environment,'/').'" value="[^"]*")\/>/','$1 force="true"/>',$xml);
}
$prefix=str_replace('\\','/',$root).'/';
$xml=str_replace('bootstrap="vendor/autoload.php"','bootstrap="'.$prefix.'vendor/autoload.php"',$xml);
$xml=str_replace('<directory>tests/','<directory>'.$prefix.'tests/',$xml);
$xml=str_replace('<directory>app</directory>','<directory>'.$prefix.'app</directory>',$xml);
file_put_contents($private.'/onboarding-qa-phpunit.xml',$xml);
}
$report=match($argv[1]??'inspect') {'designations'=>'onboarding-designations-readonly.json','smtp-check'=>'onboarding-smtp-preflight.json',default=>'onboarding-readiness.json'};
file_put_contents($private.'/'.$report,json_encode($proof,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
echo json_encode($proof,JSON_THROW_ON_ERROR).PHP_EOL;