47 lines
3.4 KiB
PHP
47 lines
3.4 KiB
PHP
<?php
|
|
// Copied into the LocalService QA root. No access to live .env, queue or providers.
|
|
ini_set('zend.exception_ignore_args', '1');
|
|
$root = dirname(__DIR__);
|
|
$output = $root.'/storage/qa-proof';
|
|
set_exception_handler(static function (Throwable $e) use ($output): void {
|
|
file_put_contents($output.'/worker-error.json', json_encode(['at'=>gmdate('c'),'error_class'=>get_class($e),'message_omitted'=>true,'pid'=>getmypid()], JSON_THROW_ON_ERROR));
|
|
exit(1);
|
|
});
|
|
$app = (static fn ($p) => require $p)($root.'/tools/upgrade-runtime.php');
|
|
throw_unless((int) config('database.connections.pgsql.port') === 55441
|
|
&& config('queue.connections.database.queue') === 'localservice-qa'
|
|
&& (int) config('services.malware.port') === 13310
|
|
&& ! config('portal.notifications_enabled') && config('mail.default') === 'log', RuntimeException::class);
|
|
$attempt = [];
|
|
foreach (['storage/qa-proof/write-proof.txt','storage/logs/write-proof.txt','bootstrap/cache/write-proof.txt','scanner-writable/write-proof.txt'] as $relative) {
|
|
$attempt[$relative] = file_put_contents($root.'/'.$relative, 'QA LocalService write proof'.PHP_EOL) !== false;
|
|
throw_unless($attempt[$relative], RuntimeException::class, 'Required QA write denied');
|
|
}
|
|
$negative = [];
|
|
foreach (['.env','app/Services/PortalSuperusers.php','vendor/composer/autoload_real.php','config/portal.php','forbidden-qa-sentinel.txt'] as $relative) {
|
|
$handle = @fopen($root.'/'.$relative, 'r+');
|
|
$negative['write_denied:'.$relative] = $handle === false;
|
|
if (is_resource($handle)) fclose($handle);
|
|
throw_unless($handle === false, RuntimeException::class, 'QA read-only area is writable by LocalService');
|
|
}
|
|
$negative['forbidden_synthetic_read_denied'] = @file_get_contents($root.'/forbidden-qa-sentinel.txt') === false;
|
|
throw_unless($negative['forbidden_synthetic_read_denied'], RuntimeException::class, 'Unnecessary synthetic read allowed');
|
|
$health = app(App\Services\Malware\MalwareScanner::class)->health();
|
|
throw_unless($health['available'] ?? false, RuntimeException::class, 'QA scanner unavailable');
|
|
if (($health['signatures_at'] ?? null) instanceof DateTimeInterface) $health['signatures_at'] = $health['signatures_at']->format('c');
|
|
$db = Illuminate\Support\Facades\DB::class;
|
|
$before = $db::table('jobs')->where('queue','localservice-qa')->count();
|
|
$status = $app->handleCommand(new Symfony\Component\Console\Input\ArrayInput([
|
|
'command'=>'queue:work','connection'=>'database','--queue'=>'localservice-qa',
|
|
'--once'=>true,'--tries'=>3,'--timeout'=>150,'--memory'=>256,'--no-interaction'=>true]));
|
|
$proof = ['at'=>gmdate('c'),'pid'=>getmypid(),'status'=>$status,
|
|
'target'=>config('database.connections.pgsql.database').':55441','queue'=>'localservice-qa',
|
|
'php'=>['version'=>PHP_VERSION,'sapi'=>PHP_SAPI,'memory_limit'=>ini_get('memory_limit'),
|
|
'gd'=>extension_loaded('gd'),'webp'=>function_exists('imagewebp')],'scanner'=>$health,
|
|
'config_read_and_QA_database_guard_passed'=>true,'authorized_writes'=>$attempt,'negative_access'=>$negative,
|
|
'jobs_before'=>$before,'jobs_after'=>$db::table('jobs')->where('queue','localservice-qa')->count(),
|
|
'failed_jobs'=>$db::table('failed_jobs')->count(),'peak_bytes'=>memory_get_peak_usage(true),
|
|
'external_notifications_enabled'=>false,'active_writes'=>0];
|
|
file_put_contents($output.'/worker-results.jsonl', json_encode($proof, JSON_THROW_ON_ERROR).PHP_EOL, FILE_APPEND);
|
|
exit($status);
|