Browse Source

feat(assinatura): pendência emite URL de verificação e casa legislativa AB#1473 (#18)

* Fix(Assinatura): materializacao recusa rodar sem base URL em vez de falhar 861 vezes AB#1473

Achado num acervo real em 22/08/2026: 0 de 861 materias DOCX tinham PDF-alvo, e
o motivo nao aparecia em lugar nenhum. So os 7 PDF passavam — PDF nao converte,
copia bytes — e davam a impressao de que a rotina estava viva.

A conversao DOCX->PDF e o OnlyOffice quem faz, e para isso ele BAIXA o documento
de origem por URL absoluta. `build_onlyoffice_url` prefere SAPL_INTERNAL_URL e so
cai no request sem ela; no cron o "request" e o `_RequisicaoDeSistema`, que monta
a partir de SITE_URL. Com as duas vazias a URL sai SEM HOST, o OnlyOffice
responde erro e cada materia vira um logger.error individual. O resumo da passada
(`0 gerados, 873 falhas`) nao se distingue de um dia normal no meio do log.

Duas mudancas, as duas sobre visibilidade:

1. Erro de CONFIGURACAO morre no comeco, alto: sem SAPL_INTERNAL_URL nem
   SITE_URL o comando levanta CommandError antes de varrer o acervo, dizendo
   qual variavel falta e por que. Vale para a passada unica e para o laco.

2. Passada que falha sem NENHUM gerado grita no stderr: falha em todas nao e
   documento podre avulso, e ambiente parado (OnlyOffice fora, URL que ele nao
   alcanca, MEDIA sem os binarios).

A fixture `base_url_configurada` entra em autouse no test_materializacao: base
URL e pressuposto de toda materializacao, nao caso de borda — a ausencia dela tem
os seus proprios testes.

Testes: 64 passed em sapl/integracao_hub/tests/ (eram 61).

* feat(assinatura): pendencia emite URL de verificacao e casa legislativa AB#1473

Sem estes dois campos o AMU assina SEM a pagina de autenticacao, e o documento
sai divergente do assinado no SAPL — exatamente o que a convergencia dos
assinadores elimina. Achado testando a assinatura pelo app: o microservico
respondeu 400 "verification_url_base vazio.".

So o SAPL sabe a URL publica desta casa e o nome dela, entao os campos precisam
viajar COM a pendencia. O amu-backend ja os consome (grava em
`casa_legislativa`/`verification_url_base` e repassa ao /sign); hoje chegavam
vazios porque a fonte nao os emitia, e o fallback por tenant_settings tambem
nao estava configurado.

Reusa `_construir_url_verificacao_base` e `_obter_nome_casa_legislativa` de
views_assinatura em vez de remontar a URL aqui: sao a forma canonica que o
proprio SAPL usa ao chamar o microservico. Duplicar a montagem e o caminho
conhecido para as duas divergirem na primeira mudanca. Sem ciclo de import
(views_assinatura nao importa integracao_hub).

Verificado no container sapl-localhost:
- 23 testes de integracao_hub/tests/test_assinatura.py passando
- payload real da materia 811/2026:
    verification_url_base: http://<host>/materia/1065/verificar/
    casa_legislativa: Camara Municipal de Franco da Rocha

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
pull/3858/head
Kemuel-sepulvida 4 weeks ago
committed by GitHub
parent
commit
3d9c94f439
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 13
      sapl/integracao_hub/serializacao.py

13
sapl/integracao_hub/serializacao.py

@ -8,6 +8,8 @@ from django.utils import timezone
from sapl.base.models import Autor, OperadorAutor
from sapl.materia.models import MateriaLegislativa
from sapl.materia.views_assinatura import (
_construir_url_verificacao_base, _obter_nome_casa_legislativa)
from sapl.parlamentares.models import Parlamentar, Votante
logger = logging.getLogger(__name__)
@ -203,6 +205,14 @@ def _autores_pendentes(materia):
def serializar_pendencia(alvo, request):
"""Item de `assinaturas-pendentes` (§3): só existe com o PDF-alvo materializado."""
materia = alvo.materia
# `verification_url_base` e `casa_legislativa` viajam com a pendência porque
# SÓ O SAPL sabe a URL pública desta casa e o nome dela. Sem eles o AMU assina
# sem a página de autenticação — e o documento sai divergente do assinado aqui,
# que é exatamente o que a convergência dos assinadores (AB#1473) elimina.
#
# Reusamos as funções de `views_assinatura` em vez de remontar a URL aqui: elas
# são a forma canônica que o próprio SAPL usa ao chamar o microserviço. Duplicar
# a montagem é o caminho conhecido para as duas divergirem na primeira mudança.
return {
# Keyset da fonte: o hub le `id` no topo e devolve como `id_gt`, e a
# view filtra `materia_id__gt` (o alvo e OneToOne com a materia, ver
@ -220,6 +230,9 @@ def serializar_pendencia(alvo, request):
'documento': _bloco_documento(
alvo.arquivo, request, 'integracao_hub_documento_alvo',
materia.pk, hash_sha256=alvo.hash_sha256),
'verification_url_base': _construir_url_verificacao_base(
request, 'materia', materia.pk),
'casa_legislativa': _obter_nome_casa_legislativa(),
}

Loading…
Cancel
Save