make(Kernel::class)->bootstrap(); $db = DB::connection(); if (! $app->environment('testing') || $db->getDatabaseName() !== 'portal_services_test' || (string) $db->getConfig('port') !== '55441') { throw new RuntimeException('Isolated QA required'); } if ($db->selectOne("SELECT count(*) AS n FROM pg_namespace WHERE nspname='mne'")->n) { throw new RuntimeException('QA schema mne must be absent'); } $run = function (string $file) use ($db): void { $sql = preg_replace('/^BEGIN;\s*$/m', '', file_get_contents(base_path('migrations/'.$file))); $db->unprepared(preg_replace('/COMMIT;\s*$/', '', $sql)); }; $check = function (bool $condition, string $message): void { if (! $condition) { throw new RuntimeException($message); } }; $reject = function (callable $operation, string $state) use ($db, $check): void { $db->statement('SAVEPOINT rejection'); $rejected = false; try { $operation(); } catch (QueryException $e) { $rejected = $e->getCode() === $state; } $db->statement('ROLLBACK TO SAVEPOINT rejection'); $check($rejected, 'Expected database rejection '.$state); }; $db->beginTransaction(); try { foreach (['001_mne_schema.sql', '002_mne_existing_territories.sql', '003_mne_integrity.sql', '004_mne_compatibility.sql'] as $file) { $run($file); } $run('004_mne_compatibility.sql'); $run('004_mne_compatibility_down.sql'); $run('004_mne_compatibility.sql'); $user = User::factory()->create(); config(['existing-business.enabled' => true]); $business = app(ExistingBusinessDrafts::class)->save($user, [ 'modality' => 'company_sale', 'classification' => 'confidential', 'reason' => 'Synthetic compatibility test', 'payload' => ['title' => 'Synthetic private business'], ]); $stranger = User::factory()->create(); $loaded = app(BusinessRepository::class)->find($business->id); $check(Gate::forUser($user)->allows('view', $loaded), 'Owner lost access'); $check(Gate::forUser($stranger)->denies('view', $loaded), 'Unauthorized access'); $sector = $db->table('public.sectors')->insertGetId(['name' => 'Synthetic compatibility', 'slug' => 'synthetic-compatibility', 'is_active' => true]); $backfill = app(CompatibilityBackfill::class); $dryStatus = Artisan::call('mne:backfill-compatibility', ['--batch' => 2, '--dry-run' => true]); $check($dryStatus === 0, 'Dry run failed'); foreach (['identity_links', 'sector_links', 'business_links', 'compatibility_checkpoints', 'compatibility_rejections'] as $table) { $check($db->table('mne.'.$table)->count() === 0, 'Dry run persisted data: '.$table); } $first = $backfill->run(2); $links = $db->table('mne.identity_links')->orderBy('user_id')->get()->toJson(); $second = $backfill->run(2); $check($first === $second, 'Backfill counts changed'); $check($links === $db->table('mne.identity_links')->orderBy('user_id')->get()->toJson(), 'Backfill not idempotent'); $check(app(SectorResolver::class)->resolve($sector) !== null, 'Sector not resolved'); $check(app(SectorResolver::class)->resolve(2147483647) === null, 'Unknown sector invented'); $row = (array) $db->table('mne.identity_links')->where('user_id', $user->id)->first(); unset($row['id']); $reject(fn () => $db->table('mne.identity_links')->insert($row), '23505'); $row['user_id'] = 9223372036854775807; $reject(fn () => $db->table('mne.identity_links')->insert($row), '23503'); $reject(fn () => $db->table('mne.identity_links')->where('user_id', $user->id)->update(['status' => 'active']), '23514'); $party = $db->selectOne("INSERT INTO mne.parties(party_type,display_name) VALUES ('person','Synthetic party') RETURNING id")->id; $db->table('mne.identity_links')->where('user_id', $user->id)->update(['party_id' => $party, 'status' => 'active']); $check(app(IdentityResolver::class)->resolve($user->id) === $party, 'Identity link not resolved'); $reject(fn () => $db->table('mne.identity_links')->where('user_id', $stranger->id)->update(['party_id' => $party]), '23505'); $db->table('mne.identity_links')->where('user_id', $user->id)->update(['status' => 'revoked']); $check(app(IdentityResolver::class)->resolve($user->id) === null, 'Revoked identity resolved'); $reject(fn () => $run('004_mne_compatibility_down.sql'), 'P0001'); $check($db->table('mne.existing_businesses')->count() === 0, 'Backfill copied business data'); $check($db->table('mne.parties')->count() === 1, 'Backfill invented identities'); $db->statement('SAVEPOINT schema_drift'); $db->statement('ALTER TABLE mne.business_links ADD COLUMN unexpected text'); $reject(fn () => $run('004_mne_compatibility.sql'), 'P0001'); $db->statement('ROLLBACK TO SAVEPOINT schema_drift'); $db->table('public.sectors')->where('id', $sector)->update(['slug' => 'changed-compatibility']); $check(app(SectorResolver::class)->resolve($sector) === null, 'Stale code resolved'); $backfill->run(2); $check($db->table('mne.sector_links')->where('sector_id', $sector)->value('status') === 'pending', 'Changed source not invalidated'); $run('005_mne_compatibility_guards.sql'); $run('005_mne_compatibility_guards.sql'); $reject(fn () => $db->table('mne.compatibility_controls')->where('capability', 'canonical_read') ->update(['enabled' => true, 'evidence_reference' => 'Synthetic activation attempt']), '23514'); $reject(fn () => $db->table('mne.compatibility_controls')->where('capability', 'canonical_read')->update(['percentage' => 1]), '23514'); $run('005_mne_compatibility_guards_down.sql'); $run('005_mne_compatibility_guards.sql'); // Transactional test role: cannot own objects, create schemas, or disable protections. $role = 'mne_runtime_test_'.getmypid(); $db->statement('CREATE ROLE '.$role.' NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOBYPASSRLS'); $db->statement('GRANT USAGE ON SCHEMA mne TO '.$role); $db->statement('GRANT SELECT, INSERT ON mne.audit_events, mne.business_status_history, mne.document_versions, mne.negotiation_events TO '.$role); $db->statement('SET LOCAL ROLE '.$role); $check(! $db->selectOne('SELECT rolsuper FROM pg_roles WHERE rolname=current_user')->rolsuper, 'Runtime test is superuser'); $db->statement("INSERT INTO mne.audit_events(action,subject_type,subject_id,correlation_id) VALUES ('synthetic','test',gen_random_uuid(),gen_random_uuid())"); foreach (['audit_events', 'business_status_history', 'document_versions', 'negotiation_events'] as $table) { foreach (["UPDATE mne.$table SET id=id", "DELETE FROM mne.$table", "TRUNCATE mne.$table"] as $sql) { $reject(fn () => $db->statement($sql), '42501'); } } $reject(fn () => $db->statement('ALTER TABLE mne.audit_events DISABLE TRIGGER ALL'), '42501'); $reject(fn () => $db->statement('CREATE TABLE mne.forbidden_runtime_table(id integer)'), '42501'); $db->statement('RESET ROLE'); echo json_encode(['passed' => true, 'dry_run_rolled_back' => true, '005_repeated_and_reversed' => true, 'canonical_activation_rejected' => true, 'up_twice' => true, 'down_reapply' => true, 'backfill_replay' => true, 'uniqueness_fk_activation_down_guards' => true, 'counts' => $first]).PHP_EOL; } finally { $db->rollBack(); }