Files
Investidor-V2/tools/portal-onboarding-release-backup-prepare.py
T
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

61 lines
4.3 KiB
Python

"""Prepare a read-only destination backup and an isolated restore for the fixed delta."""
from pathlib import Path
import hashlib, json, zipfile
R = Path(__file__).resolve().parent.parent
P = R / 'storage/app/private/investmoz-v2/portal-audit'
O = R / 'outputs/investmoz-operational-onboarding-20261011'
load = lambda p: json.loads(p.read_text(encoding='utf-8-sig'))
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
manifest = load(O / 'manifesto.json')
assert manifest['delta_sha256'].startswith('41a5ce778932')
archive = O / manifest['package']
assert sha(archive) == manifest['package_sha256']
expected = {x['path']: x['after_sha256'] for x in manifest['files']}
expected.update({x['path']: x['sha256'] for x in manifest['assets']})
with zipfile.ZipFile(archive) as z:
assert len(z.namelist()) == len(set(z.namelist())) == len(expected)
assert set(z.namelist()) == set(expected)
for name, value in expected.items():
assert hashlib.sha256(z.read(name)).hexdigest() == value
baseline = {x['path']: x['before_sha256'] for x in manifest['files']}
for relative, value in baseline.items():
assert (sha(R / relative) if (R / relative).is_file() else None) == value
scope = {'code_revision': manifest['delta_sha256'], 'active_base_hashes': baseline,
'production_manifest_sha256': manifest['production_manifest_sha256'],
'candidate': {'revision': manifest['delta_sha256'], 'zip_sha256': sha(archive),
'manifest_sha256': sha(O / 'manifesto.json')}}
(P / 'onboarding-release-backup-scope.json').write_text(json.dumps(scope, indent=2), encoding='utf-8')
source = (R / 'tools/portal-workflow-execution-target-backup.php').read_text(encoding='utf-8')
source = source.replace('workflow-execution', 'onboarding-release')
source = source.replace('workflow_consolidated_target_', 'onboarding_release_target_')
source = source.replace("['2026_10_10_050000_extend_organization_country']", "['2026_10_09_030000_extend_opportunity_resources','2026_10_10_040000_create_portal_profile_authorization','2026_10_10_050000_extend_organization_country']")
source = source.replace("['app','config','routes','bootstrap']", "['app','config','routes','bootstrap','resources']")
source = source.replace("['composer.json','composer.lock','package.json','package-lock.json']", "['composer.json','composer.lock','package.json','package-lock.json','artisan','public/index.php']")
start = source.index('// Service assets are copied from an independent READ ONLY OS snapshot.')
end = source.index('$zip->close();', start)
source = source[:start] + "// Services are unchanged by this delta; their preceding recovery archive is retained.\n" + source[end:]
start = source.index("$proof['resources_fingerprint']")
end = source.index("$proof['source_files_stable_at_snapshot_completion']", start)
source = source[:start] + source[end:]
source = source.replace("$proof['authenticated_installation_preview_still_required']=true;", """$proof['authenticated_installation_preview_still_required']=false;
$proof['no_migration_required']=true;
$proof['no_service_change_required']=true;
$proof['valid_until']=gmdate('c', time()+86400);
$proof['services_scope']='No service, certificate, PHP limit, worker, DLL or ACL change in this delta';
$proof['active_file_stability_rechecked']=true;
foreach ($fileHashes as $entry => $value) {
if (str_starts_with($entry,'active-code/')) $file=$root.'/'.substr($entry,12);
elseif (str_starts_with($entry,'runtime/active-build/')) $file=$root.'/public/build/'.substr($entry,21);
elseif (str_starts_with($entry,'private/')) $file=$root.'/storage/app/private/'.substr($entry,8);
else continue;
throw_unless(is_file($file) && hash_file('sha256',$file)===$value,RuntimeException::class,'Source file changed during snapshot.');
}
throw_unless(count($tables)===295 && $installationState['country_flag'],RuntimeException::class,'Post-installation baseline differs.');
""")
# The old immutable operation was a migration preflight; this release has no migrations.
source = source.replace("$proof['activation_ready']=false;", "$proof['activation_ready']=false;")
(R / 'tools/portal-onboarding-release-target-backup.php').write_text(source, encoding='utf-8')
print(json.dumps({'result': 'prepared', 'delta': manifest['delta_sha256'][:12], 'payload': len(expected),
'active_writes': 0, 'restore_port': 55441, 'services_changes': 0}))