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

64 lines
5.3 KiB
Python

from pathlib import Path
import hashlib,json,csv,zipfile,shutil,subprocess
from datetime import datetime,timezone
R=Path(__file__).resolve().parent.parent;P=R/'storage/app/private/investmoz-v2/portal-audit';O=R/'outputs/investmoz-service-followup-20261011'
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
before=json.loads((P/'service-followup-preservation-before.json').read_text());checks={}
for kind,base in [('candidate_file_hashes',R/'outputs/investmoz-workflow-upgrade-20261011'),('service_plan_file_hashes',R/'outputs/investmoz-workflow-service-plan-20261011'),('active_hashes',R)]:
changed=[k for k,v in before[kind].items() if not (base/k).is_file() or sha(base/k)!=v];assert not changed
checks[kind]={'file_count':len(before[kind]),'changed_count':0}
csv.field_size_limit(16777216)
old=list(csv.reader((P/'service-followup-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
assert len({r[0] for r in new[1:]})==3401
changed=[]
for i,(a,b) in enumerate(zip(old,new)):
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']
changed.append({'id':b[0],'column':old[0][c]})
assert len(changed)==3
manifest=json.loads((O/'manifesto-delta-qa.json').read_text());z=O/manifest['zip']
assert sha(z)==manifest['zip_sha256']
with zipfile.ZipFile(z) as archive:
assert len(archive.namelist())==165
assert not any('.env' in name or '/private/' in name or 'credentials' in name for name in archive.namelist())
for k,v in manifest['delta_files'].items():assert hashlib.sha256(archive.read(k)).hexdigest()==v
for k,v in manifest['production_assets'].items():assert hashlib.sha256(archive.read('public/build/'+k)).hexdigest()==v
proof=json.loads((O/'evidencias-por-criterio.json').read_text())
images=O/'capturas-qa';images.mkdir(exist_ok=True)
for section in ['pdf_above_2_MiB','image_above_2_MiB','exact_20_MiB','bootstrap']:
for screenshot in proof[section]['screenshots']:
file=R/screenshot
assert file.is_file() and not any(token in file.name for token in ['login','two-factor','password','mfa-code'])
shutil.copyfile(file,images/file.name)
proof[section]['screenshots'][proof[section]['screenshots'].index(screenshot)]='capturas-qa/'+file.name
(O/'evidencias-por-criterio.json').write_text(json.dumps(proof,indent=2,ensure_ascii=False),encoding='utf-8')
# Improve only the new authored text, without touching historical blocks or identifiers.
replacements={'candidata98':'candidata 98','contas15':'contas 15','Conta16':'Conta 16','titular16':'titular 16','Titular16':'Titular 16','sintético15':'sintético 15',
'bootstrap **':'bootstrap **','295tabelas':'295 tabelas','31sequências':'31 sequências','191ficheiros':'191 ficheiros','9MFA':'9 MFA',
'PT3M real':'PT3M real','entre178':'entre 178','e180':' e 180','s; job':' s; job','lease210s':'lease 210 s',
'PDF2,5MiB':'PDF 2,5 MiB','imagem3,3MB':'imagem 3,3 MB','trêsWebP':'três WebP','PHP web20M':'PHP web 20M','POST24M':'POST 24M',
'Fronteira20MiB':'Fronteira 20 MiB','workerCLI128M':'worker CLI 128M','CLI128M':'CLI 128M','comando já previsto256M':'comando já previsto 256M',
'pico148MiB':'pico 148 MiB','vhost20':'vhost 20','deltaQA':'delta QA','MFA legível':'MFA legível','LocalService/':'LocalService / ',
'295tabelas/31sequências/':'295 tabelas / 31 sequências / ','190000 acompanha':'190000 acompanha',
'zero jobs/falhas':'zero jobs/falhas','3401linhas':'3401 linhas','7739ocorrências':'7739 ocorrências',
'alinha\u200br':'alinhar','umjob':'um job','ZeroDDL':'Zero DDL','15min':'15 min','nove envelopesMFA':'nove envelopes MFA',
'285tabelas':'285 tabelas','134.217.728bytes':'134.217.728 bytes','155.189.248bytes':'155.189.248 bytes','20MiB':'20 MiB',
'10MiB':'10 MiB','25MiB':'25 MiB','2MiB':'2 MiB','zeroIDs':'zero IDs','3401requisitos':'3401 requisitos','7739ocorrências':'7739 ocorrências',
'191ficheiros':'191 ficheiros','159assets':'159 assets'}
for filename in ['relatorio.md']:
f=O/filename;t=f.read_text(encoding='utf-8')
for a,b in replacements.items():t=t.replace(a,b)
f.write_text(t,encoding='utf-8')
for filename in ['backlog.md','relatorio-executivo.md','plano-ativacao.md','workflow-criterios-saida-20261011.md']:
f=R/'docs/investmoz/v2/auditoria-portal'/filename;t=f.read_text(encoding='utf-8');end=t.index('<!-- /service-followup-qa-20261011 -->')
block=t[:end]
for a,b in replacements.items():block=block.replace(a,b)
f.write_text(block+t[end:],encoding='utf-8')
result={'result':'passed','at':datetime.now(timezone.utc).isoformat(),'preservation':checks,'matrix_changes':changed,'states_sources_versions_preserved':True,
'fixed_candidate':'98a8e0b70892','separate_QA_delta':manifest['qa_delta_code_revision'],'payload_files':165,'activation_ready':False,'active_writes':0}
(O/'verificacao-final.json').write_text(json.dumps(result,indent=2,ensure_ascii=False),encoding='utf-8')
print(json.dumps({'result':'passed','fixed_candidate':'98a8e0b70892','separate_delta':manifest['qa_delta_code_revision'][:12],'matrix_cells_updated':3,'active_writes':0,'activation_ready':False}))