117 lines
7.1 KiB
Python
117 lines
7.1 KiB
Python
"""Verify the sealed review package and the two targeted audit edits; no database access."""
|
|
from pathlib import Path
|
|
from collections import Counter
|
|
from datetime import datetime, timezone
|
|
import csv
|
|
import hashlib
|
|
import json
|
|
import zipfile
|
|
|
|
csv.field_size_limit(20_000_000)
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
PRIVATE = ROOT / 'storage/app/private/investmoz-v2/portal-audit'
|
|
DOC = ROOT / 'docs/investmoz/v2/auditoria-portal'
|
|
OUT = ROOT / 'outputs/investmoz-country02-https-20261011'
|
|
read = lambda p: json.loads(Path(p).read_text(encoding='utf-8-sig'))
|
|
sha = lambda p: hashlib.sha256(Path(p).read_bytes()).hexdigest()
|
|
packet = read(PRIVATE / 'country-https-results-20261011/csv-edits.json')
|
|
csv_results = []
|
|
for edit in packet['files']:
|
|
file = DOC / edit['filename']
|
|
rows = list(csv.reader(file.open(encoding='utf-8-sig', newline='')))
|
|
assert len(rows) == len(edit['rows'])
|
|
patched = {p['row']: p['values'] for p in edit['patches']}
|
|
changed_ids = []
|
|
for i, row in enumerate(rows):
|
|
expected = list(edit['rows'][i])
|
|
for field, value in patched.get(i, {}).items():
|
|
expected[rows[0].index(field)] = value
|
|
assert row == expected, (edit['filename'], i)
|
|
if i in patched:
|
|
changed_ids.append(row[rows[0].index('ID')])
|
|
assert set(changed_ids) == {'AUD-COUNTRY-02', 'AUD-OPS-01'}
|
|
csv_results.append({'file': edit['filename'], 'changed_ids': changed_ids,
|
|
'other_cells_and_source_references_preserved': True,
|
|
'sha256': sha(file)})
|
|
requirements = list(csv.DictReader((DOC / 'matriz-requisitos.csv').open(encoding='utf-8-sig', newline='')))
|
|
assert len(requirements) == len({r['ID'] for r in requirements}) == 3393
|
|
assert sum(int(r['Quantidade de linhas de origem']) for r in requirements) == 6845
|
|
|
|
manifest = read(OUT / 'manifesto-candidata.json')
|
|
envelope = read(OUT / 'manifesto-pacote.json')
|
|
assert sha(OUT / 'manifesto-candidata.json') == envelope['manifesto_candidata_sha256']
|
|
assert sha(OUT / envelope['archive']) == envelope['archive_sha256']
|
|
with zipfile.ZipFile(OUT / envelope['archive']) as archive:
|
|
assert len(archive.namelist()) == len(set(archive.namelist())) == envelope['archive_entries'] == 200
|
|
assert set(archive.namelist()) == set(envelope['verified_members_sha256'])
|
|
for name, digest in envelope['verified_members_sha256'].items():
|
|
assert hashlib.sha256(archive.read(name)).hexdigest() == digest
|
|
assert not any(p in {'.env', 'vendor', 'node_modules', 'database.dump'} for p in Path(name).parts)
|
|
assert not name.endswith('-key.pem')
|
|
revision = hashlib.sha256(json.dumps(manifest['revision_input'], sort_keys=True, separators=(',', ':')).encode()).hexdigest()
|
|
assert revision == manifest['delivery_revision']
|
|
for name, digest in manifest['deployment_files_sha256'].items():
|
|
assert sha(OUT / name) == digest
|
|
source = Path(read(PRIVATE / 'country-https-latest.json')['source'])
|
|
for name, digest in manifest['files'].items():
|
|
assert sha(source / name) == digest
|
|
stage = read(PRIVATE / 'country-https-production-stage-latest.json')
|
|
for name, digest in stage['inputs'].items():
|
|
assert sha(source / name) == digest
|
|
for name, digest in stage['assets'].items():
|
|
assert sha(Path(stage['build_directory']) / name) == digest
|
|
for name, digest in stage['active_assets'].items():
|
|
assert sha(ROOT / 'public/build' / name) == digest
|
|
baseline = read(PRIVATE / 'country-c110-source-latest.json')
|
|
for name, digest in baseline['baseline_live_sources'].items():
|
|
assert sha(ROOT / name) == digest, name
|
|
active_config = read(OUT / 'configuracao-ativa-leitura.json')
|
|
for name in ['active_vhost', 'apache_config', 'ssl_include']:
|
|
assert sha(active_config[name]['path']) == active_config[name]['sha256']
|
|
assert sha(ROOT / 'public/build/manifest.json') == active_config['active_manifest_sha256']
|
|
for directory in ['investmoz-country02-candidate-20261011', 'investmoz-country02-c110-20261011']:
|
|
previous = ROOT / 'outputs' / directory
|
|
sealed = read(previous / 'manifesto-pacote.json')
|
|
assert sha(previous / sealed['archive']) == sealed['archive_sha256']
|
|
assert sha(previous / 'manifesto-candidata.json') == sealed['manifesto_candidata_sha256']
|
|
|
|
backup = read(read(PRIVATE / 'country-https-backup-latest.json')['path'])
|
|
assert backup['code_hash'] == manifest['code_hash']
|
|
assert sha(backup['dump_path']) == backup['dump_sha256']
|
|
assert sha(backup['files_path']) == backup['files_sha256']
|
|
for key in ['restore_verified', 'files_verified', 'sequences_verified', 'compatibility_verified', 'reversal_verified', 'qa_passed']:
|
|
assert backup[key] is True
|
|
with zipfile.ZipFile(backup['files_path']) as archive:
|
|
assert archive.read('runtime/.env') == (ROOT / '.env').read_bytes()
|
|
runtime = json.loads(archive.read('runtime/effective-runtime.json'))
|
|
assert runtime['config_cached'] == (ROOT / 'bootstrap/cache/config.php').is_file()
|
|
age = (datetime.now(timezone.utc) - datetime.fromisoformat(backup['verified_at'])).total_seconds()
|
|
assert 0 <= age <= 86400
|
|
browser = read(OUT / 'chromium-https.json')
|
|
sql = read(OUT / 'persistencia-qa.json')
|
|
quality = read(OUT / 'validacao-qa.json')
|
|
assert browser['result'] == sql['result'] == 'passed'
|
|
assert browser['code_hash'] == sql['code_hash'] == manifest['code_hash']
|
|
assert all(value is True if isinstance(value, bool) else value['encrypted'] and not value['plainHistory'] and not value['privateKeysPresent'] for value in browser['checks'].values())
|
|
assert browser['javascript_errors'] == browser['mixed_requests'] == []
|
|
assert quality['phpunit_result'] == quality['phpstan_result'] == quality['production_build'] == 'passed'
|
|
assert sql['tables'] == 288 and sql['new_tables'] == 0 and sql['other_packages_installed'] is False
|
|
runtime_final = read(PRIVATE / 'country-https-final-runtime.json')
|
|
assert runtime_final['qa_ca_trusted'] is True and runtime_final['active_ca_trusted'] is False
|
|
assert runtime_final['temporary_qa_listener_ports'] == []
|
|
assert manifest['ready_for_review'] is True and manifest['active_activation_performed'] is False
|
|
assert manifest['active_configuration_changed'] is False and manifest['active_writes'] == 0
|
|
summary = {'result': 'passed', 'at': datetime.now(timezone.utc).isoformat(),
|
|
'requirements': 3393, 'source_occurrences': 6845,
|
|
'states': dict(Counter(r['Estado'] for r in requirements)), 'csv_preservation': csv_results,
|
|
'active_sources_assets_environment_apache_and_previous_packages_unchanged': True,
|
|
'package_members_verified': 200, 'production_assets_verified': len(stage['assets']),
|
|
'code_hash': manifest['code_hash'], 'delivery_revision': revision,
|
|
'package_sha256': envelope['archive_sha256'], 'backup_verified_at': backup['verified_at'],
|
|
'backup_age_minutes': round(age / 60, 1), 'C110_C111_C112': 'QA demonstrated',
|
|
'AB_C37_scope_preserved': True, 'temporary_qa_servers_stopped': True,
|
|
'active_tls_not_installed_or_trusted': True, 'active_writes': 0,
|
|
'activation_requires_reviewed_replacement_revision_and_HTTPS_authorization': True}
|
|
(OUT / 'verificacao-final.json').write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
print(json.dumps(summary, ensure_ascii=False))
|