Pular para conteúdo

0008 — Adota xadm-comum-web (base transversal da casa) e desliga o security transitivo

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-08-05 · Decidido em: 2026-08-05

Contexto

O int-pied mantinha, no pacote comum, cópias divergentes da base transversal que a casa extraiu para a lib br.com.xadm:xadm-comum-web:0.1.0 (br.com.xadm.comum.web, publicada no Forgejo Packages): ProblemDetail e UnifiedErrorResponseProcessor (byte-idênticos ao canônico), VersaoProvider (mesmo papel de VersaoInfo, nome divergente) e HealthController respondendo {status:"ok"} sem @Secured (o canônico é {status:"UP"} + @Secured(IS_ANONYMOUS)). maxsul era o único dos 4 apps da casa que ainda não consumia a lib — sem o repo maven do Forgejo, sem xadm-seguranca.

O refino da spec pegou dois fatos que só o artefato publicado responde: o POM da lib declara io.micronaut.security:micronaut-security em scope compile — logo, transitivo — e o shape real do /health. maxsul é deliberadamente aberto, sem auth (diagnóstico atrás da rede — decisões 0004/0005). No Micronaut, micronaut-security no classpath liga o SecurityFilter por default e rejeita (401) todo endpoint não-@Secured — o que trancaria o webhook, as telas e o próprio /health do healthcheck.

Decisão

Consumir a lib e remover as cópias, reconciliando nome/contrato para o canônico:

  • build.gradle.kts: repo maven do Forgejo (https://fonte.xadm.biz/api/packages/xadm/maven, org pública → leitura anônima) + implementation("br.com.xadm:xadm-comum-web:0.1.0").
  • Deletadas as cópias locais (ProblemDetail, UnifiedErrorResponseProcessor, HealthController, VersaoProvider); imports migrados para br.com.xadm.comum.web (WebhookController, GlobalExceptionHandler, Application, GlobalViewModel).
  • Security transitivo desligado em application.yml: micronaut.security.enabled: false. Mantém a postura "tudo aberto" e deixa o @Secured(IS_ANONYMOUS) da lib inerte — não há SecurityFilter para interceptar.
  • Contrato do /health: ok → UP (mudança observável). A lib mantém o campo versao (shape §5 {status, versao} intacto; verificado pelo gate). Docs de operação e o teste atualizados.

Consequências

  • Uma fonte única para a base transversal (§1.9): correção/evolução na lib chega aos 4 apps sem divergência de cópia. VersaoProvider deixa de existir; VersaoInfo lê o mesmo /version.properties#app.version (a task gerarVersionProperties do build permanece).
  • micronaut-security (e micronaut-management) agora estão no classpath, apenas desligados. Um dev da Fase 2 que for introduzir auth não precisa adicionar a dependência — precisa religar o filtro (micronaut.security.enabled: true) e desenhar as regras (intercept-url-map/@Secured). O /health do management segue enabled: false (o HealthController da lib é quem serve /health).
  • Mudança de contrato ok→UP é HTTP-200 nos dois casos: o healthcheck do Dockerfile (curl -f) e o Coolify/Traefik julgam por status HTTP, não pelo corpo — imunes. Nenhum monitor faz grep de "ok".
  • Reversível: remover a dependência e restaurar as cópias é uma edição de build + git revert; o contrato do /health volta com o literal.

Alternativas consideradas

  • Manter security ligado + intercept-url-map liberando /** anonimamente — rejeitado: mais superfície de config agora, sem ganho presente (a auth da Fase 2 ainda não está desenhada). Desligar o filtro é a expressão mais enxuta da postura atual e trivial de reverter.
  • Excluir a transitiva no Gradle (exclude group: "io.micronaut.security") — rejeitado: o @Secured da lib passaria a não resolver em runtime de forma silenciosa, e a casa pode vir a expor membros que dependem de tipos de security; desligar por config é mais honesto que amputar o classpath.
  • Pedir à casa expor security como compileOnly/optional na lib — encaminhado como feedback §6 pro repo central (beneficia os outros apps abertos), mas não bloqueia esta adoção: desligar por config resolve no app hoje.