make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); use App\Services\EditorialReading; use App\Services\VerifiedDocumentBinary; use Illuminate\Support\Facades\DB; use Symfony\Component\HttpFoundation\BinaryFileResponse; $target = DB::selectOne('select current_database() as name,inet_server_port() as port'); if (! app()->environment('testing') || $target->name !== 'simulator_fiscal_delta_20261021_test' || (int) $target->port !== 55441) { throw new RuntimeException('Named isolated QA only'); } $directory = base_path('outputs/legacy-editorial-20261022'); if (! is_dir($directory)) { mkdir($directory, 0700, true); } $identities = json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true, 512, JSON_THROW_ON_ERROR); if (count($identities) !== 28) { throw new RuntimeException('Exact 28-original scope required'); } $label = $argv[1] ?? 'v1'; if (! preg_match('/^[a-z0-9-]{1,32}$/D', $label)) { throw new RuntimeException('Invalid package label'); } $zip = new ZipArchive; $archive = $directory.'/legacy-editorial-private-'.$label.'.zip'; if (is_file($archive)) { throw new RuntimeException('Preserve existing package; choose a reviewed subsequent version rather than overwrite'); } if ($zip->open($archive, ZipArchive::CREATE | ZipArchive::EXCL) !== true) { throw new RuntimeException('Cannot create private package'); } $manifest = ['format' => 'investmoz-legacy-editorial-private-delivery-v1', 'prepared_at' => gmdate(DATE_ATOM), 'destination' => 'teste-investidor.tempo.co.mz', 'publish' => false, 'documents' => [], 'images' => [], 'rules' => ['Transport/import is private and distinct from publication.', 'Resolve target IDs by original SHA256/external identity; no QA user/document/resource IDs are authoritative in the destination.', 'Keep source QA revisions as provenance, never impersonate their actors as destination audit authors.', 'Recheck target scan and existing identity/version; reuse matching originals, never overwrite conflicts.', 'Apply current metadata/edition through authenticated management, creating destination history. No automatic publication.']]; $reading = app(EditorialReading::class); $rows = []; $imageHashes = []; DB::beginTransaction(); DB::statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY'); try { foreach ($identities as $identity) { $doc = DB::table('documents')->where('external_id', $identity['external_id'])->where('sha256', $identity['sha256'])->whereNull('deleted_at')->first(); if (! $doc) { throw new RuntimeException('Missing original identity'); } $resource = DB::table('portal_resources')->where('document_id', $doc->id)->first(); if (! $resource || $resource->published || $doc->data_classification !== 'internal') { throw new RuntimeException('Expected private QA draft'); } $binary = app(VerifiedDocumentBinary::class)->respond($doc); $bytes = $binary instanceof BinaryFileResponse ? file_get_contents($binary->getFile()->getPathname()) : $binary->getContent(); if (hash('sha256', $bytes) !== $identity['sha256']) { throw new RuntimeException('Original changed'); } $file = 'originals/'.$identity['external_id'].'.txt'; $zip->addFromString($file, $bytes); $display = $reading->reading($resource, null, true); $edition = $resource->editorial_content ? json_decode($resource->editorial_content, true, 512, JSON_THROW_ON_ERROR) : null; $imageBinding = null; if ($edition && ! empty($edition['image_resource_id'])) { $imageDoc = DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->where('r.id', $edition['image_resource_id'])->first(['d.*']); if (! $imageDoc) { throw new RuntimeException('Selected image missing'); } $imageBinding = ['sha256' => $imageDoc->sha256, 'source_url' => $imageDoc->original_source]; unset($edition['image_resource_id']); } if ($display['image_url']) { preg_match('~/documentos/(\d+)/view~', $display['image_url'], $match); $imageDoc = $reading->publicResources()->where('r.id', (int) $match[1])->first(['d.*']); $imageBinary = app(VerifiedDocumentBinary::class)->respond($imageDoc); $imageBytes = $imageBinary instanceof BinaryFileResponse ? file_get_contents($imageBinary->getFile()->getPathname()) : $imageBinary->getContent(); if (! isset($imageHashes[$imageDoc->sha256])) { $imageFile = 'images/'.$imageDoc->sha256; $zip->addFromString($imageFile, $imageBytes); $imageHashes[$imageDoc->sha256] = true; $manifest['images'][] = ['file' => $imageFile, 'sha256' => $imageDoc->sha256, 'source_url' => $imageDoc->original_source, 'mode' => 'reuse target matching hash first; import only if absent and authorized']; } } $revisions = DB::table('portal_resource_revisions')->where('resource_id', $resource->id)->orderBy('revision_no')->get(); $historyFile = 'provenance/'.$identity['external_id'].'.json'; $zip->addFromString($historyFile, json_encode(['scope' => 'QA provenance only; IDs and actors are not destination identities', 'resource_snapshot' => $resource, 'revisions' => $revisions], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $metadata = (array) $resource; foreach (['id', 'document_id', 'created_by', 'approved_by', 'last_reviewed_by', 'last_reviewed_at', 'metadata_version', 'document_group_id', 'duplicate_of_resource_id', 'document_identity_key', 'editorial_content', 'created_at', 'updated_at'] as $key) { unset($metadata[$key]); } $manifest['documents'][] = ['external_id' => $identity['external_id'], 'file' => $file, 'sha256' => $identity['sha256'], 'kind' => $identity['kind'], 'metadata' => $metadata, 'qa_metadata_version' => $resource->metadata_version, 'edition' => $edition, 'selected_image' => $imageBinding, 'original_image_reference' => $display['image_source_url'], 'original_image_sha256' => $display['image_expected_sha256'], 'body_image_references' => $display['image_references'], 'history_file' => $historyFile, 'publish' => false, 'version_identity' => 'Legado '.$identity['external_id']]; $rows[] = ['external_id' => $identity['external_id'], 'qa_resource_id' => $resource->id, 'version' => $resource->metadata_version, 'original_sha256' => $doc->sha256, 'private' => ! $resource->published, 'image_available' => (bool) $display['image_url'], 'image_reference' => $display['image_source_url'], 'body_image_references' => count($display['image_references']), 'history_revisions' => $revisions->count()]; } } finally { DB::rollBack(); } $manifest['notice'] = 'The QA proof edition of original post 62413 contains an explicitly marked QA note. Review/correct it in the portal before any publication; no editorial text is silently removed from this package.'; $zip->addFromString('manifest.json', json_encode($manifest, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $zip->close(); $verify = new ZipArchive; if ($verify->open($archive, ZipArchive::CHECKCONS) !== true) { throw new RuntimeException('Archive invalid'); } foreach ($manifest['documents'] as $item) { if (hash('sha256', $verify->getFromName($item['file'])) !== $item['sha256']) { throw new RuntimeException('Archive original mismatch'); } } foreach ($manifest['images'] as $item) { if (hash('sha256', $verify->getFromName($item['file'])) !== $item['sha256']) { throw new RuntimeException('Archive image mismatch'); } } $entries = $verify->numFiles; $verify->close(); $receipt = ['qa_only' => true, 'originals' => count($rows), 'rows' => $rows, 'archive_entries' => $entries, 'archive_sha256' => hash_file('sha256', $archive), 'archive_bytes' => filesize($archive), 'verified_original_hashes' => 28, 'included_image_originals' => count($manifest['images']), 'destination_imported' => false, 'destination_published' => false, 'database_writes' => 0]; file_put_contents($directory.'/private-delivery-'.$label.'-receipt.json', json_encode($receipt, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); echo json_encode(['originals' => count($rows), 'archive_entries' => $entries, 'sha256' => $receipt['archive_sha256'], 'included_images' => count($manifest['images']), 'destination_imported' => false, 'destination_published' => false]);