feat: agente de triagem de incidentes de seguranca com Spring AI e padroes de projeto - #1
Merged
Merged
Conversation
Estrutura inicial do agente de triagem de seguranca: - Spring AI com starter Ollama para inferencia local - Java 21, Maven wrapper (somente script) - Modelo padrao qwen2.5:7b, configuravel por variavel de ambiente - gitignore ampliado para target/, IDEs e macOS
Tipos imutaveis que servem de base para todos os patterns: - Severity com peso, usado na agregacao recursiva do Composite - Alert e Ioc representando a deteccao bruta, nunca alterados pelo agente - MitreTechnique para classificacao ATT&CK - TriageVerdict separando o que o modelo conclui do que o agente executa
AgentEventBus e o Subject; AgentEventListener e o Observer. - Publicacao isolada por observador: falha de um nao interrompe os demais, garantindo que a trilha de auditoria sobreviva a erros de renderizacao - CopyOnWriteArrayList porque a GUI registra observadores pela EDT do Swing enquanto o agente publica de outra thread - AuditTrailListener materializa a trilha exigida por conformidade - ConsoleListener espelha o progresso sem depender da GUI
Incident e o Context; IncidentState e a abstracao de estado. - Operacoes ilegais sao impossiveis por construcao: a interface declara todas as operacoes com implementacao padrao que lanca excecao, e cada estado concreto sobrescreve apenas o que permite - Nenhum switch sobre fase; nova fase = nova classe, sem alterar o Context - AwaitingApprovalState e a barreira de governanca do dominio: contencao so e liberada apos decisao humana explicita - Cada transicao publica evento no barramento, ligando State e Observer - 4 testes cobrindo fluxo completo, barreira de aprovacao, negacao e estado terminal
AgentCommand e a abstracao; CommandInvoker e o Invoker; ContainmentGateway isola a fronteira com EDR, firewall e NAC. - Comandos sao codigo Java, nunca texto gerado pelo modelo: o modelo escolhe qual invocar e com quais parametros, o efeito e fixado em compilacao - A barreira de aprovacao vive no invoker, nao em cada comando, entao um comando novo ja nasce protegido - Acao compensatoria via undo: reverter contencao equivocada importa tanto quanto aplica-la - Falha de um comando nao interrompe a fila - 6 testes cobrindo recusa sem aprovacao, execucao, undo, ordem e falha
TriagePlanner e a abstracao; ReAct, PlanThenExecute e HumanInTheLoop sao as estrategias concretas. ThreatAnalyst isola o modelo atras de uma porta. - CommandFactory e o unico ponto onde saida de modelo vira acao, e opera por lista de permissao: ferramenta desconhecida e descartada, nunca interpretada - ReAct executa apenas leitura durante o ciclo e acumula contencao para depois da aprovacao, senao o ciclo adaptativo contornaria a governanca - HumanInTheLoop e Strategy que tambem decora: forca aprovacao sem duplicar o planejamento - MitreRepository mantem ATT&CK offline, sem dependencia de rede - 5 testes com analista falso, incluindo rejeicao de ferramenta alucinada
LlmThreatAnalyst implementa a porta usando ChatClient com saida estruturada. - Papel do modelo restrito a classificar, justificar e sugerir nomes de ferramenta; nao executa nada e nao decide se a acao acontece - Prompt de sistema declara a lista de permissao e proibe inventar host, IP ou identificador de tecnica ausente do alerta - DTOs planos em vez de mapas aninhados: modelos de 7B erram menos formato - Toda falha degrada para NEEDS_HUMAN_REVIEW; agente que nao conclui escala, nunca adivinha - Classificacao nao reconhecida tambem vira revisao humana
IncidentTriageService coordena os quatro padroes sem conter regra propria: State define o que pode acontecer, Strategy decide o que fazer, Command executa e Observer difunde. - PlannerRegistry permite trocar a estrategia em tempo de execucao, o que torna o Strategy observavel na GUI - Nenhuma acao destrutiva ocorre na triagem: o State barra e o Invoker recusa - Veredito abaixo da confianca minima vai para aprovacao mesmo se o plano nao tiver acao destrutiva - Configuracao exposta via soc-agent.* no application.yml
EvidenceNode e o Component, EvidenceLeaf a folha, EvidenceGroup o composto. - Operacoes recursivas como metodos padrao da interface: folha e composto respondem identicamente a leafCount, highestSeverity, depth e render - Severidade agrega de baixo para cima, entao um grupo LOW com IOC CRITICAL aparece como CRITICAL sem recalculo manual - Folha recusa filhos, preservando a transparencia sem permitir composicao invalida - EvidenceTreeBuilder monta incidente, alertas, IOCs, tecnicas e decisao - 5 testes cobrindo recursao, agregacao e tratamento uniforme
Cada regiao da tela expoe um padrao: arvore a esquerda e o Composite, log a direita e o Observer, seletor no topo troca o Strategy em execucao e os botoes inferiores sao Commands habilitados conforme o State. - A janela e ela propria um AgentEventListener; como o agente publica de outra thread, toda atualizacao visual volta para a EDT - Triagem roda em SwingWorker: a chamada ao modelo levaria segundos e congelaria a interface na EDT - Botao de aprovar so habilita na fase AWAITING_APPROVAL, tornando a barreira de governanca visivel na interface - Quatro cenarios cobrindo exfiltracao, forca bruta, ransomware e um falso positivo, com hosts e enderecos ficticios - Ambiente headless nao impede a aplicacao de subir
A trilha de auditoria subia vazia: AuditTrailListener e ConsoleListener existiam no contexto mas ninguem os registrava, entao nenhum evento chegava neles. So a janela do painel se inscrevia, por conta propria. Em um agente cujo requisito central e auditabilidade, perder a trilha inteira e a falha mais grave possivel, e ela passava despercebida porque nada quebrava. - EventListenerRegistrar inscreve todo AgentEventListener do contexto - Acrescentar observador novo passa a exigir apenas declara-lo como bean - 4 testes cobrindo difusao, isolamento de falha, registro e filtro por tipo Tambem adiciona HeadlessDemoRunner para exercitar o fluxo completo em terminal, sem interface grafica.
Oito diagramas em Mermaid, renderizados nativamente pelo GitHub e validados com o parser do mermaid 11: - Fluxograma de camadas mostrando a regra de dependencia - Diagrama de classes para cada um dos cinco padroes - Maquina de estados do ciclo de vida do incidente - Diagrama de sequencia do fluxo completo, destacando a pausa para aprovacao humana Inclui a tabela de verificacao da barreira de governanca, que mapeia a invariante 'nenhuma acao destrutiva sem decisao humana' aos dois mecanismos independentes que a protegem e aos testes que a cobrem.
O runner aprovava sozinho e executava a contencao, o que anulava justamente a barreira que o projeto existe para demonstrar. No cenario de backup noturno isso significava isolar o servidor de backup sem decisao humana alguma. Agora o padrao e parar em AWAITING_APPROVAL, como pararia em producao; a aprovacao simulada exige --aprovar explicito. - Busca de cenario por trecho do nome, ja que a linha de comando quebra o argumento nos espacos - README documenta o resultado real medido: o Qwen 2.5 7B classifica o backup legitimo como verdadeiro positivo com confianca 0,80 e propoe isolar o servidor - A causa raiz (ausencia de inventario de ativos e calendario de mudancas) fica registrada como evolucao do projeto
DanielDPereira
requested review from
DanielDPereira
and
a lite review from Copilot
August 10, 2026 15:59
There was a problem hiding this comment.
Pull request overview
Este PR introduz um agente de triagem de incidentes de segurança (offline) em Java/Spring Boot + Spring AI (Ollama), estruturado para demonstrar e aplicar padrões GoF (State/Command/Strategy/Observer/Composite) com barreira de governança e aprovação humana antes de contenção.
Changes:
- Implementa o núcleo de domínio (State/Command/Strategy/Observer) com trilha de auditoria e fila de comandos reversíveis.
- Adiciona integração com LLM local via Spring AI (porta
ThreatAnalyst) e lista de permissão de ferramentas viaCommandFactory. - Cria GUI Swing + runner headless, documentação (README + arquitetura) e suíte de testes offline cobrindo os fluxos principais.
Reviewed changes
Copilot reviewed 59 out of 60 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/test/java/br/fatec/esiii/socagent/strategy/TriagePlannerTest.java | Testes das estratégias (plan-then-execute, react, human-in-the-loop) e whitelist de ferramentas |
| src/test/java/br/fatec/esiii/socagent/state/IncidentStateTest.java | Testes do fluxo de fases do incidente e barreira de aprovação no State |
| src/test/java/br/fatec/esiii/socagent/observer/AgentEventBusTest.java | Testes do barramento de eventos e isolamento de falhas de observadores |
| src/test/java/br/fatec/esiii/socagent/gui/tree/EvidenceNodeTest.java | Testes do Composite (contagem, severidade agregada, profundidade, render) |
| src/test/java/br/fatec/esiii/socagent/command/CommandInvokerTest.java | Testes do invoker (aprovação, execução, fila, undo e falhas) |
| src/main/resources/application.yml | Configuração do Spring AI/Ollama e parâmetros do agente (planner, confiança mínima, aprovador padrão) |
| src/main/java/br/fatec/esiii/socagent/strategy/TriagePlanner.java | Interface Strategy e record Plan para resultado de planejamento |
| src/main/java/br/fatec/esiii/socagent/strategy/ThreatAnalyst.java | Porta de saída para o modelo (classificar e propor ações) |
| src/main/java/br/fatec/esiii/socagent/strategy/ReActPlanner.java | Planner ReAct com ciclo iterativo e separação leitura vs contenção |
| src/main/java/br/fatec/esiii/socagent/strategy/ProposedAction.java | DTO inerte de ação sugerida pelo modelo (tool + args + rationale) |
| src/main/java/br/fatec/esiii/socagent/strategy/PlanThenExecutePlanner.java | Planner “plano completo” e avaliação de aprovação necessária |
| src/main/java/br/fatec/esiii/socagent/strategy/HumanInTheLoopPlanner.java | Decorator que força aprovação humana para planos não vazios |
| src/main/java/br/fatec/esiii/socagent/strategy/CommandFactory.java | Tradução por lista de permissão de sugestões do modelo em AgentCommand |
| src/main/java/br/fatec/esiii/socagent/state/IncidentStates.java | Implementações concretas do State e fluxo permitido de fases |
| src/main/java/br/fatec/esiii/socagent/state/IncidentState.java | Interface State com operações permitidas e exceção padrão em transições ilegais |
| src/main/java/br/fatec/esiii/socagent/state/IncidentPhase.java | Enum de fases para GUI/relatórios |
| src/main/java/br/fatec/esiii/socagent/state/Incident.java | Context do State + publicação de eventos no barramento |
| src/main/java/br/fatec/esiii/socagent/state/IllegalTransitionException.java | Exceção para transição/ação não permitida pela fase atual |
| src/main/java/br/fatec/esiii/socagent/SocAgentApplication.java | Entry point Spring Boot + scan de properties |
| src/main/java/br/fatec/esiii/socagent/service/SampleAlertCatalog.java | Catálogo de cenários de alertas para demonstração |
| src/main/java/br/fatec/esiii/socagent/service/PlannerRegistry.java | Registro e ativação runtime de estratégias (Strategy) |
| src/main/java/br/fatec/esiii/socagent/service/IncidentTriageService.java | Orquestrador (integra State/Strategy/Command/Observer) e caminhos approve/deny/undo |
| src/main/java/br/fatec/esiii/socagent/service/HeadlessDemoRunner.java | Runner headless para demonstrar fluxo completo no terminal |
| src/main/java/br/fatec/esiii/socagent/service/AgentProperties.java | Properties do agente (planner/confiança/aprovador) |
| src/main/java/br/fatec/esiii/socagent/observer/EventListenerRegistrar.java | Registro automático de listeners declarados como bean |
| src/main/java/br/fatec/esiii/socagent/observer/ConsoleListener.java | Listener para log no console (Observer) |
| src/main/java/br/fatec/esiii/socagent/observer/AuditTrailListener.java | Listener que materializa trilha de auditoria em memória |
| src/main/java/br/fatec/esiii/socagent/observer/AgentEventListener.java | Interface de listener com supports e listenerName |
| src/main/java/br/fatec/esiii/socagent/observer/AgentEventBus.java | Barramento com isolamento de falhas e CopyOnWriteArrayList |
| src/main/java/br/fatec/esiii/socagent/observer/AgentEvent.java | Record de evento e enum de tipos publicados pelo agente |
| src/main/java/br/fatec/esiii/socagent/mitre/MitreRepository.java | Repositório offline de técnicas MITRE ATT&CK |
| src/main/java/br/fatec/esiii/socagent/gui/tree/EvidenceTreeBuilder.java | Builder da árvore de evidências (Composite) a partir do incidente |
| src/main/java/br/fatec/esiii/socagent/gui/tree/EvidenceNode.java | Interface do Composite com operações recursivas (render, severidade, contagem) |
| src/main/java/br/fatec/esiii/socagent/gui/tree/EvidenceLeaf.java | Folha do Composite (IOC/técnica/nota) |
| src/main/java/br/fatec/esiii/socagent/gui/tree/EvidenceGroup.java | Composto do Composite (agrupamento de nós) |
| src/main/java/br/fatec/esiii/socagent/gui/SocDashboardFrame.java | GUI Swing (painel), seleção de cenário/estratégia, botões e renderização da árvore |
| src/main/java/br/fatec/esiii/socagent/gui/GuiLauncher.java | Launcher condicionado a profile/headless e setup de Look&Feel |
| src/main/java/br/fatec/esiii/socagent/domain/TriageVerdict.java | Modelo de veredito (classificação/confiança/justificativa/técnicas) e regra de acionabilidade |
| src/main/java/br/fatec/esiii/socagent/domain/Severity.java | Enum de severidade com agregação e regra de contenção por nível |
| src/main/java/br/fatec/esiii/socagent/domain/MitreTechnique.java | Record de técnica ATT&CK (inclui unknown) |
| src/main/java/br/fatec/esiii/socagent/domain/Ioc.java | Record de IOC com validação e helpers de criação |
| src/main/java/br/fatec/esiii/socagent/domain/Alert.java | Record de alerta e formatação compacta para prompt |
| src/main/java/br/fatec/esiii/socagent/command/SimulatedContainmentGateway.java | Gateway simulado com estado em memória (isolamento/bloqueio) |
| src/main/java/br/fatec/esiii/socagent/command/LookupMitreCommand.java | Comando de consulta MITRE (somente leitura) |
| src/main/java/br/fatec/esiii/socagent/command/IsolateHostCommand.java | Comando destrutivo e reversível (isolar/restaurar host) |
| src/main/java/br/fatec/esiii/socagent/command/ContainmentGateway.java | Porta para execução de contenção (EDR/firewall/NAC) |
| src/main/java/br/fatec/esiii/socagent/command/CommandResult.java | Record de resultado (ok/failure/refused) com duração |
| src/main/java/br/fatec/esiii/socagent/command/CommandInvoker.java | Invoker: fila, autorização, execução, undo e publicação de eventos |
| src/main/java/br/fatec/esiii/socagent/command/CollectForensicsCommand.java | Comando de coleta forense (leitura) |
| src/main/java/br/fatec/esiii/socagent/command/BlockIpCommand.java | Comando destrutivo e reversível (bloquear/desbloquear IP) |
| src/main/java/br/fatec/esiii/socagent/command/AgentCommand.java | Interface base de Command (requiresApproval/undoable/undo) |
| src/main/java/br/fatec/esiii/socagent/ai/LlmThreatAnalyst.java | Implementação ThreatAnalyst com Spring AI + prompts estruturados e degradação para revisão humana |
| src/main/java/br/fatec/esiii/socagent/ai/AnalystResponses.java | Records de saída estruturada (veredito/plano/próximo passo) |
| README.md | Documentação de uso, stack/licenças, cenários, configuração e decisões de projeto |
| pom.xml | Build Maven (Spring Boot 3.5.3, Spring AI BOM 1.0.0, Java 21, dependências) |
| mvnw.cmd | Maven Wrapper (Windows) |
| mvnw | Maven Wrapper (Unix) |
| docs/arquitetura.md | Documento de arquitetura com diagramas Mermaid (padrões e fluxos) |
| .mvn/wrapper/maven-wrapper.properties | Propriedades do Maven Wrapper (URL da distribuição) |
| .gitignore | Ignora target/IDE/OS artifacts |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+74
to
+79
| public List<AgentCommand> createAll(List<ProposedAction> actions, String defaultHostname) { | ||
| return actions.stream() | ||
| .map(action -> create(action, defaultHostname)) | ||
| .flatMap(Optional::stream) | ||
| .toList(); | ||
| } |
Comment on lines
+70
to
+74
| if (candidate.requiresApproval()) { | ||
| pendingContainment.add(candidate); | ||
| observations.add("Acao '%s' acumulada para apos aprovacao humana".formatted(candidate.name())); | ||
| } else { | ||
| observations.add(candidate.execute().output()); |
| List<String> techniqueIds) { | ||
|
|
||
| public TriageVerdict { | ||
| confidence = Math.clamp(confidence, 0.0, 1.0); |
Comment on lines
+251
to
+258
| private void setBusy(boolean busy) { | ||
| triageButton.setEnabled(!busy); | ||
| scenarioSelector.setEnabled(!busy); | ||
| plannerSelector.setEnabled(!busy); | ||
| if (busy) { | ||
| statusLabel.setText("Consultando o modelo..."); | ||
| } | ||
| } |
Comment on lines
+42
to
+45
| public Incident open(List<Alert> alerts) { | ||
| String id = "INC-%04d".formatted(sequence.getAndIncrement()); | ||
| return new Incident(id, alerts, eventBus); | ||
| } |
Comment on lines
+12
to
+15
| * <p>O runtime do agente conhece apenas esta interface. Trocar de | ||
| * {@link ReActPlanner} para {@link PlanThenExecutePlanner} nao altera uma linha | ||
| * do orquestrador, e envolver qualquer um deles em | ||
| * {@link HumanInTheLoopPlanner} acrescenta governanca sem modifica-los. |
DanielDPereira
approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Agente de triagem de incidentes de seguranca construido com Spring AI e modelos de linguagem abertos executados localmente via Ollama. Nenhuma chamada a servico externo, nenhuma chave de API.
Categoria de caso de uso: Security Agents — investigar alertas, correlacionar eventos e acionar contencao, com governanca estrita e aprovacao humana obrigatoria para acoes criticas.
Padroes de projeto
state/command/strategy/observer/gui/tree/Documentacao completa com 8 diagramas UML em
docs/arquitetura.md, validados com o parser do mermaid 11.Decisoes de projeto
O modelo nao executa nada. Ele classifica, justifica e sugere nomes de ferramenta. A
CommandFactorye o unico ponto onde uma sugestao vira acao e opera por lista de permissao — ferramenta alucinada e descartada com registro em log, nunca interpretada. Ha teste cobrindo esse caso.A barreira de aprovacao e redundante de proposito. O State so libera a transicao para contencao apos decisao humana, e o
CommandInvokerrecusa comandos aprovaveis fora dessa fase. Se um planejador futuro esquecer de marcar uma acao como destrutiva, a outra camada ainda barra.Falha degrada para revisao humana. Modelo indisponivel, resposta fora do formato ou classificacao desconhecida resultam em
NEEDS_HUMAN_REVIEW.Licenciamento
Toda a pilha e software livre. O modelo padrao e o Qwen 2.5 7B, sob Apache 2.0 — licenca aprovada pela OSI. O Llama 3.1 funciona igualmente bem, mas sua licenca e source-available, com restricao de uso acima de 700 milhoes de usuarios mensais.
Verificacao
Limitacao conhecida e documentada
O cenario "Backup noturno" e uma transferencia legitima em janela de manutencao. O Qwen 2.5 7B classifica como verdadeiro positivo com confianca 0,80 e propoe isolar o servidor de backup.
O comportamento esta documentado no README como resultado medido, nao corrigido artificialmente. Com autonomia total o agente derrubaria a infraestrutura de backup durante a manutencao; a barreira de aprovacao impede o estrago. A causa raiz e ausencia de enriquecimento — o agente nao sabe que
BKP-SRV-01e servidor de backup nem que existe janela aprovada. Inventario de ativos e calendario de mudancas no prompt resolvem, e ficam registrados como evolucao.Como testar