246 lines
25 KiB
Python
246 lines
25 KiB
Python
"""Record verified destination results; no SQL, credential extraction or CSV authoring."""
|
|
from pathlib import Path
|
|
import csv
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
from collections import Counter
|
|
from datetime import datetime, timezone
|
|
|
|
csv.field_size_limit(10_000_000)
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
PRIVATE = ROOT / 'storage/app/private/investmoz-v2/portal-audit'
|
|
OUT = ROOT / 'outputs/investmoz-workflow-activation-20261011'
|
|
DOCS = ROOT / 'docs/investmoz/v2/auditoria-portal'
|
|
CANDIDATE = ROOT / 'outputs/investmoz-workflow-consolidated-20261011'
|
|
REV = '41caea0f900fe0705e84e065a65f9534ff3a585ee34098f860666f522875a3a5'
|
|
ZIP_HASH = '1d6dece89817459f012909f309f688e85e40752e845469855b2dce101879c102'
|
|
MANIFEST_HASH = '092ea57b5eeecef8ae1c44f4c1a8dd6c95d63af5e4448524c46a9e251b1d9b63'
|
|
|
|
def read(name):
|
|
return json.loads((PRIVATE / name).read_text(encoding='utf-8-sig'))
|
|
|
|
def write(path, value):
|
|
path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
|
|
|
|
def digest(path):
|
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
|
|
def rows():
|
|
with (DOCS / 'matriz-requisitos.csv').open(encoding='utf-8-sig', newline='') as f:
|
|
return list(csv.reader(f))
|
|
|
|
mode = sys.argv[1] if len(sys.argv) > 1 else 'prepare'
|
|
assert mode in ('prepare', 'finalize')
|
|
assert digest(CANDIDATE / 'investmoz-workflow-41caea0f900f.zip') == ZIP_HASH
|
|
assert digest(CANDIDATE / 'manifesto.json') == MANIFEST_HASH
|
|
schema = read('workflow-activation-bootstrap-verified.json')
|
|
web = read('workflow-activation-web-proof.json')
|
|
browser = read('workflow-activation-browser-completed-proof.json')
|
|
prior_browser = read('workflow-activation-browser-before-controller-recovery.json')
|
|
services = read('workflow-activation-services-resumed.json')
|
|
backup = read('workflow-execution-target-backup.json')
|
|
queue = read('workflow-execution-active-queue.json')
|
|
ls = json.loads((ROOT / 'storage/logs/workflow-localservice-preflight.json').read_text())
|
|
assert schema['result'] == web['result'] == ls['result'] == 'passed'
|
|
assert schema['revision'] == web['revision'] == browser['revision'] == services['revision'] == REV
|
|
assert schema['superuser_pair'] == dict(id=1, first_user_id=13, second_user_id=2, approved_by=2, version=1)
|
|
assert schema['sequences_compared'] == 31 and schema['new_sequences'] == 0
|
|
assert browser['criteria']['second_holder_confirmed_with_own_MFA']
|
|
assert browser['criteria']['first_holder_cannot_confirm']
|
|
assert services['worker_enabled'] and services['worker_first_run_result'] == 0
|
|
assert queue['pending_by_class'] == [] and queue['failed_jobs'] == 0
|
|
assert not queue['effective_notifications_enabled'] and queue['configured_notification_recipient_count'] == 0
|
|
assert not schema['operational_flags_enabled'] and schema['COUNTRY02_enabled']
|
|
assert backup['restore_verified'] and backup['files_verified'] and backup['file_count'] == 867
|
|
OUT.mkdir(exist_ok=True)
|
|
|
|
if mode == 'prepare':
|
|
evidence = dict(
|
|
at=schema['at'], revision=REV, target='https://portal-investidor.test / investemoz:5432',
|
|
technical_execution='completed', operational_flows='disabled_pending_designation',
|
|
package=dict(sha256=ZIP_HASH, manifest_sha256=MANIFEST_HASH, code_files=22, build_assets=159),
|
|
backup=dict(verified_at=backup['verified_at'], source_database='investemoz', source_port=5432,
|
|
restored_target=backup['restored_target'], tables_before=288, sequences=31,
|
|
files=867, original_files=4, restore_and_bytes_verified=True,
|
|
Windows_DACL_restore_applied=False),
|
|
destination_schema=schema,
|
|
scanner_and_permissions=ls,
|
|
worker=dict(principal='S-1-5-19', enabled=True, first_run_result=0,
|
|
queue='default', interval_seconds=60, execution_limit_seconds=180,
|
|
lease_seconds=210, memory='256M', commands=services['commands'],
|
|
actual_documentary_jobs_processed=0,
|
|
actual_documentary_pipeline='pending_legitimate_activity'),
|
|
browser=dict(criteria=browser['criteria'], holder_order=browser['holder_order'],
|
|
navigation=prior_browser['navigation'] + browser['navigation'],
|
|
cookie_attributes=browser['cookie_attributes'],
|
|
secure_context=True, TLS_bypass=False,
|
|
mixed_content=browser['mixed'], application_page_errors=browser['errors'],
|
|
loaded_asset_count=len(browser['assets']), loaded_assets_match_candidate=True,
|
|
credentials_or_codes_recorded=False),
|
|
web=web,
|
|
final_queue=dict(at=queue['at'], pending_by_class=[], failed_jobs=0,
|
|
external_notifications_enabled=False, configured_recipients=0),
|
|
qa_evidence_reused=['outputs/investmoz-workflow-consolidated-20261011/relatorio-consolidacao.md',
|
|
'outputs/investmoz-service-followup-20261011/relatorio.md'],
|
|
excluded=['190000', '050000 reapplication', 'operational role grants', 'organizations or representations',
|
|
'cartography or library imports', 'publications', 'individual sharing', 'restoration',
|
|
'experimental modules and offers', 'SLA'],
|
|
reversal='Containment only; preserve HTTPS, COUNTRY02, schema, data and history. Full restore requires separate decision.'
|
|
)
|
|
assert evidence['browser']['mixed_content'] == [] and evidence['browser']['application_page_errors'] == []
|
|
write(OUT / 'evidencias-destino.json', evidence)
|
|
report = f'''# Resultado técnico da intervenção autorizada
|
|
|
|
**Candidata 41caea0f900f disponibilizada no destino. B1/B2, 030000 → 040000 e bootstrap cruzado concluídos. Fluxos operacionais desabilitados. COUNTRY02 preservado ativo.** Verificação final: {schema['at']}.
|
|
|
|
Código 117d2d889701 e pacote imutáveis: 22 ficheiros de código / 159 assets. ZIP SHA-256 `{ZIP_HASH}`. Manifesto SHA-256 `{MANIFEST_HASH}`. Nenhuma alteração adicional ao produto nem recompilação nesta execução. Os ajustes efetuados nos controladores de ensaio não integram o payload.
|
|
|
|
## Resultado por ação
|
|
|
|
| Ação | Resultado efetivo no destino | Evidência / limite |
|
|
| --- | --- | --- |
|
|
| Backup/restauro | Backup da base real renovado às 17:12:20 UTC, fisicamente restaurado e comparado no clone 55441. 288 tabelas, 31 sequências, 867 ficheiros e 4 originais | Válido antes das ações HTTP. O restauro ocorreu no clone, sem substituir a base ativa. Metadados de ACL/tarefas recuperados; DACLs restauradas não foram aplicadas no Windows |
|
|
| Código/bundle | 181 ficheiros correspondem ao manifesto fixo; .env, dependências, chave/cifra, TLS e cookie preservados | Recursos realmente carregados pelo Chromium também conferidos por hash |
|
|
| B1 ClamD | ClamAV 1.5.4 x64, 127.0.0.1:3310, LocalService, assinaturas oficiais 28150 de 11/10/2026 | Atualização e recarga reais; scan limpo e malware detetado em memória. Nenhuma importação/publicação |
|
|
| B2 permissões | Leitura da configuração e dos 4 originais, acesso ao scanner e escrita nas áreas autorizadas | Sob LocalService: escrita recusada em código/vendor/config/.env e leitura recusada em controlos privados alheios. Outros titulares/owners preservados |
|
|
| B2 PHP/HTTPS | Apache PHP 8.5.11, upload 20M / POST 24M / memória 256M / execução 180s; GD/WebP presentes | Chromium com certificado reconhecido, sem ignorar TLS. Upload temporário de 3 MiB e 20 MiB aceite; 21 MiB recusado por PHP com 422; nova tentativa 3 MiB aceite. Nenhum registo de utilizador criado |
|
|
| Apache/vhosts | Configuração validada e recarga graciosa observada; HTTPS do portal 200, HTTP → HTTPS 308, localhost HTTP 200 | Controlo Laragon não recarregou a instância iniciada fora dele. O responsável autorizou expressamente o mecanismo próprio de recarga graciosa; nenhum término forçado |
|
|
| 030000 | Aplicada uma vez pela conta 2, pela interface autenticada | 3 tabelas e 1 coluna. Auditoria `opportunity_resources_installed` |
|
|
| 040000 | Aplicada uma vez pela conta 13, após 030000, pela interface autenticada | 4 tabelas e 4 colunas. Auditoria `install`. Prévias/backup/fingerprints correspondiam; sem migrate geral |
|
|
| Worker | LocalService, fila default, cadência 60s, IgnoreNew, PT3M, lease 210s, memória 256M; primeira execução 0 | Fila relida imediatamente antes: vazia, destinatários 0, notificações OFF. Nenhum job ativo consumido. O ensaio completo documental e a recuperação após interrupção permanecem provas distintas do clone |
|
|
| Bootstrap | Pedido pela conta 13; confirmação pela conta 2 com sessão/MFA próprios; uma dupla versão 1 | Prévia do primeiro titular não permite confirmar. Interface apresentou o sucesso. Pedido consumido e três auditorias próprias, sem novo utilizador/grant operacional |
|
|
|
|
[Evidências sanitizadas por critério](evidencias-destino.json). [Procedimento executado e contenção](procedimento-executado.md). [Designações operacionais pendentes](designacoes-operacionais.md). [Manifesto de execução](manifesto-execucao.json).
|
|
|
|
## Preservação e correspondência da base
|
|
|
|
Resultado aditivo: **288 → 291 → 295 tabelas, 5 colunas, zero novas sequências**. As 288 tabelas anteriores foram comparadas com o restauro: 283 sem alteração de dados, cache/sessões com mudanças normais de autenticação e migrations/audit_events com apenas acréscimos autorizados. As 31 sequências foram conferidas; só a sequência de migrations avançou pelas duas instalações. Os 4 originais e os 2 envelopes MFA permanecem iguais por bytes.
|
|
|
|
Mantidos 13 utilizadores, 0 organizações, 0 representações/memberships, 4 documentos e 6 oportunidades. Acrescentados apenas o schema autorizado, um pedido de segurança consumido, uma dupla de titulares e cinco eventos de auditoria. 050000 não foi reaplicada; 190000 permanece ausente. Fila final: 0 jobs / 0 failed_jobs. Não se registaram credenciais, códigos ou valores de cookies nas evidências.
|
|
|
|
## Pendências que condicionam a utilização operacional
|
|
|
|
1. Designar Promotores, Validadores e Publicadores em contas existentes, com organização/representação legítima, tipos, âmbito e responsabilidade. Os Superutilizadores 2/13 não recebem esses papéis automaticamente nem leitura universal de anexos.
|
|
2. Executar a primeira atividade documental legítima quando houver atores/âmbitos: envio → fila → scan → derivadas → recuperação autorizada. A recuperação após falha e ausência de duplicações já foram demonstradas no clone; não atribuir essa prova ao destino vazio nem inserir dados fictícios no ativo.
|
|
3. COUNTRY02 continua instalado/ON. A gravação real do país mestre permanece dependente de uma organização legítima e de representação autorizada. A falta dessas entidades não impediu a instalação técnica.
|
|
4. Restauração e partilha individual continuam desabilitadas. 190000, cartografia/acervo, legado, ofertas, competências modulares e SLA não foram ativados. Dispositivos reais/acessibilidade integral mantêm os critérios próprios.
|
|
|
|
Esta intervenção não reabre nem repete A/B, C37 ou os percursos QA sem alteração relevante. Não declara a auditoria global nem a Gestão de Oportunidades operacionais concluídas. Mantém cinco fases/19 etapas e as decisões aprovadas. As propostas e relatórios anteriores permanecem referências históricas.
|
|
|
|
## Ocorrências técnicas durante a execução
|
|
|
|
O controlador antigo não lia o payload DOM do Inertia 3 e perdeu o controlo do primeiro Chromium. Foi corrigida a leitura do controlador de ensaio, sem mudança no produto. 030000 já instalada foi recuperada por ledger/auditoria, sem repetição. A nova sessão foi identificada efetivamente como conta 13 e aproveitada para 040000/pedido; a conta 2 confirmou separadamente. Um comando JSON com BOM interrompeu apenas a continuação do controlador; o comando foi normalizado e a mesma sessão recuperada, sem repetir login ou instalação. Esses erros de instrumentação não foram classificados como falhas da autenticação do portal.
|
|
|
|
## Reversão
|
|
|
|
Contenção preserva HTTPS/cookie, chave/cifra, COUNTRY02, originais, colunas e histórico. Desabilitar apenas a supervisão/fluxos deste pacote pelos controlos próprios, conservando jobs/quarentena para diagnóstico. Existem o backup pré-intervenção de 867 ficheiros, suplemento de 10 ficheiros e exportações das ACLs exatamente afetadas (21 árvores e 27 raízes/owners). Não repor leitura excessiva de LocalService nem regredir assinaturas válidas.
|
|
|
|
Depois do bootstrap não executar down/drop nem regressar automaticamente ao código com cerimónia antiga. Não executar key:generate, purge, retry all ou restauro completo. **Restauro completo requer decisão separada e reconciliação de escritas posteriores.**
|
|
'''
|
|
(OUT / 'resultado.md').write_text(report, encoding='utf-8')
|
|
procedure = '''# Procedimento executado e recuperação disponível
|
|
|
|
1. Conferidos candidata 41caea0f900f, ZIP/manifesto, investemoz:5432 e backup/restauro do destino de 17:12:20 UTC. Exportados objetos de serviço/ACL antes das mudanças.
|
|
2. Disponibilizados exclusivamente 22 ficheiros de código e 159 assets autorizados; COUNTRY02 ON, restantes fluxos OFF; chave/cifra/.env/dependências/TLS preservados.
|
|
3. Atualizados scanner 3310 e assinaturas 28150. Alinhadas tarefas LocalService; verificados direitos positivos e negativos com a identidade real. Worker inicialmente OFF.
|
|
4. Aplicados limites só ao vhost HTTPS; sintaxe validada. Como Laragon não recarregou a instância existente, o responsável autorizou a recarga graciosa própria do Apache. Filho substituído sem término forçado; três vhosts e PHP web conferidos no Chromium com TLS reconhecido.
|
|
5. 030000: prévia correspondente e ação HTTP autenticada da conta 2. Ledger e auditoria confirmados. Não repetir a instalação.
|
|
6. 040000: nova prévia com dependência 030000 e backup correspondentes; ação HTTP autenticada da conta 13. Ledger e auditoria confirmados. Não executar migrate geral.
|
|
7. Leitura imediatamente antes do worker: zero jobs/falhas, notificações OFF e zero destinatários. Habilitada a tarefa própria supervisionada; execução inicial terminada com 0. Não enfileirados ensaios sintéticos no ativo.
|
|
8. Conta 13 apresentou pedido de bootstrap com MFA. Conta 2 entrou em contexto de navegador separado e confirmou com o seu MFA. Conferidos IDs/alvo/hash/validade, uma dupla, pedido consumido e auditoria. Conta 13 não podia confirmar o próprio pedido.
|
|
9. Comparados novamente schema/linhas/sequências/4 originais/2 envelopes MFA contra o restauro. Encerrados Chromium e controladores temporários. Serviços autorizados permanecem supervisionados; fluxos operacionais OFF, COUNTRY02 ON.
|
|
|
|
## Contenção em caso de falha
|
|
|
|
Desabilitar a tarefa **InvestMoz Portal Documentary Worker** pelo Agendador, preservando fila e originais. Manter flags operacionais OFF. Corrigir somente o consumidor afetado e recuperar o job específico após diagnóstico; não usar purge/retry all. Scanner e HTTPS mantêm a proteção. A tarefa worker está protegida contra alteração por utilizador sem administração do Windows.
|
|
|
|
Repor configurações/tarefas/ACLs apenas nos objetos exportados e com o processo próprio preparado. Conferir sintaxe e vhosts antes de recarga. Conservar COUNTRY02 e o novo schema/histórico; o bootstrap já usado impede tratar down vazio do clone como reversão ativa. O backup anterior é a referência preservada de recuperação, não uma ordem de restaurar o ativo. Restauro completo e regressão de código incompatível exigem decisão separada.
|
|
|
|
## Abertura operacional separada
|
|
|
|
Preencher designações-operacionais.md com contas/organizações/representações/tipos/âmbitos reais. As concessões e a habilitação dos fluxos exigem o mecanismo e a decisão próprios. Nenhum dado ou responsável foi inventado para demonstração. 190000 só entra na entrega do percurso integrado; não bloqueou o schema deste workflow isolado.
|
|
'''
|
|
(OUT / 'procedimento-executado.md').write_text(procedure, encoding='utf-8')
|
|
designations = '''# Titulares e designações operacionais
|
|
|
|
| Conta existente | Papel | Organização/âmbito | Responsabilidade | Estado |
|
|
| --- | --- | --- | --- | --- |
|
|
| 13 — onala@me.com | Superutilizador titular | Administração de segurança | Apresentou o pedido com MFA; não confirmou o próprio pedido | Inicializado no destino |
|
|
| 2 — nala@tempo.co.mz | Superutilizador titular | Administração de segurança | Confirmou independentemente com MFA em sessão separada | Inicializado no destino |
|
|
| A preencher | Promotor | Organização/representação legítima, tipos e âmbito | Criar/coeditar/corrigir/submeter conforme autorização | Pendente; fluxo OFF |
|
|
| A preencher | Validador | Organização/âmbito e tipos | Revisão independente, correção/rejeição/aprovação fundamentadas | Pendente; fluxo OFF |
|
|
| A preencher | Publicador | Organização/âmbito, tipos e visibilidade | Publicar/suspender no âmbito autorizado | Pendente; fluxo OFF |
|
|
|
|
O responsável confirmou que os dois titulares são pessoas diferentes. Para os papéis operacionais indicar apenas conta existente, organização/representação legítima, tipos, âmbito e responsabilidade. Não são necessárias passwords ou informações MFA. Não acumular papéis de forma a contornar a revisão independente. A administração de segurança não concede acesso universal aos anexos nem atribui automaticamente papéis operacionais.
|
|
|
|
O destino permanece com zero organizações/memberships. A criação legítima e representação devem seguir o fluxo autorizado próprio. A configuração técnica está instalada; a abertura dos fluxos continua separada. Restauração, partilha individual, modulares/ofertas/SLA e 190000 permanecem fora.
|
|
'''
|
|
(OUT / 'designacoes-operacionais.md').write_text(designations, encoding='utf-8')
|
|
current = rows()
|
|
headers = current[0]
|
|
idx = headers.index('Evidência funcional')
|
|
addition = {
|
|
'AUD-OPS-01': 'Intervenção autorizada 41caea0f900f concluída no destino em 11/10/2026: backup/restauro real 17:12:20 UTC (288 tabelas/31 sequências/867 ficheiros/4 originais) conferido; ClamD3310/LocalService/assinaturas28150, permissões efetivas e PHP web20M/24M/256M/GD/WebP demonstrados. Worker supervisionado habilitado após nova leitura da default vazia/notificações OFF, primeira execução0. Processamento documental legítimo no destino permanece pendente; provas completas/falha/repetição do clone conservadas. Evidência: outputs/investmoz-workflow-activation-20261011/resultado.md e evidencias-destino.json.',
|
|
'AUD-PROFILE-15': 'Bootstrap cruzado efetivamente executado no destino: titular13 apresenta e titular2 confirma, pessoas independentes designadas, sessões/MFA próprios; prévia do autor não permite confirmar, uma dupla versão1 e pedido consumido com auditoria. Nenhuma conta/organização/representação/grant operacional criado. Papéis operacionais por designar com organização/tipos/âmbito; fluxos OFF. Evidência: outputs/investmoz-workflow-activation-20261011/designacoes-operacionais.md e evidencias-destino.json.',
|
|
'AUD-PROFILE-31': 'Candidata41caea0f900f e payload181 imutáveis disponibilizados no destino:030000 autenticada por2 e040000 autenticada por13, uma vez e na ordem, com prévias/hash/backup correspondentes e auditoria. Schema288→291→295,7tabelas/5colunas/0novas sequências, dados/originais/cifra/histórico preservados; COUNTRY02/050000 preservados,190000 ausente. Bootstrap13→2 concluído; restauração/partilha individual e fluxos operacionais OFF. Contenção preserva schema/dados/HTTPS; restauro completo separado. Evidência: outputs/investmoz-workflow-activation-20261011/resultado.md e procedimento-executado.md.'
|
|
}
|
|
updates = {}
|
|
for row in current[1:]:
|
|
if row[0] in addition:
|
|
assert '[Execução no destino 41caea0f900f]' not in row[idx]
|
|
updates[row[0]] = {'Evidência funcional': row[idx] + '\n\n[Execução no destino 41caea0f900f] ' + addition[row[0]]}
|
|
assert len(updates) == 3
|
|
write(PRIVATE / 'workflow-activation-matrix-baseline.json', dict(rows=current, updates=updates))
|
|
block = '''<!-- workflow-authorized-activation-20261011 -->
|
|
## Execução técnica autorizada no destino — 41caea0f900f
|
|
|
|
**Código/bundle, B1/B2, 030000 → 040000 e bootstrap cruzado concluídos no destino. COUNTRY02 preservado ON; fluxos operacionais OFF.** [Resultado e limites](../../../../outputs/investmoz-workflow-activation-20261011/resultado.md), [provas sanitizadas](../../../../outputs/investmoz-workflow-activation-20261011/evidencias-destino.json), [procedimento executado/reversão](../../../../outputs/investmoz-workflow-activation-20261011/procedimento-executado.md) e [designações](../../../../outputs/investmoz-workflow-activation-20261011/designacoes-operacionais.md).
|
|
|
|
Pacote/code/manifesto41caea0f900f/117d2d889701 preservados. Backup do destino de17:12:20UTC restaurado/verificado no clone:288 tabelas/31sequências/867ficheiros/4originais. No destino, somente030000 pela conta2 e040000 pela conta13, por ações HTTP autenticadas:288→291→295tabelas/5colunas/0novas sequências. Auditoria sem duplicações. Bootstrap:pedido13/confirmação2, sessões/MFA próprios, uma dupla/um pedido consumido. Zero novas identidades/organizações/representações ou concessões operacionais.
|
|
|
|
ClamD3310/LocalService/assinaturas28150 e ACLs positivas/negativas demonstrados. PHPweb20M/24M/256M/180s/GD/WebP e trêsvhosts verificados no Chromium com TLS reconhecido. Recarga própria graciosa do Apache expressamente autorizada após Laragon não recarregar a instância fora dele. Worker supervisionado habilitado após releitura da default vazia/notificações OFF; primeira execução0. O processamento documental completo/falha/repetição continua prova distinta do clone; no destino falta atividade documental legítima. Dados das288tabelas anteriores,4originais/2envelopesMFA eCOUNTRY02 preservados.
|
|
|
|
**Pendências operacionais:** designarPromotor/Validador/Publicador com contaexistente,organização/representação legítima,tipos/âmbito/responsabilidade; abertura dos fluxos separada. País mestre real aguardará organização legítima. Restauração/partilha individual,190000,cartografia/acervo/legado,modulares/ofertas/SLA continuam fora. A/B/C37 e provas QA válidas preservadas, sem repetição. Contenção preservaHTTPS/cifra/COUNTRY02/schema/histórico; restauro completo exige decisão separada.
|
|
|
|
Mesma matriz:3401requisitos/linhas,7739ocorrências, apenas3evidências complementadas; zero novosIDs/fontes e estados gerais preservados. Os blocos seguintes são históricos; as instalações e o bootstrap neles referidos como pendentes foram concluídos neste âmbito técnico.
|
|
|
|
<!-- /workflow-authorized-activation-20261011 -->
|
|
|
|
'''
|
|
for name in ['relatorio-executivo.md', 'backlog.md', 'plano-ativacao.md', 'workflow-criterios-saida-20261011.md']:
|
|
file = DOCS / name
|
|
text = file.read_text(encoding='utf-8')
|
|
assert '<!-- workflow-authorized-activation-20261011 -->' not in text
|
|
file.write_text(block + text, encoding='utf-8')
|
|
print(json.dumps(dict(result='records_prepared', matrix_authoring_pending=True, revision=REV)))
|
|
else:
|
|
baseline = read('workflow-activation-matrix-baseline.json')
|
|
current = rows()
|
|
assert len(current) == len(baseline['rows']) == 3402
|
|
differences = []
|
|
for before, after in zip(baseline['rows'], current):
|
|
assert len(before) == len(after)
|
|
for col, (old, new) in enumerate(zip(before, after)):
|
|
if old != new:
|
|
assert before[0] in baseline['updates'] and current[0][col] == 'Evidência funcional'
|
|
assert new == baseline['updates'][before[0]]['Evidência funcional']
|
|
differences.append(dict(id=before[0], column=current[0][col]))
|
|
assert len(differences) == 3
|
|
proof = read('workflow-activation-matrix-proof.json')
|
|
assert proof['states_unchanged'] and proof['sources_and_versions_unchanged']
|
|
state_column = current[0].index('Estado')
|
|
states = dict(Counter(row[state_column] for row in current[1:]))
|
|
files = {name: digest(OUT / name) for name in ['resultado.md', 'evidencias-destino.json', 'procedimento-executado.md', 'designacoes-operacionais.md']}
|
|
manifest = dict(at=datetime.now(timezone.utc).isoformat(), revision=REV, code='117d2d8897012e25bf2efc7a6c589dfb47c58b4a52a1e28331512b935ca00d44',
|
|
candidate_zip_sha256=ZIP_HASH, immutable_candidate_manifest_sha256=MANIFEST_HASH,
|
|
product_delta_this_execution=False, product_files=181, target='investemoz:5432',
|
|
technical_execution='completed', operational_flows_enabled=False, COUNTRY02_enabled=True,
|
|
resources_installed=True, profiles_installed=True, bootstrap_holder_ids=[13, 2],
|
|
artifacts=files, matrix=dict(rows=3401, source_occurrences=7739, states=states, changes=differences,
|
|
new_ids=0, source_and_version_changes=0,
|
|
sha256=digest(DOCS / 'matriz-requisitos.csv')))
|
|
write(OUT / 'manifesto-execucao.json', manifest)
|
|
print(json.dumps(dict(result='execution_recorded', revision=REV, states=states, changed_cells=3, operational_flows_enabled=False), ensure_ascii=False))
|