87 lines
5.9 KiB
PHP
87 lines
5.9 KiB
PHP
<?php
|
|
|
|
// Synthetic metadata baseline for the historical fiscal preservation tests only.
|
|
use App\Models\SimulationFormDraft;
|
|
use App\Models\User;
|
|
use App\Support\IsolatedQaDatabase;
|
|
use Database\Seeders\ProductionReferenceSeeder;
|
|
use Database\Seeders\TerritoryReferenceSeeder;
|
|
use Illuminate\Contracts\Console\Kernel;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
|
|
require dirname(__DIR__).'/vendor/autoload.php';
|
|
try {
|
|
if (PHP_SAPI !== 'cli' || ! isset($argv)) {
|
|
throw new RuntimeException('Explicit CLI arguments required.');
|
|
}
|
|
$app = require dirname(__DIR__).'/bootstrap/app.php';
|
|
$app->make(Kernel::class)->bootstrap();
|
|
$referencesOnly = in_array('--references-only', $argv, true);
|
|
$allowed = $referencesOnly ? ['simulator_fiscal_delta_20261021_test', 'proactive_investment_20261027_test'] : ['proactive_investment_20261027_test'];
|
|
if ($app->configurationIsCached() || ! IsolatedQaDatabase::allowsSchemaChanges()
|
|
|| ! in_array(DB::connection()->getDatabaseName(), $allowed, true)) {
|
|
throw new RuntimeException('Explicit isolated proactive QA database required.');
|
|
}
|
|
$marker = 'synthetic-fiscal-preservation-20261102';
|
|
$tables = ['opportunities', 'documents', 'opportunity_documents', 'simulation_form_drafts', 'users', 'organizations', 'audit_events'];
|
|
if (! $referencesOnly) {
|
|
DB::transaction(function () use ($marker, $tables): void {
|
|
DB::select('select pg_advisory_xact_lock(261102, 1)');
|
|
$actor = User::find(1021);
|
|
if ($actor && $actor->email !== 'synthetic-fiscal-preservation@example.invalid') {
|
|
throw new RuntimeException('Existing identity 1021 differs; no account may be reset.');
|
|
}
|
|
if (DB::table('audit_events')->where('source_system', $marker)->exists()) {
|
|
// Only this tool's own synthetic baseline may be archived. A live
|
|
// draft for this actor would correctly prevent creating another.
|
|
DB::table('simulation_form_drafts')->where('owner_user_id', 1021)
|
|
->where('create_key_hash', hash('sha256', $marker.'-key'))->whereNull('deleted_at')
|
|
->update(['deleted_at' => now()]);
|
|
foreach ($tables as $table) {
|
|
if (DB::table($table)->count() === 0) {
|
|
throw new RuntimeException('An existing baseline is incomplete; inspect before repairing.');
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
if (! $actor) {
|
|
$actor = User::factory()->create(['id' => 1021, 'name' => 'SYNTHETIC QA fiscal preservation',
|
|
'email' => 'synthetic-fiscal-preservation@example.invalid', 'password' => bcrypt(Str::random(64)), 'email_verified_at' => now()]);
|
|
DB::statement("select setval(pg_get_serial_sequence('users','id'), greatest((select max(id) from users), 1021))");
|
|
}
|
|
$organization = (string) Str::uuid();
|
|
DB::table('organizations')->insert(['id' => $organization, 'name' => 'SYNTHETIC QA preservation organization',
|
|
'organization_type' => 'private', 'source_system' => $marker, 'data_classification' => 'internal']);
|
|
$sector = DB::table('sectors')->insertGetId(['name' => 'SYNTHETIC QA preservation sector', 'slug' => $marker, 'is_active' => true]);
|
|
$opportunity = DB::table('opportunities')->insertGetId(['reference' => $marker, 'slug' => $marker,
|
|
'title' => 'SYNTHETIC QA preservation opportunity', 'status' => 'draft', 'sector_id' => $sector]);
|
|
$document = (string) Str::uuid();
|
|
$bytes = 'SYNTHETIC QA metadata baseline; not a scanned or downloadable document.';
|
|
DB::table('documents')->insert(['id' => $document, 'file_name' => 'SYNTHETIC-QA-METADATA.txt', 'media_type' => 'text/plain',
|
|
'storage_key' => $marker.'/'.$document, 'sha256' => hash('sha256', $bytes), 'status' => 'active', 'uploaded_by' => $actor->id,
|
|
'source_system' => $marker, 'data_classification' => 'internal']);
|
|
DB::table('opportunity_documents')->insert(['id' => (string) Str::uuid(), 'opportunity_id' => $opportunity,
|
|
'document_id' => $document, 'payload' => json_encode(['title' => 'SYNTHETIC metadata preservation only', 'visibility' => 'internal']), 'created_by' => $actor->id]);
|
|
SimulationFormDraft::create(['id' => (string) Str::uuid(), 'owner_user_id' => $actor->id, 'version_no' => 1, 'deleted_at' => now(),
|
|
'create_key_hash' => hash('sha256', $marker.'-key'), 'create_payload_hash' => hash('sha256', $marker.'-payload'),
|
|
'snapshot_sha256' => hash('sha256', $marker.'-snapshot'), 'personal_snapshot' => SimulationFormDraft::encryptSnapshot([]),
|
|
'economic_snapshot' => SimulationFormDraft::encryptSnapshot(['project_title' => 'SYNTHETIC pre-existing draft'])]);
|
|
DB::table('audit_events')->insert(['source_system' => $marker, 'entity_type' => 'qa-fixture', 'actor_user_id' => $actor->id,
|
|
'action' => 'synthetic_preservation_baseline', 'after_data' => json_encode(['synthetic' => true, 'metadata_only' => true])]);
|
|
});
|
|
}
|
|
$seeder = $referencesOnly ? ProductionReferenceSeeder::class : TerritoryReferenceSeeder::class;
|
|
if (Artisan::call('db:seed', ['--class' => $seeder, '--force' => true]) !== 0) {
|
|
throw new RuntimeException('Packaged territory reference preparation failed.');
|
|
}
|
|
echo json_encode(['database' => DB::connection()->getDatabaseName(), 'synthetic_metadata' => ! $referencesOnly, 'packaged_territories' => DB::table('geo_locations')->count(),
|
|
'counts' => array_combine($tables, array_map(fn (string $table): int => DB::table($table)->count(), $tables))], JSON_THROW_ON_ERROR).PHP_EOL;
|
|
|
|
} catch (Throwable $error) {
|
|
fwrite(STDERR, $error::class.': fixture preparation failed ('.$error->getCode().').'.PHP_EOL);
|
|
exit(1);
|
|
}
|