Files
Investidor-V2/tools/portal-country-candidate-finalize.php
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

117 lines
14 KiB
PHP

<?php
// Preparation only. No application providers, database connection or activation.
use App\Services\OrganizationCountryInstallation;
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
$root = dirname(__DIR__);
require $root.'/vendor/autoload.php';
$app = require $root.'/bootstrap/app.php';
(new LoadEnvironmentVariables)->bootstrap($app);
(new LoadConfiguration)->bootstrap($app);
$dir = $root.'/storage/app/private/investmoz-v2/portal-audit';
$read = static function (string $file): array {
$bytes = file_get_contents($file);
if (str_starts_with($bytes, "\xff\xfe")) {
$bytes = mb_convert_encoding(substr($bytes, 2), 'UTF-8', 'UTF-16LE');
}
$bytes = preg_replace('/^\xEF\xBB\xBF/', '', $bytes);
return json_decode(trim($bytes), true, 512, JSON_THROW_ON_ERROR);
};
$link = $read($dir.'/country-candidate-backup-latest.json');
$backup = $read($link['path']);
$installer = new OrganizationCountryInstallation;
throw_unless($backup['code_hash'] === $installer->fingerprint() && $backup['candidate_qa_manifest_sha256'] === hash_file('sha256', $root.'/public/build-qa-opportunities/manifest.json'), RuntimeException::class, 'Candidate changed since restored backup.');
foreach (['restore_verified', 'files_verified', 'compatibility_verified', 'reversal_verified', 'legacy_profile_controller_verified'] as $criterion) {
throw_unless($backup[$criterion] === true, RuntimeException::class, 'Candidate compatibility criterion missing.');
}
throw_unless($backup['source_installations']['migrations'] === [] && $backup['source_installations']['organization_count'] === 0 && $backup['active_writes'] === 0, RuntimeException::class, 'Active inventory changed; renew preview.');
$unit = $read($dir.'/revision-regression-final-20261011.log');
$stan = $read($dir.'/revision-final-phpstan-20261011.log');
$quality = $read($dir.'/revision-quality-result.json');
$build = $read($dir.'/revision-build-result.json');
throw_unless($unit['result'] === 'passed' && $stan['result'] === 'passed' && $quality['type_exit'] === 0 && $quality['lint_exit'] === 0 && $build['build_exit'] === 0, RuntimeException::class, 'Candidate quality criterion missing.');
$countryUnit = $read($dir.'/country-candidate-regression-20261011.log');
$countryStan = $read($dir.'/country-candidate-stan-20261011.log');
$production = $read($dir.'/country-production-stage-latest.json');
$productionBrowser = $read($dir.'/country-production-chromium-20261011.json');
$productionTypes = $read($dir.'/country-production-types-result.json');
$platform = $read($dir.'/country-production-platform-20261011.json');
$capabilities = $read($dir.'/country-target-capabilities-20261011.json');
throw_unless($capabilities['result'] === 'passed' && $capabilities['identity']['database'] === $backup['target']['database'] && $capabilities['identity']['read_only'] === 'on', RuntimeException::class, 'Source service role capability missing.');
$productionPersistence = $read($dir.'/country-production-persistence-20261011.json');
$coldProductionPersistence = $read($dir.'/country-production-cold-persistence-20261011.json');
throw_unless($platform['result'] === 'passed' && $productionPersistence['result'] === 'passed' && $coldProductionPersistence['result'] === 'passed'
&& $productionPersistence['code_hash'] === $installer->fingerprint() && $coldProductionPersistence['code_hash'] === $installer->fingerprint(), RuntimeException::class, 'Runtime/persistence evidence missing.');
throw_unless($countryUnit['result'] === 'passed' && $countryStan['result'] === 'passed' && $production['result'] === 'passed'
&& $productionBrowser['result'] === 'passed' && $productionTypes['exit'] === 0, RuntimeException::class, 'Final production/MFA quality criterion missing.');
throw_unless($productionBrowser['code_hash'] === $installer->fingerprint() && $productionBrowser['production_manifest_sha256'] === $production['build_manifest_sha256']
&& $productionBrowser['session_driver'] === $backup['runtime']['session_driver'] && $backup['production_manifest_sha256'] === $production['build_manifest_sha256'] && $backup['sequences_verified'], RuntimeException::class, 'Final build/backup revision mismatch.');
foreach ($production['inputs'] as $file => $expected) {
throw_unless(hash_file('sha256', $root.'/'.$file) === $expected, RuntimeException::class, 'Production source input changed.');
}
foreach ($production['assets'] as $file => $expected) {
throw_unless(hash_file('sha256', $production['build_directory'].'/'.$file) === $expected, RuntimeException::class, 'Production asset changed.');
}
foreach ($production['active_assets'] as $file => $expected) {
throw_unless(hash_file('sha256', $root.'/public/build/'.$file) === $expected, RuntimeException::class, 'Active asset changed during preparation.');
}
$schema = $read($dir.'/country-schema-compare-20261011.json');
throw_unless($schema['backup_code_hash'] === $installer->fingerprint() && count($schema['additional_qa_tables']) === 7 && $schema['missing_in_qa_tables'] === [], RuntimeException::class, 'Table reconciliation missing.');
$receipts = [];
foreach (['next-organization-chromium-20261010.json', 'revision-land-replay-chromium-20261011.json'] as $name) {
$proof = $read($dir.'/'.$name);
throw_unless($proof['result'] === 'passed' && $proof['active_writes'] === 0, RuntimeException::class, 'Country browser criterion missing.');
$receipts[$name] = hash_file('sha256', $dir.'/'.$name);
}
$backup['qa_passed'] = true;
$backup['candidate_id'] = 'CAND-COUNTRY02-20261011';
file_put_contents($link['path'], json_encode($backup, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
file_put_contents($root.'/storage/app/private/investmoz-v2/organization-country-installation/readiness.json', json_encode($backup, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$files = [];
foreach ($installer->files() as $file) {
$files[$file] = hash_file('sha256', $root.'/'.$file);
}
$out = $root.'/outputs/investmoz-country02-candidate-20261011';
if (! is_dir($out)) {
mkdir($out, 0700, true);
}
if (is_file($out.'/manifesto-candidata.json')) {
$prior = $read($out.'/manifesto-candidata.json');
if ($prior['code_hash'] !== $installer->fingerprint()) {
$history = $out.'/manifesto-candidata-'.substr($prior['code_hash'], 0, 12).'-anterior.json';
if (! is_file($history)) {
copy($out.'/manifesto-candidata.json', $history);
}
}
}
$revision = hash('sha256', json_encode(['code_hash' => $installer->fingerprint(), 'production_manifest' => $production['build_manifest_sha256'], 'input_hash' => $production['input_hash'], 'assets' => $production['assets']], JSON_THROW_ON_ERROR));
$manifest = ['candidate_id' => $backup['candidate_id'], 'fixed_at' => gmdate('c'), 'code_hash' => $installer->fingerprint(), 'files' => $files,
'previous_code_hash' => '84a0e4a33dbfa8d727a190b2cd6280c23751ec15d5b1c2d436b415ff7ed7528e', 'delivery_revision' => $revision,
'revision_reason' => 'Record completed Fortify MFA independently of optional profile availability; include AppServiceProvider in installer fingerprint. Production build and transitive inputs now fixed.',
'production' => ['manifest_sha256' => $production['build_manifest_sha256'], 'input_hash' => $production['input_hash'], 'directory' => $production['build_directory'], 'base' => $production['public_base'], 'public_env' => $production['public_env'], 'files' => $production['assets'], 'transitive_inputs' => $production['inputs'], 'generated_routes' => $production['generated_routes'], 'types_exit' => $productionTypes['exit'], 'browser_receipt_sha256' => hash_file('sha256', $dir.'/country-production-chromium-20261011.json'), 'assets_loaded_verified' => count($productionBrowser['assets'])],
'platform_compatibility' => $platform, 'target_database_capabilities_read_only' => $capabilities,
'production_rehearsal' => ['session_driver' => $productionBrowser['session_driver'], 'configuration_difference_for_isolation' => ['QA database/port, private runtime paths, distinct cookie/origin, array cache and sync queue; no external service', 'All optional opportunity/profile/investor-path/legacy flags disabled; only country enabled on QA'], 'persistence_receipt_sha256' => hash_file('sha256', $dir.'/country-production-persistence-20261011.json'), 'cold_mfa_browser_receipt_sha256' => hash_file('sha256', $dir.'/country-production-file-session-20261011.json'), 'cold_persistence_receipt_sha256' => hash_file('sha256', $dir.'/country-production-cold-persistence-20261011.json')],
'qa_assets_manifest_sha256' => $backup['candidate_qa_manifest_sha256'], 'active_manifest_sha256' => $backup['active_manifest_sha256'],
'included' => ['Organization master incorporation country with provenance/version/audit', 'Explicit reuse in existing private company/submission, preserving historical values', 'Existing organization membership/policies; legacy installation authorization with verified email and MFA', 'Authenticated optional 050000 installation, preview/dependencies/idempotency/audit/inconsistency rejection', 'Flag disable reversal preserving data'],
'routes' => ['/investidor/profile', '/investidor/organizations/{id}/country', '/investidor/companies/{id}/organization-country', '/investidor/manifestacoes/{id}', '/management/opportunity-resources-install/organization-country'],
'dependencies' => ['Existing organizations, memberships, audit_events and investment workspace', 'Stable effective key/configuration and authenticated installation actor with verified email and recent completed MFA'],
'master_data' => ['required_for_ddl_or_enable' => false, 'active_organizations' => $backup['source_installations']['organization_count'], 'active_memberships' => $backup['source_installations']['membership_count'], 'required_for_master_reuse' => ['Existing legitimate organization identity/UUID/provenance', 'Authorized nondeleted membership linking actual user and organization, with role admin/manager/officer to edit or viewer to consult', 'Incorporation country and its reference; explicit authorized copy when requested'],
'can_follow_later' => ['Country/reference via PUT /investidor/organizations/{id}/country by an existing representative', 'Explicit company country reuse via POST /investidor/companies/{id}/organization-country', 'Private company declarations do not create master organizations or memberships'],
'not_implemented_in_this_scope' => ['General creation/onboarding of real master organizations and representation approval; no such public/admin CRUD endpoint was found. Requires a separately authorized data/bootstrap operation or completion of that flow.'], 'invented_or_assigned' => 0],
'installer_eligibility_counts_read_only' => $backup['installer_eligibility_counts'], 'effective_configuration_read_only' => $backup['runtime'], 'active_origin_configured' => config('app.url'),
'other_installations_required' => [], 'cold_qa_new_columns' => 2, 'cold_qa_new_tables' => 0, 'cold_qa_new_accounts_or_organizations' => 0,
'exclusions' => ['Opportunity workflow/Response and modular offers', 'SLA/calendars/real appointments', '030000/040000/190000 installation or investor path activation', 'Cartographic imports/layer publication', 'Legacy expansion/public disclosure/calculation activation', 'Full accessibility/screen reader/real devices', 'QA identities/data/private documents/configuration'],
'qa_browser_receipts' => $receipts, 'preserved_acceptance' => ['A/B internal QA', 'C37 QA18 authentication'],
'backup' => ['at' => $backup['verified_at'], 'database' => $backup['target']['database'], 'port' => (int) $backup['target']['port'], 'code_hash' => $backup['code_hash'], 'production_manifest_sha256' => $backup['production_manifest_sha256'], 'read_only' => true, 'restored_target' => $backup['restored_target'], 'tables' => count($backup['tables']), 'sequences' => count($backup['sequences']), 'sequences_verified' => true, 'files_and_runtime_assets' => $backup['file_count'], 'missing_files' => count($backup['missing_files']), 'dump_sha256' => $backup['dump_sha256'], 'private_archive_sha256' => $backup['files_sha256'], 'mfa_envelopes_recovered' => $backup['original_mfa_envelopes_recovered'], 'legacy_profile_controller_verified' => true, 'disable_preserves_data' => true],
'table_reconciliation' => ['active_restored' => count($backup['tables']), 'qa' => count($schema['inventories']['qa_current']['tables']), 'additional_qa_tables' => $schema['additional_qa_tables'], 'missing_tables' => []],
'affected_validation' => ['country_tests' => $countryUnit, 'phpstan_changed_sources' => $countryStan, 'production_browser_checks' => $productionBrowser['checks']],
'functional_qa_complete_for_included_scope' => true, 'candidate_revision_fixed' => true, 'production_bundle_prepared' => true, 'activation_ready' => true, 'activation_authorized' => false,
'installation_active' => false, 'country_flag_active' => false, 'active_writes' => 0,
'before_activation' => ['Separate explicit approval for the reviewed delivery revision; nothing active was applied', 'Recheck exact candidate fingerprint, production assets, target/schema and evidence freshness (24h); renew if changed or expired', 'Authenticated existing manager with completed recent MFA reviews GET then POST /management/opportunity-resources-install/organization-country; only missing 050000', 'Enable only PORTAL_ORGANIZATION_COUNTRY_ENABLED and switch the verified production manifest after immutable assets are staged; preserve current unrelated flags and stable key', 'No master organizations/representations supplied or invented; controlled empty state remains until authorized real master data is provided', 'No dependency on closure of the 3386 other open requirements'],
'reversal' => ['Disable PORTAL_ORGANIZATION_COUNTRY_ENABLED and refresh only the intended runtime configuration', 'Restore verified previously loaded build if needed', 'Keep 050000 columns, values/provenance, submissions and audit; never run migration down/key rotation/MFA disable', 'If data recovery is needed, validate the isolated restored clone before any separately authorized active restoration']];
file_put_contents($out.'/manifesto-candidata.json', json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
echo json_encode(['candidate' => $manifest['candidate_id'], 'code_hash' => $manifest['code_hash'], 'delivery_revision' => $revision, 'files' => count($files), 'qa_complete_for_scope' => true, 'activation_ready' => true, 'activation_authorized' => false, 'active_writes' => 0]).PHP_EOL;