Files
SGF/app/Modules/Purchasing/InternalRequisitionQa.php
T
2026-11-04 09:37:20 +02:00

77 lines
4.5 KiB
PHP

<?php
namespace App\Modules\Purchasing;
use Illuminate\Support\Facades\DB;
use LogicException;
/** Mounts the existing shared requisition adapter in a fresh, pinned QA composition. */
final class InternalRequisitionQa
{
public const FILES = [
'packages/purchasing/src/RequisitionPort.php',
'packages/purchasing/src/RequisitionFailure.php',
'packages/purchasing/src/InternalRequisitions.php',
'integrations/sgf/internal-requisitions/bootstrap.php',
'integrations/sgf/internal-requisitions/Schema.php',
'integrations/sgf/internal-requisitions/Port.php',
'integrations/sgf/internal-requisitions/Controller.php',
'integrations/sgf/internal-requisitions/routes.php',
'integrations/sgf/internal-requisitions/screen.php',
'integrations/sgf/internal-requisitions/screen.mjs',
];
public static function verifiedBundle(string $bundle, string $pin): string
{
$root = realpath($bundle);
if ($root === false || is_link($bundle) || ! preg_match('/^[a-f0-9]{64}$/D', $pin)
|| ! is_file($root.'/manifest.json') || is_link($root.'/manifest.json')
|| ! hash_equals($pin, hash_file('sha256', $root.'/manifest.json'))) {
throw new LogicException('REQUISITION_QA_BUNDLE_REFUSED');
}
$manifest = json_decode(file_get_contents($root.'/manifest.json'), true, 32, JSON_THROW_ON_ERROR);
$files = $manifest['files'] ?? [];
$expected = self::FILES; $actual = array_keys($files); sort($expected); sort($actual);
if (($manifest['format'] ?? null) !== 'sgf.requisitions.qa-bundle.v1' || $actual !== $expected) {
throw new LogicException('REQUISITION_QA_MANIFEST_REFUSED');
}
foreach ($files as $relative => $hash) {
$file = realpath($root.'/'.$relative);
if ($file === false || ! str_starts_with(strtolower($file), strtolower($root.DIRECTORY_SEPARATOR))
|| ! is_file($file) || ! is_string($hash) || ! preg_match('/^[a-f0-9]{64}$/D', $hash)
|| ! hash_equals($hash, hash_file('sha256', $file))) {
throw new LogicException('REQUISITION_QA_SOURCE_REFUSED');
}
$part = $root;
foreach (explode('/', $relative) as $segment) {
$part .= '/'.$segment;
if (is_link($part)) throw new LogicException('REQUISITION_QA_LINK_REFUSED');
}
}
return $root;
}
public static function mount(): ?string
{
if (config('internal_requisitions.qa_enabled') !== true) return null;
if (! app()->environment('budget-testing')) throw new LogicException('REQUISITION_QA_ENVIRONMENT_REFUSED');
$c = DB::connection(); $config = $c->getConfig();
$run = (string) getenv('SGF_ISOLATED_REGRESSION_RUN');
if (! preg_match('/^[a-f0-9]{12}$/D', $run) || ($config['driver'] ?? null) !== 'pgsql'
|| ($config['host'] ?? null) !== '127.0.0.1' || (string) ($config['port'] ?? '') !== '55439'
|| ! preg_match('/^budget_core_sgf_([a-f0-9]{12})$/D', $config['database'] ?? '', $m)
|| ($config['username'] ?? null) !== 'ir_composition_'.$m[1]
|| ! empty($config['url']) || ! empty($config['read']) || ! empty($config['write'])
|| ($config['search_path'] ?? 'public') !== 'public') throw new LogicException('REQUISITION_QA_DATABASE_REFUSED');
$identity = $c->selectOne("SELECT current_database() db,current_user role,current_setting('cluster_name') cluster,
rolsuper OR rolcreatedb OR rolcreaterole OR rolreplication OR rolbypassrls elevated FROM pg_roles WHERE rolname=current_user");
if ($identity->db !== $config['database'] || $identity->role !== $config['username'] || $identity->elevated
|| $identity->cluster !== 'sgf_modular_regression_'.$run) throw new LogicException('REQUISITION_QA_IDENTITY_REFUSED');
$bundle = self::verifiedBundle((string) config('internal_requisitions.qa_bundle'), (string) config('internal_requisitions.qa_manifest_sha256'));
$expected = 'C:/laragon/data/sgf-tempo/run/modular-regression-'.$run.'/private/requisition-composition-'.$m[1].'/bundle';
if (strtolower(str_replace('\\', '/', $bundle)) !== strtolower($expected)) throw new LogicException('REQUISITION_QA_LOCATION_REFUSED');
require_once $bundle.'/integrations/sgf/internal-requisitions/bootstrap.php';
return $bundle.'/integrations/sgf/internal-requisitions/routes.php';
}
}