122 lines
12 KiB
Python
122 lines
12 KiB
Python
from pathlib import Path
|
||
import json,hashlib,csv,shutil,zipfile
|
||
from datetime import datetime,timezone
|
||
from collections import Counter
|
||
R=Path(__file__).resolve().parent.parent;P=R/'storage/app/private/investmoz-v2/portal-audit'
|
||
O=R/'outputs/investmoz-workflow-consolidated-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');revision=manifest['revision'][:12]
|
||
preview=load(P/'consolidated-preview-qa.json');holder=load(P/'consolidated-holder-compatibility-qa.json')
|
||
assert preview['result']=='passed' and holder['result']=='passed'
|
||
assert len(preview['screenshots'])==1
|
||
shots=O/'capturas-qa';shots.mkdir(exist_ok=True)
|
||
shot=R/preview['screenshots'][0];assert shot.is_file()
|
||
shutil.copyfile(shot,shots/shot.name)
|
||
public_preview={k:preview[k] for k in ['result','started_at','base','target','browser','checks','active_writes']}
|
||
public_preview['screenshot']='capturas-qa/'+shot.name
|
||
public_preview['test_harness_correction']='First attempted legacy manager14 after initialized pair received403; corrected authorized holder15, no application change. Historical failed attempt retained privately.'
|
||
(O/'preview-qa.json').write_text(json.dumps(public_preview,indent=2,ensure_ascii=False),encoding='utf-8')
|
||
(O/'compatibilidade-titulares-qa.json').write_text(json.dumps(holder,indent=2,ensure_ascii=False),encoding='utf-8')
|
||
# Improve authored prose only, without changing scope, hashes, paths or service proposal.
|
||
spacing={' +159':' + 159','a030000':'a 030000','somente030000':'somente 030000',
|
||
'somente040000':'somente 040000','somente030':'somente 030', 'pedido15→confirmação16':'pedido 15 → confirmação 16',
|
||
'PDF20MiB':'PDF de 20 MiB','Fila4→3→2→1→0':'Fila 4 → 3 → 2 → 1 → 0','repetição0→0':'repetição 0 → 0',
|
||
'CLI256M':'CLI 256M','pico148MiB':'pico de 148 MiB','scanner13310/ClamAV1.5.4':'scanner 13310 / ClamAV 1.5.4',
|
||
'assinaturas11/10':'assinaturas de 11/10','às08:26UTC':'às 08:26 UTC','DBQA':'DB QA','destino3310':'destino 3310',
|
||
'real180s/recuperação210s':'real de 180 s / recuperação de 210 s','nos191':'nos 191',
|
||
'aumento288→295':'aumento 288 → 295','tabelas030000+040000':'tabelas 030000 + 040000',
|
||
'contém181':'contém 181','fixtures.191':'fixtures. 191','ID2':'ID 2','ID13':'ID 13','IDs3/18':'IDs 3/18',
|
||
'legado e190000':'legado e 190000','atuais3310':'atuais 3310','provasLocalService':'provas LocalService',
|
||
'reconciliação191':'reconciliação dos 191 ficheiros','tabelaB3':'tabela B3',
|
||
'→030000→040000':' → 030000 → 040000',
|
||
'→ flags':' → flags','escopo': 'âmbito','SHA-256:':'SHA-256:',
|
||
'Destino':'Destino','050000 não se repete':'050000 não se repete',
|
||
'COUNTRY02 permaneceON':'COUNTRY02 permanece ON','code/bundle':'código/bundle',
|
||
'destino real**':'destino real**','flagsOFF':'flags OFF','COUNTRY02 ON':'COUNTRY02 ON',
|
||
'fila default partilhada':'fila default partilhada','upload20M':'upload 20M','POST24M':'POST 24M',
|
||
'memória256M':'memória 256M','execução180s':'execução 180 s','cadência60s':'cadência 60 s',
|
||
'externo180s':'externo 180 s','lease210s':'lease 210 s','prazo15min':'prazo 15 min',
|
||
'em030000':'em 030000','em040000':'em 040000','050000/190000':'050000/190000',
|
||
'somente030000/040000':'somente 030000/040000','somente030000':'somente 030000',
|
||
'190000 fica':'190000 fica','notificações enfileiradas':'notificações enfileiradas',
|
||
'OFF.050000':'OFF. 050000','revisão/ZIP':'revisão/ZIP',
|
||
'|288/31 |799 |':'| 288 / 31 | 799 |','|295/31 |188 |':'| 295 / 31 | 188 |','|295/31 |191 |':'| 295 / 31 | 191 |',
|
||
'Destino,15:11:50UTC':'Destino, 15:11:50 UTC','anterior,15:11:55UTC':'anterior, 15:11:55 UTC',
|
||
'delta,16:29:27UTC':'delta, 16:29:27 UTC','QA renovada,':'QA renovada, ',
|
||
'+476':' + 476','+312':' + 312','+2TLS':' + 2 TLS','+5Apache':' + 5 Apache',
|
||
'+1env':' + 1 env','+17 código':' + 17 código','+158bundle':' + 158 bundle',
|
||
'+22 código':' + 22 código','+159bundle':' + 159 bundle',',9 envelopes':', 9 envelopes',
|
||
'investment_project,real_estate,land_rights,business_sale,business_partnership,franchise':'investment_project, real_estate, land_rights, business_sale, business_partnership, franchise'}
|
||
for name in ['relatorio-consolidacao.md','procedimento-unico.md','designacoes-b3.md']:
|
||
p=O/name;text=p.read_text(encoding='utf-8')
|
||
for a,b in spacing.items():text=text.replace(a,b)
|
||
p.write_text(text,encoding='utf-8')
|
||
report=O/'relatorio-consolidacao.md'
|
||
report.write_text(report.read_text(encoding='utf-8')+'''\n## Verificações afetadas da consolidação\n\nChromium HTTPS/MFA normal confirmou a prévia040000 com o novo fingerprint/readiness e a dependência030000 com fingerprint/readiness correspondente ao restauro renovado. Interface de instalação renderizada pelo bundle consolidado. Não houve repetição da instalação: a recusa403 ao gestor legado que não integra a dupla QA foi verificada antes da leitura permitida ao titular15. As contas reais clonadas2/13 passaram validateBootstrapHolder, incluindo leitura do envelope MFA normal; zero alterações às contas. [Prévia QA](preview-qa.json), [compatibilidade dos titulares](compatibilidade-titulares-qa.json).\n''',encoding='utf-8')
|
||
block=f'''<!-- consolidated-workflow-qa-20261011 -->
|
||
## Candidata consolidada {revision} — QA, sem ativação
|
||
|
||
[Relatório e bloqueios](../../../../outputs/investmoz-workflow-consolidated-20261011/relatorio-consolidacao.md), [procedimento único](../../../../outputs/investmoz-workflow-consolidated-20261011/procedimento-unico.md) e [manifesto](../../../../outputs/investmoz-workflow-consolidated-20261011/manifesto.json).
|
||
|
||
Delta 117d2d889701 integrado: 22 ficheiros de código + 159 assets (181 no ZIP), referência 98a8e0b70892 preservada. Compilação de produção do delta verificada por bytes; nenhuma alteração de código adicional. Prévia Chromium/MFA 040000 com fingerprint novo e dependência030000 corresponde ao restauro renovado; gestor legado fora da dupla QA recebe403, titular autorizado recebe200. Instalações/funcionalidades válidas não repetidas.
|
||
|
||
LocalService S-1-5-19 demonstrada no clone55441: configuração lida, ClamD13310, quatro scans PDF20MiB/trêsWebP, fila4→0 e repetição0→0, zero recursos novos/falhas e hashes/cifra recuperados; escrita só nas áreas QA autorizadas, negada em código/vendor/config/.env e leitura alheia negada. Tarefa própria removida. Limite180s/lease210s anteriores preservados como prova distinta de utilizador interativo. Não é instalação/prova do destino3310.
|
||
|
||
191 ficheiros reconciliados:22código+159bundle+1env+9documentais, incluindo os4originais do destino com hashes iguais e5ficheiros sintéticos. Backup799 do destino tem âmbito maior; os8documentais exclusivos da QA188 continuam no backup anterior. RestauroQA renovado16:49:42UTC:295tabelas/31seq/191ficheiros/9MFA; renovar o backup/restauro do destino real e associar à revisão antes da intervenção.
|
||
|
||
B3: responsável confirmou nala@tempo.co.mz (**ID2**) e onala@me.com (**ID13**); email/MFA/gestão legada verificados READ ONLY e compatibilidade do envelope validada no clone. IDs3/18 iniciais reconciliados. Designação registada, sem conceder privilégios. Ainda faltam autorização/cerimónia cruzada e contas/organização/tipos/âmbito operacionais. B1/B2: serviços3310, supervisão/limites e ACLs efetivas do destino por autorizar/verificar; RX adicional não neutraliza escrita herdada. Notificações OFF e nova leitura da default imediatamente antes de iniciar worker; parar perante classe desconhecida ou notificação enfileirada.
|
||
|
||
Mesma matriz3401requisitos/7739ocorrências, três evidências complementadas, zero IDs/estados gerais novos. COUNTRY02 ativo e fechos A/B/C37 preservados. Restauração/partilha individual/190000/legado/modulares/ofertas/SLA permanecem fora. Os blocos seguintes mantêm o histórico.
|
||
|
||
<!-- /consolidated-workflow-qa-20261011 -->
|
||
|
||
'''
|
||
for a,b in {**spacing,'dependência030000':'dependência 030000','recebe403':'recebe 403','recebe200':'recebe 200',
|
||
'clone55441':'clone 55441','ClamD13310':'ClamD 13310','fila4→0':'fila 4 → 0','quatro scans PDF20MiB/trêsWebP':'quatro scans PDF de 20 MiB / três WebP',
|
||
'Limite180s/lease210s':'Limite 180 s / lease 210 s','191 ficheiros reconciliados:22código+159bundle+1env+9documentais':'191 ficheiros reconciliados: 22 código + 159 bundle + 1 env + 9 documentais',
|
||
'os4originais':'os 4 originais','e5ficheiros':'e 5 ficheiros','Backup799':'Backup 799','os8documentais':'os 8 documentais',
|
||
'QA188':'QA 188','RestauroQA renovado16:49:42UTC:295tabelas/31seq/191ficheiros/9MFA':'Restauro QA renovado 16:49:42 UTC: 295 tabelas / 31 sequências / 191 ficheiros / 9 MFA',
|
||
'IDs3/18':'IDs 3/18','serviços3310':'serviços 3310','matriz3401requisitos/7739ocorrências':'matriz: 3401 requisitos / 7739 ocorrências'}.items():block=block.replace(a,b)
|
||
for name in ['backlog.md','relatorio-executivo.md','plano-ativacao.md','workflow-criterios-saida-20261011.md']:
|
||
p=R/'docs/investmoz/v2/auditoria-portal'/name;old=p.read_text(encoding='utf-8')
|
||
assert '<!-- consolidated-workflow-qa-20261011 -->' not in old
|
||
p.write_text(block+old,encoding='utf-8')
|
||
before=load(P/'consolidated-preservation-before.json');checks={}
|
||
for kind,base in [('fixed_candidate',R/'outputs/investmoz-workflow-upgrade-20261011'),('delta_reference',R/'outputs/investmoz-service-followup-20261011'),('service_plan',R/'outputs/investmoz-workflow-service-plan-20261011')]:
|
||
changed=[key for key,value in before[kind].items() if not (base/key).is_file() or sha(base/key)!=value]
|
||
assert not changed,(kind,changed);checks[kind]={'files':len(before[kind]),'changed':0}
|
||
active=load(P/'service-followup-preservation-before.json')['active_hashes']
|
||
assert all(sha(R/key)==value for key,value in active.items())
|
||
checks['active_monitored_files']={'files':len(active),'changed':0}
|
||
csv.field_size_limit(16777216)
|
||
old=list(csv.reader((P/'consolidated-matrix-before.csv').open(encoding='utf-8-sig',newline='')))
|
||
new=list(csv.reader((R/'docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv').open(encoding='utf-8-sig',newline='')))
|
||
assert len(old)==len(new)==3402 and len({r[0] for r in new[1:]})==3401
|
||
differences=[]
|
||
for a,b in zip(old,new):
|
||
assert len(a)==len(b)
|
||
for c,(x,y) in enumerate(zip(a,b)):
|
||
if x!=y:
|
||
assert old[0][c]=='Evidência funcional' and b[0] in ['AUD-OPS-01','AUD-PROFILE-15','AUD-PROFILE-31']
|
||
differences.append({'id':b[0],'column':old[0][c]})
|
||
assert len(differences)==3
|
||
for key,value in manifest['service_proposal'].items():assert sha(O/key)==value
|
||
assert sha(O/manifest['zip'])==manifest['zip_sha256']
|
||
with zipfile.ZipFile(O/manifest['zip']) as z:
|
||
assert len(z.namelist())==181
|
||
for key,value in manifest['payload'].items(): assert hashlib.sha256(z.read(key)).hexdigest()==value
|
||
for key,value in manifest['unchanged_dependencies'].items(): assert sha(R/key)==value, key
|
||
backup=load(P/'consolidated-backup-restoration-qa.json')
|
||
assert backup['code_manifest']=={key:value for key,value in manifest['payload'].items() if not key.startswith('public/build/')}
|
||
assert backup['production_manifest_sha256']==manifest['production_manifest_sha256']
|
||
result={'result':'passed','verified_at':datetime.now(timezone.utc).isoformat(),'candidate':manifest['revision'],
|
||
'code_revision':manifest['code_revision'],'zip_sha256':manifest['zip_sha256'], 'manifest_sha256':sha(O/'manifesto.json'),
|
||
'preservation':checks,'matrix':{'requirements':3401,'source_occurrences':sum(int(dict(zip(new[0],row))['Quantidade de linhas de origem']) for row in new[1:]),'changes':differences,'new_ids':0,'states_sources_versions_preserved':True},
|
||
'QA_restore_bound_to_exact_candidate_code_and_production_bundle':True,
|
||
'changed_preview_and_holder_compatibility_passed':True,'LocalService_QA_passed':True,
|
||
'destination_account_ids_designated':[2,13], 'active_writes':0,'activation_ready':False,'activation_authorized':False,
|
||
'delivery_files':{p.relative_to(O).as_posix():sha(p) for p in sorted(O.rglob('*')) if p.is_file()}}
|
||
(O/'verificacao-final.json').write_text(json.dumps(result,indent=2,ensure_ascii=False),encoding='utf-8')
|
||
print(json.dumps({k:result[k] for k in ['result','candidate','manifest_sha256','LocalService_QA_passed','active_writes','activation_ready']}))
|