55 lines
5.7 KiB
PHP
55 lines
5.7 KiB
PHP
<?php
|
|
|
|
// Inspect the exact active target after stopping. No providers or active database writes.
|
|
use App\Services\OrganizationCountryInstallation;
|
|
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
|
|
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
|
|
|
|
$root = dirname(__DIR__);
|
|
require $root.'/vendor/autoload.php';
|
|
ini_set('zend.exception_ignore_args', '1');
|
|
set_exception_handler(static function (Throwable $error): void { fwrite(STDERR, 'Stop-state inspection failed; see local diagnostic.'.PHP_EOL); exit(1); });
|
|
$app = require $root.'/bootstrap/app.php';
|
|
(new LoadEnvironmentVariables)->bootstrap($app);
|
|
(new LoadConfiguration)->bootstrap($app);
|
|
$dir = $root.'/storage/app/private/investmoz-v2/portal-audit';
|
|
$before = json_decode(file_get_contents($dir.'/country-activation-preflight-20261011.json'), true, 512, JSON_THROW_ON_ERROR);
|
|
$c = config('database.connections.'.config('database.default'));
|
|
throw_unless($c['driver'] === 'pgsql' && empty($c['url']) && (int) $c['port'] === 5432 && $c['database'] === 'investemoz', RuntimeException::class, 'Source refused.');
|
|
$pdo = new PDO('pgsql:host='.$c['host'].';port='.$c['port'].';dbname='.$c['database'], $c['username'], $c['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
$pdo->exec('BEGIN ISOLATION LEVEL REPEATABLE READ 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($identity['database'] === 'investemoz' && (int) $identity['port'] === 5432 && $identity['read_only'] === 'on', RuntimeException::class, 'Source refused.');
|
|
$tables = [];
|
|
foreach ($pdo->query("SELECT schemaname,tablename FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema') ORDER BY schemaname,tablename")->fetchAll(PDO::FETCH_ASSOC) as $t) {
|
|
$name = '"'.str_replace('"', '""', $t['schemaname']).'"."'.str_replace('"', '""', $t['tablename']).'"';
|
|
$rows = $pdo->query('SELECT row_to_json(t)::text FROM '.$name.' t ORDER BY row_to_json(t)::text')->fetchAll(PDO::FETCH_COLUMN);
|
|
$tables[$name] = ['count' => count($rows), 'sha256' => hash('sha256', implode("\n", $rows))];
|
|
}
|
|
$changed = [];
|
|
foreach ($tables as $name => $v) { if (($before['tables'][$name] ?? null) !== $v) { $changed[] = $name; } }
|
|
throw_unless(array_keys($tables) === array_keys($before['tables']), RuntimeException::class, 'Table inventory unexpectedly changed.');
|
|
$counts = [];
|
|
foreach (array_keys($before['counts']) as $table) { $counts[$table] = (int) $pdo->query('SELECT count(*) FROM "'.$table.'"')->fetchColumn(); }
|
|
$countryAudit = (int) $pdo->query("SELECT count(*) FROM audit_events WHERE source_system='organization-country-installation'")->fetchColumn();
|
|
$installations = $pdo->query("SELECT migration FROM migrations WHERE migration IN ('2026_10_09_030000_extend_opportunity_resources','2026_10_10_040000_create_portal_profile_authorization','2026_10_09_190000_prepare_investor_path','2026_10_10_050000_extend_organization_country') ORDER BY migration")->fetchAll(PDO::FETCH_COLUMN);
|
|
$columns = $pdo->query("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")->fetchAll(PDO::FETCH_COLUMN);
|
|
$pdo->exec('ROLLBACK');
|
|
throw_unless($installations === [] && $columns === [] && $countryAudit === 0, RuntimeException::class, 'Installation unexpectedly present.');
|
|
throw_unless(array_diff($changed, ['"public"."sessions"', '"public"."cache"', '"public"."cache_locks"']) === [], RuntimeException::class, 'Business data changed during inspection.');
|
|
foreach (['users','organizations','memberships','migrations','audit_events'] as $name) { throw_unless($counts[$name] === $before['counts'][$name], RuntimeException::class, 'Unexpected business mutation.'); }
|
|
$flagNames = ['organization_country_enabled','opportunity_dashboard_access_enabled','profile_access_enabled','opportunity_specialized_drafts_enabled','opportunity_modular_profiles_qa_enabled','legacy_content_qa_enabled'];
|
|
$flags = [];
|
|
foreach ($flagNames as $name) { $flags[$name] = (bool) config('portal.'.$name); }
|
|
$flags['investor_path_enabled'] = (bool) config('investor-path.enabled');
|
|
throw_if(in_array(true, $flags, true), RuntimeException::class, 'Unexpected flag enabled.');
|
|
throw_unless(hash_file('sha256', $root.'/public/build/manifest.json') === '75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94', RuntimeException::class, 'Original manifest not restored.');
|
|
$result = ['result' => 'stopped_before_authenticated_apply', 'at' => gmdate('c'), 'target' => $identity, 'code_hash' => (new OrganizationCountryInstallation)->fingerprint(),
|
|
'approved_delivery' => 'c68ceef9d4a3', 'failure' => 'C110: crypto.randomUUID is not a function on actual HTTP portal-investidor.test origin.',
|
|
'original_manifest_restored' => true, 'flags' => $flags, 'table_count' => count($tables), 'counts_before' => $before['counts'], 'counts_after' => $counts, 'changed_tables' => $changed,
|
|
'business_rows_unchanged' => true, 'installation_audit_events' => $countryAudit, 'installed_packages' => $installations, 'country_columns' => $columns,
|
|
'authenticated_preview_obtained' => false, 'authenticated_apply_performed' => false, 'database_effect' => 'Normal guest HTTP session/cache only; no DDL, business rows, accounts, organizations or representations changed.',
|
|
'next' => 'Correct UUID initialization in QA, rebuild/fix a new revision and repeat the authenticated preview before separately authorized activation.' ];
|
|
file_put_contents($dir.'/country-activation-stopped-20261011.json', json_encode($result, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
|
echo json_encode($result, JSON_THROW_ON_ERROR).PHP_EOL;
|