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

75 lines
5.1 KiB
Python

from pathlib import Path
import hashlib, json
R = Path(__file__).resolve().parent.parent
P = R / 'storage/app/private/investmoz-v2/portal-audit'
load = lambda p: json.loads(p.read_text(encoding='utf-8-sig'))
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
candidate = load(P / 'consolidated-candidate-latest.json')
O = Path(candidate['output'])
manifest = load(O / 'manifesto.json')
assert manifest['revision'] == candidate['revision']
assert sha(O / 'manifesto.json') == candidate['manifest_sha256']
assert sha(O / candidate['zip']) == candidate['zip_sha256'] == manifest['zip_sha256']
assert manifest['code_files'] == 22 and manifest['production_assets'] == 159
for relative, expected in manifest['base_hashes'].items():
path = R / relative
assert (sha(path) if path.is_file() else None) == expected, relative
for relative, expected in manifest['unchanged_dependencies'].items():
assert sha(R / relative) == expected, relative
snapshot = load(P / 'workflow-execution-services-latest.json')
assert snapshot['active_services_changes'] == snapshot['active_acl_changes'] == 0
scope = {
'code_revision': manifest['code_revision'],
'active_base_hashes': manifest['base_hashes'],
'production_manifest_sha256': manifest['production_manifest_sha256'],
'candidate': candidate,
'resources_fingerprint': manifest['resources_fingerprint'],
'profile_fingerprint': manifest['profile_fingerprint'],
'services_snapshot': snapshot,
}
(P / 'workflow-execution-backup-scope.json').write_text(json.dumps(scope, indent=2), encoding='utf-8')
source = (R / 'tools/portal-workflow-upgrade-target-backup.php').read_text(encoding='utf-8')
source = source.replace('workflow-upgrade-target-backup-failure-20261011.json', 'workflow-execution-target-backup-failure.json')
source = source.replace('workflow-upgrade-code-20261011.json', 'workflow-execution-backup-scope.json')
source = source.replace("$c['driver'] === 'pgsql' && empty($c['url'])", "$c['driver'] === 'pgsql' && empty($c['url']) && in_array($c['host'], ['127.0.0.1','localhost'], true)")
source = source.replace("'workflow_target_'", "'workflow_consolidated_target_'").replace('^workflow_target_', '^workflow_consolidated_target_')
source = source.replace('workflow-target-backups/', 'workflow-execution-target-backups/')
source = source.replace('workflow-upgrade-target-backup-link-20261011.json', 'workflow-execution-target-backup-link.json')
source = source.replace('workflow-upgrade-target-backup-20261011.json', 'workflow-execution-target-backup.json')
needle = '$zip->close();'
addition = '''// Service assets are copied from an independent READ ONLY OS snapshot.
$services=$scope['services_snapshot'];
foreach($services['files'] as $serviceFile){
$name='services/'.$serviceFile['entry'];
$servicePath=$services['directory'].'/'.str_replace('\\\\','/',$serviceFile['entry']);
throw_unless(is_file($servicePath)&&hash_file('sha256',$servicePath)===$serviceFile['sha256'],RuntimeException::class,'Private service snapshot differs.');
if($serviceFile['source']!==null){throw_unless(is_file($serviceFile['source'])&&hash_file('sha256',$serviceFile['source'])===$serviceFile['sha256'],RuntimeException::class,'Service recovery source changed after snapshot.');}
$zip->addFile($servicePath,$name);$fileHashes[$name]=$serviceFile['sha256'];
}
$servicesMetadata=$services['directory'].'/snapshot.json';
$zip->addFile($servicesMetadata,'services/snapshot.json');$fileHashes['services/snapshot.json']=hash_file('sha256',$servicesMetadata);
'''
assert source.count(needle) == 1
source = source.replace(needle, addition + needle)
needle = "$proof['scope']='Read-only backup"
position = source.index(needle)
addition = '''$proof['candidate_revision']=$scope['candidate']['revision'];
$proof['candidate_zip_sha256']=$scope['candidate']['zip_sha256'];
$proof['candidate_manifest_sha256']=$scope['candidate']['manifest_sha256'];
$proof['resources_fingerprint']=$scope['resources_fingerprint'];$proof['profile_fingerprint']=$scope['profile_fingerprint'];
$proof['services_snapshot_at']=$services['at'];
$proof['service_asset_count']=count($services['files'])+1;
$proof['service_task_export_count']=count(array_filter($services['tasks'],fn($task)=>$task['exists']));
$proof['ACL_metadata_exported']=$services['acl_objects'];$proof['ACL_metadata_roundtrip']=$services['acl_metadata_roundtrip'];
$proof['ACL_restore_applied_on_destination']=false;
$proof['ACL_scope']=$services['acl_scope'];
$proof['signature_file_count']=$services['signature_files'];
$proof['source_files_stable_at_snapshot_completion']=true;
$proof['no_new_active_accounts_or_grants']=true;
'''
source = source[:position] + addition + source[position:]
source = source.replace("'files' => count($fileHashes),", "'files' => count($fileHashes), 'sequences' => count($sequences), 'MFA_readable' => $mfaReadable, 'originals' => count($documents), 'candidate' => substr($scope['candidate']['revision'],0,12),")
(R / 'tools/portal-workflow-execution-target-backup.php').write_text(source, encoding='utf-8')
print(json.dumps({'result': 'renewal_prepared', 'candidate': manifest['revision'][:12], 'code_revision': manifest['code_revision'][:12], 'service_assets': len(snapshot['files']) + 1, 'active_writes': 0}))