Início tecnologia

Necessist: auditoria de testes open source com IA

Um teste que passa pode não estar verificando nada. O Necessist é uma ferramenta open source da Trail of Bits, escrita em Rust, que remove uma instrução ou uma chamada de método do teste, roda tudo de novo e compara o resultado. Se o teste continua passando sem aquela linha, algo ali pode estar errado. No experimento descrito no paper do projeto, arquivos de teste da biblioteca padrão do Go mostraram casos em que bastava apagar uma chamada de sincronização para o teste continuar verde e esconder uma falha. A auditoria dos resultados que passaram pode ser feita com apoio de um modelo de linguagem, em um recurso que o repositório marca como experimental. Quem acompanha o blog já viu o Harness Engineering, que trata de garantir que código escrito por agentes de IA seja confiável. O Necessist olha para uma etapa anterior, o próprio teste. O projeto está sob licença AGPL-3.0.

Braço robótico removendo um bloco de código de uma torre que continua em pé, com uma rachadura vermelha visível no interior
Imagem gerada usando o Magnific

O que é o Necessist

A ferramenta faz uma pergunta objetiva sobre cada trecho de um teste: o que muda se esta linha desaparecer? O paper chama o método de mutilação do harness de testes. Ele remove instruções e chamadas de método uma a uma, sempre do próprio teste e nunca do código de produção. O trabalho saiu no paper Test Harness Mutilation, de Samuel Moelius, da Trail of Bits. Ele foi apresentado no Mutation 2024, workshop do ICST 2024, e publicado nos proceedings do 2024 IEEE International Conference on Software Testing, Verification and Validation Workshops (ICSTW), com DOI 10.1109/ICSTW60967.2024.00053. O repositório existe desde novembro de 2020 e continua recebendo commits.

O mutation testing convencional, feito por ferramentas como cargo-mutants (licença MIT, 1.317 estrelas em 30 de setembro de 2026), StrykerJS (Apache-2.0, 3.159 estrelas) e mutmut (BSD-3-Clause, 1.459 estrelas), injeta falhas no código de produção para medir buracos na suíte como um todo. O Necessist mira outro alvo: o teste individual. O README trata as duas abordagens como complementares e cita o Universal Mutator como exemplo de mutador geral que já existia.

O projeto tem alcance de nicho e recebe manutenção regular: 149 estrelas e 21 forks em 30 de setembro de 2026, 63.558 downloads acumulados no crates.io e 14 contas com contribuições registradas, entre elas o dependabot. As versões saem em ritmo curto: a 4.0.0 foi publicada em 15 de agosto de 2026, a 4.0.1 em 15 de setembro e a 4.1.0 em 24 de setembro de 2026, a release mais recente até o fechamento deste texto.

Tecnologia e mutilação determinística

Cada arquivo de teste passa primeiro por uma execução sem alterações. Se já falha, a ferramenta avisa e segue adiante, porque não dá para atribuir a falha à remoção. Depois, cada trecho elegível é retirado, o teste é recompilado e executado com timeout padrão de 60 segundos; o parâmetro --timeout muda esse limite e --timeout 0 desativa o corte. O resultado cai em quatro estados: passou, estourou o tempo, falhou ou não compilou. Só o primeiro interessa, e nem ele prova um bug. A operação pode ser redundante ou a checagem pode estar em outro lugar.

Declarações, laços e outras instruções que contêm instruções, comandos como break, continue e return, asserções e a última linha do teste ficam de fora. Certas funções, métodos e macros são ignorados conforme o backend, e essas listas variam bastante entre Go, Python, Rust, PHP e os demais frameworks. O projeto justifica a escolha com weakest preconditions, sem calcular essas condições formalmente. Não há sorteio: como existe um único tipo de mutação, a remoção, a varredura é exaustiva. No experimento do paper, os conjuntos ficaram em alguns milhares de candidatos em arquivos de algumas dezenas de milhares de linhas.

No experimento com a biblioteca padrão do Go, 139 commits que corrigiam testes viraram 144 arquivos, contabilizados como 200 arquivos por causa das repetições. Cada um rodou antes e depois da correção, num total de 400 execuções. O maior conjunto de candidatos veio de cmd/go/go_test.go, com 4.280 remoções possíveis em 6.250 linhas. O caso mais demorado foi net/http/transport_test.go, com cerca de 2,8 horas por execução. Em net/smtp, a remoção de wg.Add(1) ainda deixava o teste passar, e a correção trocou o mecanismo por um canal de erro. Um dos exemplos que o próprio README destaca veio do rust-openssl: o teste verify_untrusted_callback_override_ok continuava passando sem a chamada a set_verify_callback, porque o callback podia nunca ser executado. A correção incluiu um sinalizador e uma verificação explícita de que o callback tinha sido chamado. Há ainda uma mudança de comportamento a considerar: desde a versão 4.0.0, arquivos ocultos ou ignorados deixaram de ser percorridos, por causa da troca do caminhador de arquivos, e testes fora dessa árvore não entram na análise. Esse é o limite que o próprio projeto declara: o teste é recompilado a cada remoção e a rodada pode levar várias horas.

