ThreatRadar LATAM
O boletim de CVE do dia tem trezentas linhas e três delas tocam a sua pilha.
ThreatRadar parte de um perfil de superfície que o cliente declara — tecnologias, fornecedores e setores — e usa esse perfil para separar o que importa do que é ruído. A correlação é determinística e auditável: interseção de tecnologias, casamento de fornecedor por substring, e uma regra explícita de que vulnerabilidade crítica entra na fila mesmo sem casar tecnologia. O motivo do casamento fica gravado em texto no próprio match.
A arquitetura é de fan-out: as fontes públicas são globais, mas cada item é materializado por tenant, sob a RLS do tenant, com upsert idempotente por (tenant, tipo de fonte, id externo). Assim o cliente vê a sua cópia correlacionada ao seu perfil, e o isolamento não depende de filtro de aplicação.
O que está pronto é a leitura do feed, a fila de triagem com transições validadas, o perfil e o brief executivo por IA. Mas sem ingestão essas três primeiras só têm conteúdo onde o seed de demonstração colocou um CVE e um match: num tenant novo o feed nasce vazio e continua vazio, e o perfil de superfície é a única parte que o cliente exercita de ponta a ponta hoje. O brief é honesto por desenho: é marcado como rascunho, se ancora só no conteúdo do item e, quando o guardrail barra, devolve `blocked` com resumo nulo em vez de inventar texto. O que ainda não anda é a ingestão: o pedido de coleta é emitido no outbox e nenhum consumidor está registrado no relay, e o parser de feed é genérico demais para os formatos reais das fontes.
Capacidades em operação
Cada item corresponde a funcionalidade que existe no código e é alcançável por um usuário com o escopo correto.
-
Perfil de superfície do tenant
GET e PUT /threatradar/profile com tecnologias, fornecedores e setores, normalizados e deduplicados, uma linha por tenant com upsert idempotente.
-
Feed com filtros
GET /threatradar/feed com filtro por severidade, CVE, tecnologia afetada e data, paginado por cursor. Detalhe por item com CVEs, tecnologias, publicação e resumo.
-
Correlação determinística e explicável
Score 0-100 pela banda de severidade mais bônus por casamento (10 para tecnologia, 5 para fornecedor). Item sem casamento e não-crítico simplesmente não vira match — a regra existe para reduzir falso positivo.
-
Fila de triagem
GET /threatradar/matches com filtro por status e risco mínimo, item embutido no retorno. PATCH com transições validadas: confirmed e dismissed são terminais.
-
Brief executivo por IA
POST /threatradar/items/{id}/brief gera até cinco frases em PT-BR sobre o que é a ameaça, a quem afeta, a urgência e a ação de maior impacto. Grava em `summary_pt`, devolve `is_draft: true` e aceita Idempotency-Key para o duplo clique não gastar duas vezes.
-
Conteúdo de feed tratado como hostil
Título e resumo de terceiro entram embrulhados em `wrap_untrusted`; o corpo do feed passa por redação de segredo na ingestão. O prompt proíbe inventar CVE ou CVSS além do fornecido.
-
Coletor SSRF-safe
Coletor SSRF-safe (escrito, ainda não ligado) — quando a ingestão for conectada ao relay, o coletor resolve o host da fonte antes de conectar e recusa IP privado, loopback ou de metadata; conexão pinada ao IP validado, sem seguir redirect, teto de 1 MB por fonte, orçamento de tempo total e contrato no-raise. / Fan-out por tenant (escrito, ainda não ligado) — upsert idempotente de itens e de matches por tenant, com contagem de novos itens, novos matches e alertas por execução, e trilha em audit_log. Nenhum dos dois é executado hoje: o consumidor do pedido de coleta não está registrado no relay.
-
Fan-out por tenant
Upsert idempotente de itens e de matches por tenant, com contagem de novos itens, novos matches e alertas por execução, e trilha em audit_log.
Entregáveis
- Telas /app/threatradar (feed), /app/threatradar/triagem (fila de matches), /app/threatradar/perfil e /app/threatradar/item/[id] com o brief.
- Perfil de superfície persistido por tenant.
- Fila de matches com score, motivo do casamento e estado de triagem.
- Resumo executivo em PT-BR gravado no item, marcado como rascunho de IA.
O que este módulo não faz
A coleta não roda hoje. O tópico `threatradar.refresh.requested` não tem consumidor registrado no relay do outbox (`_enqueue` em app/worker/tasks/outbox.py trata scan, shadowsignal, soc, triageai, securecode, otsentinel, orchestrator, casos e hibp — não trata threatradar). Manual e agendado emitem o evento e nada é enfileirado; a task `threatradar.refresh` existe e nunca é chamada. Consequência de cobrança: o refresh manual reserva crédito no `start_refresh` e o capture/release vive dentro de `execute_refresh`, então o hold fica aberto. Além disso, o parser de feed é genérico (JSON plano com id, title, severity) e não há adaptador para o formato do NVD 2.0, do CERT.br ou de feeds de IOC — a fonte demo do seed aponta para a API do NVD e não é decodificada. Não há catálogo de fontes globais além dessa fonte demo, e `threatradar_sources` é control-plane sem endpoint de gestão. O alerta `threatradar.alert.raised` é gravado no outbox e não tem consumidor: não vira e-mail nem notificação. Não há tabela de run — o `run_id` devolvido é o id do hold — e não há reaper. O brief consome token do provedor sem hold de créditos e é sob demanda, um item por chamada. O beat agendado só roda com `JC_THREATRADAR_ENABLED=true`, que é false por padrão. O rótulo LATAM descreve a intenção do recorte regional: hoje o produto é o perfil mais a correlação, sem fonte regional ligada.
Declaramos o limite porque software de segurança que promete tudo não é auditável. Se o que falta aqui é o que você precisa, o serviço consultivo cobre — ou dizemos que não cobre.
Conecta com
- app/scan/passive (guard SSRF e redação de segredo)
- app/ai (AiGateway, registry aditivo, sanitize)
- app/billing (hold no refresh manual)
- app/core/outbox e worker Celery (beat de sweep; consumidor de refresh não registrado no relay)
- telas /app/threatradar, /triagem, /perfil e /item/[id] no app web
Controle de acesso
O acesso é concedido por escopo, não por perfil genérico. Quem só precisa ler não recebe permissão de escrita, e a barreira é o banco de dados, não a interface.
- threatradar:feed:read
- threatradar:feed:write
- threatradar:profile:read
- threatradar:profile:write
- threatradar:collect:run
Quer ver funcionando?
Demonstração com dado do seu ambiente, não com base de exemplo. É a única forma de saber se serve.