83 lines
7.3 KiB
Python
83 lines
7.3 KiB
Python
"""Record the responsible user's scoped C37 acceptance, without repeating tests."""
|
||
import csv
|
||
import hashlib
|
||
import json
|
||
from datetime import datetime, timedelta, timezone
|
||
from pathlib import Path
|
||
|
||
csv.field_size_limit(16000000)
|
||
ROOT = Path(__file__).resolve().parent.parent
|
||
DOC = ROOT / 'docs/investmoz/v2/auditoria-portal'
|
||
PRIVATE = ROOT / 'storage/app/private/investmoz-v2/portal-audit'
|
||
OUT = PRIVATE / 'c37-manual-close-20261010'
|
||
OUT.mkdir(exist_ok=True)
|
||
stamp = datetime.now(timezone.utc)
|
||
references = ['c37-qa18-chromium-20261010.json', 'investor-ab-chromium-20261010.json',
|
||
'portal-logout-chromium-20261010.json', 'logout-finalize-20261010/manual-qa18-logout.json']
|
||
proofs = []
|
||
for name in references:
|
||
data = (PRIVATE / name).read_bytes()
|
||
proof = json.loads(data)
|
||
if name.endswith('manual-qa18-logout.json'):
|
||
assert proof['button_and_logout_confirmed_by_user'] and not proof['session_authenticated_after_logout']
|
||
else:
|
||
assert proof['result'] == 'passed' and proof['active_writes'] == 0
|
||
proofs.append({'file': name, 'sha256': hashlib.sha256(data).hexdigest()})
|
||
evidence = {'recorded_at_utc': stamp.isoformat(), 'case': 'C37', 'state': 'closed_scoped_qa18_authentication',
|
||
'manual_confirmation': 'Registar a confirmação manual e encerrar C37 no âmbito da autenticação QA18, ligando-a às provas anteriores de logout e recuperação. Não repetir os ensaios já concluídos.',
|
||
'accepted_by': 'Responsável, mensagem desta conversa em 10/10/2026', 'actor_id': 18,
|
||
'scope': 'Login, MFA, redirecionamento, sessão autenticada, atualização, logout e recuperação/nova sessão QA18',
|
||
'references': proofs, 'tests_repeated': False, 'active_writes': 0,
|
||
'does_not_close': ['A/B acceptance', 'entire audit', 'mobile and full accessibility', 'other profiles', 'active activation']}
|
||
(OUT / 'acceptance.json').write_text(json.dumps(evidence, ensure_ascii=False, indent=2), encoding='utf-8')
|
||
tag = '[C37 fechado QA18 10/10/2026] '
|
||
text = ('Confirmação manual expressa do responsável: C37 encerrado exclusivamente no âmbito da autenticação QA18. '
|
||
'Liga login/MFA/redirecionamento/sessão/F5/nova sessão à prova Chromium QA18 anterior, '
|
||
'ao logout manual18 com invalidação de sessão e à recuperação previamente demonstrada; sem repetir ensaios. '
|
||
'Aceitação sanitizada e hashes: c37-manual-close-20261010/acceptance.json. C85 permanece corrigido QA. '
|
||
'Não encerra A/B, auditoria integral, outros perfis ou ativação ativa.')
|
||
ids = {'AUD-UI-01', 'AUD-GUIDE-01', 'AUD-DASH-01', 'AUD-PROFILE-24', 'AUD-PROFILE-25'}
|
||
files = []
|
||
for filename in ['matriz-requisitos.csv', 'backlog-priorizado.csv']:
|
||
source = DOC / filename
|
||
rows = list(csv.reader(source.open(encoding='utf-8-sig', newline='')))
|
||
h = rows[0]
|
||
patches = []
|
||
for index, row in enumerate(rows[1:], 1):
|
||
old = dict(zip(h, row))
|
||
if old['ID'] not in ids:
|
||
continue
|
||
if filename.startswith('matriz'):
|
||
values = {'Evidência funcional': old['Evidência funcional'] + ' | ' + tag + text,
|
||
'Lacuna': tag + 'C37 não é mais pendência de autenticação QA18; permanecem os demais critérios do requisito. Histórico abaixo preservado e superado apenas neste âmbito. | ' + old['Lacuna'],
|
||
'Interface': old['Interface'] + ' | ' + tag + 'Aceitação manual QA18 encerrada, ligada a logout e recuperação anteriores.',
|
||
'Recuperação': old['Recuperação'] + ' | ' + tag + 'Recuperação/nova sessão aceite pelo responsável; provas anteriores preservadas, não repetidas.',
|
||
'Consolidação': old['Consolidação'] + ' | ' + tag + 'Fecho por caso e âmbito; estado global parcial e referências/versões preservados.'}
|
||
variants = json.loads(old['Critérios e versões por origem (JSON)'])
|
||
for variant in variants:
|
||
variant['aceitacao_c37_qa18_20261010'] = {'case': 'C37', 'estado': 'encerrado no âmbito da autenticação QA18',
|
||
'fonte': 'Confirmação manual expressa do responsável', 'prova': 'c37-manual-close-20261010/acceptance.json',
|
||
'registado_em': stamp.isoformat(), 'ensaios_repetidos': False, 'ativacao': False}
|
||
values['Critérios e versões por origem (JSON)'] = json.dumps(variants, ensure_ascii=False, separators=(',', ':'))
|
||
else:
|
||
values = {'Pendência': tag + 'C37 autenticação QA18 encerrado; não agendar repetição. Demais pendências e histórico: ' + old['Pendência'],
|
||
'Aceitação': old['Aceitação'] + ' | ' + tag + text}
|
||
patches.append({'row': index, 'values': values})
|
||
assert len(rows) == 3394 and len(patches) == len(ids)
|
||
files.append({'filename': filename, 'input_sha256': hashlib.sha256(source.read_bytes()).hexdigest(), 'rows': rows,
|
||
'patches': patches, 'allowed_columns': sorted({field for patch in patches for field in patch['values']}), 'append': []})
|
||
(OUT / 'csv-edits.json').write_text(json.dumps({'files': files}, ensure_ascii=False), encoding='utf-8')
|
||
section = f'''## C37 encerrado — autenticação QA18 — {stamp.astimezone(timezone(timedelta(hours=2))).isoformat()}
|
||
|
||
**Confirmação manual expressa do responsável registada. C37 está encerrado exclusivamente no âmbito da autenticação QA18.** Login → MFA → redirecionamento → sessão autenticada → atualização → logout → nova sessão/recuperação estão ligados às provas anteriores, sem repetir ensaios nem alterar conta, chave ou MFA. O logout manual de 20:17:15 foi confirmado pelo responsável e pelo rastreio: POST302→/, autenticação e estado persistido vazios.
|
||
|
||
Aceitação e hashes dos recibos: `c37-manual-close-20261010/acceptance.json`. Referências: `c37-qa18-chromium-20261010.json`, `logout-finalize-20261010/manual-qa18-logout.json`, `portal-logout-chromium-20261010.json` e recuperação do dossier em `investor-ab-chromium-20261010.json`. A prova QA21 do botão é complementar; a conta18 tem a sua própria confirmação. Horário local UTC+02; datas técnicas dos recibos conservadas em UTC.
|
||
|
||
O fecho **não encerra A/B, auditoria integral, móvel/acessibilidade integral, outros perfis ou ativação ativa**. Os cinco requisitos relacionados continuam parciais pelos seus outros critérios; contagens preservadas: 3393 requisitos/3393 linhas/6845 ocorrências. Menções históricas abaixo a C37/autenticação18 pendente são superadas somente por este fecho. C85 permanece corrigido em QA. Próximo trabalho independente: gravação/recuperação territorial e consistência país–hierarquia por consumidor, países/origem/estatísticas, documentos e workflow, preservando decisões próprias de perfis modulares/SLA.
|
||
'''
|
||
for name in ['relatorio-executivo.md', 'backlog.md', 'casos-reproducao.md', 'plano-ativacao.md']:
|
||
file = DOC / name
|
||
old = file.read_text(encoding='utf-8-sig')
|
||
file.write_text('<!-- c37-manual-close-20261010:begin -->\n' + section + '\n<!-- c37-manual-close-20261010:end -->\n\n' + old, encoding='utf-8')
|
||
print(json.dumps({'case': 'C37', 'state': 'closed_scoped_qa18_authentication', 'requirements_touched': len(ids), 'tests_repeated': False, 'active_writes': 0}))
|