Recursos já existentes

Na versão 4.1.0, a mais recente, a ferramenta oferece mais que a remoção de trechos isolados. Também há opções para reduzir ruído e retomar trabalho interrompido.

  • Oito backends documentados: Rust, Go, Python com pytest, PHP, Anchor, Foundry, Hardhat e Vitest. O suporte a Python com pytest entrou na versão 4.1.0, de 24 de setembro de 2026, e é o motivo da inconsistência do resumo do README, que ainda enumera sete frameworks.
  • Resultados gravados em SQLite no arquivo necessist.db, com --dump para despejar, --resume para retomar e --reset para apagar.
  • Arquivo necessist.toml na raiz do projeto para ignorar funções, métodos, macros e testes por nome, além de percorrer funções declaradas no mesmo arquivo.
  • Diretivas de código // necessist: skip e // necessist: skip-file, marcadas como experimentais.
  • Auditoria assistida por LLM, experimental, e limite de tempo por teste ajustável com --timeout.
  • Opções de linha de comando para tratar avisos como erro com --deny, silenciar com --allow e contar candidatos por arquivo com --dump-candidate-counts.

Auditoria assistida por IA

A skill necessist-audit entrou na versão 3.2.0, de julho de 2026, e segue marcada como experimental. Ela vem embutida no próprio binário e investiga se uma remoção que passou indica bug no teste ou no código testado. Exige acesso ao shell e o comando necessist no PATH, e lê os resultados com necessist --dump. Se o arquivo necessist.db não existir no diretório, a própria skill instrui o agente a rodar o Necessist para gerá-lo antes da auditoria. A instalação no Claude Code é necessist --check-skill ~/.claude/skills/necessist-audit/SKILL.md --write, com o caminho equivalente para o Codex. A opção --find-skill procura a skill nos diretórios conhecidos e atualiza as instalações existentes, mas não instala diretórios ausentes; para instalar, o caminho é --check-skill com o argumento --write.

Na análise, o modelo só pode olhar remoções cujo resultado foi passou. A instrução manda examinar o teste inteiro, inferir o comportamento pretendido, procurar evidência no código e nos chamadores e considerar explicações benignas, como idempotência, setup duplicado, não determinismo e estado persistente. A classificação é formal: só vira finding, o achado, quando contrato ou invariante, mecanismo causal e evidência ligada à remoção estão estabelecidos. Se faltar qualquer item, o resultado fica como lead, uma pista, com a indicação do que falta provar. Antes de reportar, a skill confere se a localização e o código removido ainda correspondem ao checkout atual; quando não correspondem, o resultado é marcado como desatualizado e o Necessist precisa rodar de novo. O README não informa qual modelo usar, quanto custa nem como os dados enviados ao provedor são tratados.

Principais dúvidas sobre o projeto

O Necessist encontra bugs automaticamente?

Não. A remoção que passa gera um candidato, e a confirmação depende de quem conhece o código. O README afirma que a ferramenta normalmente não produz bugs óbvios e que a triagem exige conhecimento íntimo do código-fonte. O paper lista três tipos comuns de falso positivo: configuração do teste, chamadas que fazem checagens e testes subordinados chamados dentro de outro teste.

O que é preciso para rodar?

Toolchain Rust com Cargo, pkg-config e os arquivos de desenvolvimento do SQLite, que no Ubuntu saem com sudo apt install pkg-config libsqlite3-dev. A instalação é cargo install necessist e a execução acontece no diretório do projeto. O changelog do projeto registra suporte limitado ao Windows, e o README não documenta Windows nem WSL como plataformas suportadas. A execução básica não depende de serviço pago.

Quanto tempo leva?

Cada remoção roda com timeout padrão de 60 segundos, ajustável com --timeout, e o teste é recompilado a cada tentativa. O README avisa que bases moderadas podem levar várias horas, e o paper registrou cerca de 2,8 horas para um único arquivo de teste da biblioteca padrão do Go.

A auditoria com IA tem custo?

O README não informa provedor, modelo, preço nem política de retenção dos dados. Como o recurso é opcional e está marcado como experimental, o eventual custo depende do agente ou do modelo usado, e nada indica cobrança adicional pelo Necessist em si.

Serve para substituir o mutation testing convencional?

Não. O projeto trata as duas abordagens como complementares, e o relatório do OSTIF sobre o Istio Ztunnel mostra a diferença na prática: o cargo-mutants deixou 418 mutantes sobreviverem, de 1.841 gerados, e o Necessist não encontrou testes quebrados no mesmo alvo. Os mutantes sobreviventes apontam lacunas na suíte; o Necessist procura outro tipo de problema, o teste que não verifica o que promete.

O Necessist parte de uma pergunta simples: se a linha desaparece e o teste continua verde, vale investigar. A resposta vem dos dados, não de uma promessa. Para quem mantém uma suíte grande, o caminho mais prudente é começar por um diretório pequeno, ler os resultados no SQLite e só depois avaliar a auditoria por IA. O código está aberto sob AGPL-3.0, e quem precisa de exceção de licença tem de falar com a Trail of Bits.

Links do projeto