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

60 lines
3.0 KiB
Python

import datetime
import hashlib
import json
from pathlib import Path
import zipfile
ROOT = Path(__file__).resolve().parent.parent
AUDIT = ROOT / 'storage/app/private/investmoz-v2/portal-audit'
OUT = ROOT / 'outputs/investmoz-country02-candidate-20261011'
def read(path):
return json.loads(Path(path).read_text(encoding='utf-8-sig'))
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def bounded(path):
path = Path(path).resolve()
assert path.is_relative_to(ROOT), 'Outside workspace refused'
return path
envelope = read(OUT / 'manifesto-pacote.json')
manifest = read(OUT / 'manifesto-candidata.json')
stage = read(AUDIT / 'country-production-stage-latest.json')
assert sha(OUT / 'manifesto-candidata.json') == envelope['manifesto_candidata_sha256']
assert sha(OUT / envelope['archive']) == envelope['archive_sha256']
assert manifest['code_hash'].startswith('36f7722ce5a5') and manifest['delivery_revision'].startswith('c68ceef9d4a3')
with zipfile.ZipFile(OUT / envelope['archive']) as z:
assert len(z.namelist()) == envelope['archive_entries']
for name, expected in envelope['verified_members_sha256'].items():
assert hashlib.sha256(z.read(name)).hexdigest() == expected, name
for name, expected in manifest['files'].items():
assert sha(bounded(ROOT / name)) == expected, name
for name, expected in manifest['production']['transitive_inputs'].items():
assert sha(bounded(ROOT / name)) == expected, name
for name, expected in manifest['production']['files'].items():
assert sha(bounded(ROOT / 'public/build' / name)) == expected, name
for name, expected in stage['active_assets'].items():
if name != 'manifest.json':
assert sha(bounded(ROOT / 'public/build' / name)) == expected, name
original = AUDIT / 'country-active-20261011_065027/manifest-before.json'
assert sha(original) == manifest['active_manifest_sha256']
receipt = {
'result': 'bundle_available_country_disabled',
'at': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'delivery_revision': manifest['delivery_revision'], 'code_hash': manifest['code_hash'],
'production_manifest_sha256': manifest['production']['manifest_sha256'],
'previous_manifest_sha256': manifest['active_manifest_sha256'],
'preserved_immutable_previous_assets': len(stage['active_assets']) - 1,
'production_files': len(manifest['production']['files']),
'original_manifest_backup': str(original),
'country_flag_enabled': False, 'active_database_writes': 0, 'installer_applied': False,
'archive_members_verified': envelope['archive_entries'],
'receipt_recovery': 'Atomic replacement succeeded at 06:50:27 UTC. Receipt expression failed; all old/new hashes rechecked before recording, no replacement repeated.',
'reversal': 'Disable country and atomically restore manifest-before.json; retain assets, columns, values and audit.',
}
for path in [original.parent / 'bundle-receipt.json', AUDIT / 'country-active-bundle-latest.json']:
path.write_text(json.dumps(receipt, indent=2), encoding='utf-8')
print(json.dumps(receipt))