# Segurança e observabilidade ## Auditoria `audit_log` recebe upload e exclusão de modelo, mudança da setting, criação, início, conclusão, falha e download. Metadados passam por lista de chaves bloqueadas e só aceitam escalares. O teste de jornada procura o token `=CMD()` no log e não o encontra. ## Sentry `beforeSend` remove body, cookies, breadcrumbs e headers de autorização. Tags previstas: módulo, `job_id`, `workspace_id`, `error_code`. Validação de negócio (`AdapterError` abaixo de 500) não é capturada. Sem DSN, a inicialização não ocorre. ## Controles - RLS e checagem de papel no serviço - Extensão conferida com assinatura ZIP/OLE - Rejeição de XLS, ODS, XML, MIME incompatível e ZIP com expansão acima de 256 MB ou taxa anômala - Chave de storage sem `..` e, no disco local, resolvida dentro do diretório privado - CSV/XLSX de saída neutraliza células que começam com `=`, `+`, `@` ou hífen que não é número - Download exige sessão, workspace, fonte concluída e `expires_at` futuro - Lock Redis (ou falha `REDIS_UNAVAILABLE`) antes de processar; clique repetido com a mesma chave de idempotência devolve o job existente - Nomes exibidos são basename sanitizado ## Threat model resumido | Ameaça | Mitigação | Residual | | --- | --- | --- | | IDOR / workspace forjado | Sessão + RLS + auditoria | Conexão de serviço ignora RLS e só pode existir no servidor | | Bypass de papel | Serviço e policies | — | | Planilha em log | Scrub e auditoria escalar | Erro inesperado ainda pode ir ao Sentry se o `throw` embutir dado; o código de domínio evita isso | | ZIP bomb | Teto de expansão antes do ExcelJS | Estruturas com data descriptor continuam limitadas pelos 10 MB de entrada | | CSV injection | Prefixo `'` | Números negativos permanecem numéricos de propósito | | Job duplicado | Lock + idempotência | Lock em memória vale para um processo; produção exige Redis | ## Riscos residuais PDF limita 200 linhas e 12 colunas e declara a limitação no próprio arquivo. XLSX/CSV levam o resultado completo. A formatação visual do modelo não é copiada: a saída é um arquivo novo e o binário do modelo é conferido por SHA-256 antes e depois.