Sobre a análise incremental
As verificações completas CodeQL em cada solicitação de pull podem ser lentas, especialmente em grandes bases de código. Se você executar o CodeQL CLI no seu próprio sistema de CI/CD, a análise incremental oferece duas maneiras de acelerar o processo:
- A análise informada por Diff relata apenas alertas em linhas que você adicionou ou alterou, portanto, as consultas são executadas mais rapidamente e os resultados são mais relevantes.
- A análise de sobreposição reutiliza um banco de dados armazenado em cache do branch padrão em vez de criar um do zero, reduzindo drasticamente o tempo de criação e avaliação de consulta do banco de dados.
Você pode usar esses recursos de forma independente ou em conjunto. Para a maioria das equipes que analisam solicitações de pull em bases de código estabelecidas, é recomendável usar ambos: análise de sobreposição para criação rápida de banco de dados e avaliação de consulta e análise informada por diferenciação para resultados focados e relevantes.
Se você usar code scanning configuração padrão ou o codeql-action em GitHub, a análise incremental já é tratada automaticamente. Este artigo destina-se às equipes que executam diretamente CodeQL CLI em sua própria infraestrutura de CI/CD.
Pré-requisitos
Antes de configurar a análise incremental, verifique se você atende aos seguintes requisitos:
- CodeQL CLI versão do pacote: 2.21.0 ou posterior para análise informada por diferenciação; 2.23.8 ou posterior para análise de sobreposição (com mínimos por idioma, consulte versões mínimas do pacote da CLI)
- A raiz de origem deve estar dentro de um repositório Git
- Git versão 2.38.0 ou posterior (necessária para análise de sobreposição, especificamente a opção
--formatusada porgit ls-files) - Todos os arquivos de interesse devem ser acompanhados pelo Git (não em
.gitignore) - O índice Git deve refletir com precisão a árvore de origem que está sendo analisada
- Modo de build: A análise de sobreposição oferece suporte apenas a
build-mode: none(builds rastreados não são compatíveis). O Go funciona com a análise de sobreposição, apesar de não dar suporte explicitamente a esse modo.
Escolhendo uma abordagem
| Scenario | Baseado em diff | Sobreposição |
|---|---|---|
| Push para a ramificação padrão | Não (não é uma PR) | modo base de sobreposição |
| Análise de PR (primeira vez, sem cache) | Yes | Não (executar análise completa) |
| Análise de PR (com base em cache) | Yes | modo de sobreposição |
| Ramificação sem pull request e não padrão | No | No |
Para obter exemplos completos e funcionais em vários sistemas de CI, consulte o repositório de configurações de exemplo de pipeline do CodeQL.
Análise informada por difusão
A análise informada por Diff é uma otimização para análise de solicitação de pull. Em vez de informar todos os alertas encontrados na base de código, ele informa apenas os alertas nas linhas que foram adicionadas ou modificadas no diff do pull request.
Etapa 1: identificar os intervalos de diferenciação
Você precisa dos intervalos de linhas adicionadas ou modificadas no diff da pull request. A entrada pode vir de qualquer origem (git diffa API da plataforma de CI ou outro mecanismo).
Para cada arquivo alterado, produza uma lista de intervalos com a seguinte estrutura:
path: caminho de arquivo absoluto (sempre use barras para frente)startLine: linha inicial inclusiva baseada em 1endLine: linha final inclusiva e baseada em 1
Por exemplo, dada essa diferença unificada (gerada por git diff):
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -2,7 +2,6 @@ import { helper } from './helper';
function existing() {
const x = 1;
- const unused = 2;
return x;
}
@@ -14,6 +13,8 @@ function validate(input: string) {
function process(input: string) {
// validate
if (!input) return;
+ const sanitized = input.trim();
+ console.log(sanitized);
return input;
}
@@ -23,5 +24,5 @@ function format(value: number) {
function render(data: object) {
const output = JSON.stringify(data);
- return output;
+ return `<div>${output}</div>`;
}
Os intervalos de diff resultantes para src/utils.ts seriam:
["/path/to/repo/src/utils.ts", 16, 17](as duas linhas inseridas no segundo pedaço)["/path/to/repo/src/utils.ts", 27, 27](a linha modificada no terceiro pedaço)
O primeiro pedaço contém apenas uma exclusão, portanto, ele não produz nenhum intervalo. Observe que os intervalos usam os números de linha "para" (novo arquivo), não os números "de" (arquivo antigo).
Casos especiais:
- Arquivos binários ou diffs muito grandes (sem conteúdo de patch disponível): use o intervalo sentinela
{path, startLine: 0, endLine: 0}para indicar "o arquivo inteiro". - Arquivos renomeados sem alterações de conteúdo: retornar uma matriz vazia (sem intervalos).
- Difusões truncadas: se a fonte de diferenciação estiver incompleta para solicitações de pull grandes (por exemplo, uma API que limita o número de arquivos alterados), você deve ignorar a análise informada por diferenciação e executar a análise completa para essa execução.
Para uma implementação de referência da análise de diff, consulte getDiffRanges() no código-fonte codeql-action.
Etapa 2: Criar um pacote de extensão de dados
Crie um diretório temporário contendo dois arquivos. Esse pacote de extensão se integra ao predicado extensível restrictAlertsTo definido na biblioteca padrão CodeQL.
**
qlpack.yml:**
name: my-ci/pr-diff-range
version: 0.0.0
library: true
extensionTargets:
codeql/util: '*' # Target the codeql/util pack where restrictAlertsTo is defined
dataExtensions:
- pr-diff-range.yml
**
pr-diff-range.yml:**
extensions:
- addsTo:
pack: codeql/util
extensible: restrictAlertsTo
checkPresence: false # Don't error if the predicate doesn't exist in older CLI versions
data:
# Each row: [filePath, startLine, endLine]
- ["/path/to/repo/src/utils.ts", 16, 17]
- ["/path/to/repo/src/utils.ts", 27, 27]
Cada linha de dados é [filePath, lineStart, lineEnd]. Os números de linha são baseados em 1. O caso especial lineStart = 0, lineEnd = 0 indica uma correspondência em todo o arquivo.
Importante
Se o diff tiver zero linhas adicionadas ou modificadas (por exemplo, apenas exclusões), você ainda deve fornecer uma extensão de dados não vazia com uma entrada sentinela ["", 0, 0]. Uma seção data vazia deixaria o predicado restrictAlertsTo inativo, o que significa que todos os alertas seriam gerados — o oposto do comportamento desejado.
Etapa 3: passar o pacote de extensão para o CodeQL CLI
Ao executar consultas, adicione os seguintes sinalizadores a codeql database run-queries:
codeql database run-queries \
--additional-packs=PATH_TO_EXTENSION_PACK \
--extension-packs=my-ci/pr-diff-range \
PATH_TO_DATABASE \
QUERIES
--additional-packsinforma CodeQL onde encontrar o pacote no disco. Para obter mais informações, consulte executar consultas no banco de dados.--extension-packsinstrui CodeQL a carregar o pacote de extensões especificado.
Etapa 4: Excluir consultas de diagnóstico
Ao usar a análise informada por difusão, você deve excluir consultas marcadas com exclude-from-incremental. Essas consultas de diagnóstico não produzem alertas (por exemplo, métricas ou cobertura de código), portanto, não fornecem valor em um contexto incremental, mas ainda consomem recursos.
Você pode adicionar isso ao arquivo de configuração de verificação de código:
query-filters:
- exclude:
tags: exclude-from-incremental
Como alternativa, crie um arquivo do conjunto de consultas (.qls) que exclua essas consultas:
- description: Pull request queries for Java
- import: codeql-suites/java-code-scanning.qls
from: codeql/java-queries
- exclude:
tags contain: exclude-from-incremental
Para obter mais informações, consulte Opções de configuração de fluxo de trabalho para verificação de código.
Etapa 5: Filtrar a saída SARIF
Depois CodeQL de gerar o arquivo SARIF, você deve filtrar a saída no lado da CI para remover resultados cujos locais estão fora dos intervalos de diferenciação.
Para cada resultado no SARIF, verifique se algum deles locations ou relatedLocations se cruza com um intervalo de diferenciação para esse arquivo. Uma posição intersecta um intervalo quando range.startLine <= location.endLine e location.startLine <= range.endLine. O caso especial range.startLine == range.endLine == 0 corresponde a qualquer localização no arquivo. Verifique se os locais do artefato SARIF são resolvidos para o mesmo formato de caminho absoluto usado nos intervalos de diferenciação antes da comparação.
O predicado restrictAlertsTo permite, mas não garante, que as consultas omitam alertas fora do intervalo, portanto a filtragem no lado da CI é necessária para obter resultados estáveis.
Para ver uma implementação de referência para filtragem SARIF, consulte filterAlertsByDiffRange() no código-fonte codeql-action.
Resumo dos sinalizadores da CLI para análise informada por diferenciação
| Comando da CLI | Flag | Purpose |
|---|---|---|
codeql database init | --codescanning-config=FILE | Arquivo de configuração de verificação de código (para filtro de consulta) |
codeql database run-queries | --additional-packs=DIR | Local do pacote de extensões |
codeql database run-queries | --extension-packs=my-ci/ | Nome do pacote de extensão a ser carregado |
codeql database interpret-results | --sarif-run-property=incremental | (Opcional) Marcar SARIF com metadados baseados em diff |
Análise de sobreposição
A análise em sobreposição acelera CodeQL a criação de bancos de dados e a avaliação de consultas para pull requests, com base em um banco de dados "base" pré-existente:
- Na ramificação padrão: Construa um banco de dados "overlay-base" (um banco de dados completo com resultados intermediários em cache). Essa pode ser qualquer branch de longa duração para a qual as pull requests são direcionadas.
- Em solicitações de pull: Baixe o banco de dados base de sobreposição em cache e crie um banco de dados leve de "sobreposição" que processa apenas os arquivos alterados.
Modo de base de sobreposição (ramificação padrão)
Execute o modo overlay-base na sua branch de destino padrão ou de longa duração após cada mesclagem para gerar e armazenar em cache um banco de dados base.
1. Inicializar o banco de dados com --overlay-base
codeql database init \
--overlay-base \
--db-cluster \
PATH_TO_DATABASE \
--source-root=PATH_TO_SOURCE \
--language=LANGUAGE
A opção --overlay-base indica a CodeQL que crie um banco de dados que possa servir como base para futuras análises de sobreposição.
2. Compilar e extrair normalmente
Execute as etapas de build e a extração como faria normalmente para seu projeto.
3. Registrar OIDs de arquivo
Após a conclusão da extração, registre os IDs de objeto do Git (OIDs) de todos os arquivos rastreados sob a raiz de origem. Execute este comando no diretório raiz de origem (PATH_TO_SOURCE). Esse instantâneo é usado posteriormente para determinar quais arquivos foram alterados.
cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'
Analise essa saída em um mapa { "relative/path": "git-oid" } JSON e armazene-a junto com o banco de dados. A saída inclui arquivos em submódulos do Git, o que exige que a análise de sobreposição rastreie com precisão todas as alterações nos arquivos entre a base e a sobreposição.
4. Executar consultas e preservar o cache
Ao executar consultas em um banco de dados de base de sobreposição, não passe --expect-discarded-cache. Os resultados intermediários armazenados em cache são o que torna as compilações de solicitação de pull rápidas. Descartá-los forçaria a reavaliação completa em cada PR.
5. Limpar e armazenar em cache o banco de dados
Após a análise, limpe o banco de dados usando o nível de limpeza overlay:
codeql database cleanup PATH_TO_DATABASE --cache-cleanup=overlay
O overlay nível de limpeza preserva mais dados armazenados em cache do que o nível padrão clear . O modo de sobreposição reutiliza esses dados armazenados em cache para uma avaliação de consulta eficiente em solicitações de pull, portanto, descartá-los eliminaria o benefício de desempenho.
Em seguida, armazene o banco de dados (incluindo o arquivo OIDs) em seu sistema de cache para recuperação posterior por builds de solicitação de pull.
Modo de sobreposição (solicitações de pull)
Execute o modo de sobreposição em builds de solicitação de pull para criar um banco de dados leve na parte superior da base armazenada em cache. Se nenhum banco de dados base de sobreposição compatível estiver disponível no cache (por exemplo, na primeira execução ou após uma CodeQL CLI atualização de versão), ignore --overlay-changes e execute uma análise completa normal. As chaves de cache devem incluir pelo menos a versão e o CodeQL CLI conjunto de idiomas para evitar bancos de dados base incompatíveis.
1. Baixe o banco de dados overlay-base armazenado em cache
Recupere o banco de dados base de sobreposição mais recente do cache. O banco de dados deve incluir o arquivo de OIDs registrado durante o modo overlay-base.
2. Calcular arquivos alterados
Compare os OIDs registrados no banco de dados base com o estado git atual. Execute este comando no mesmo diretório raiz de origem (PATH_TO_SOURCE) usado durante o modo base de sobreposição:
cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'
Compare os dois mapas para localizar arquivos que foram adicionados, removidos ou modificados (OID diferente). Escreva o resultado como um arquivo JSON:
{
"changes": ["src/modified-file.ts", "src/new-file.ts", "src/deleted-file.ts"]
}
Os caminhos de arquivo devem ser relativos à raiz de origem.
3. Inicializar o banco de dados com --overlay-changes
Execute codeql database init no diretório do banco de dados overlay-base restaurado. O PATH_TO_DATABASE deve apontar para o banco de dados de base de sobreposição em cache restaurado, não um novo diretório vazio– o comando estende a base existente para a análise de solicitação de pull.
codeql database init \
--overlay-changes=PATH_TO_OVERLAY_CHANGES_JSON \
--db-cluster \
PATH_TO_DATABASE \
--source-root=PATH_TO_SOURCE \
--language=LANGUAGE
Importante
No modo de sobreposição, não passe --overwrite ou --force-overwrite. Você está desenvolvendo sobre o banco de dados base em cache existente, não o substituindo.
4. Criar, extrair e executar consultas normalmente
Prossiga com a execução de build, extração e consulta normalmente. Você pode adicionar o sinalizador --sarif-run-property ao seu comando codeql database interpret-results existente para marcar a saída SARIF com metadados de sobreposição:
codeql database interpret-results \
--format=sarif-latest \
--output=results.sarif \
--sarif-run-property=incrementalMode=overlay \
PATH_TO_DATABASE \
QUERIES_OR_SUITES
Se tanto a sobreposição quanto a análise baseada em diff estiverem ativas, use incrementalMode=overlay,diff-informed.
Os alertas da análise incremental aparecem nos resultados da varredura de código do pull request da mesma forma que os alertas das varreduras completas. Qualquer banco de dados base de sobreposição funcionará independentemente da idade, mas bases mais recentes produzem resultados mais rápidos e precisos.
Assim como na análise baseada em diff, exclua as consultas marcadas com exclude-from-incremental ao usar o modo de sobreposição. Para obter detalhes, consulte a Etapa 4: Excluir consultas de diagnóstico.
Resumo dos sinalizadores da CLI para análise de sobreposição
| Comando da CLI | Flag | Mode | Purpose |
|---|---|---|---|
codeql database init | --codescanning-config=FILE | sobreposição | Arquivo de configuração de verificação de código (para filtro de consulta) |
codeql database init | --overlay-base | overlay-base | Criar um banco de dados básico para uso futuro em sobreposições |
codeql database init | --overlay-changes=FILE | sobreposição | Criar banco de dados de sobreposição usando apenas arquivos alterados |
codeql database init | |||
(não --overwrite) | sobreposição | Não substitua o banco de dados base armazenado em cache | |
codeql database run-queries | |||
(não --expect-discarded-cache) | overlay-base | Preservar resultados intermediários armazenados em cache | |
codeql database cleanup | --cache-cleanup=overlay | overlay-base | Usar o nível de limpeza específico da sobreposição |
codeql database interpret-results | --sarif-run-property=incremental | sobreposição | Marcar SARIF com metadados de sobreposição |
Versões mínimas do pacote da CLI
A versão mínima base para análise de sobreposição é 2.23.8. Alguns idiomas exigem versões mínimas mais altas:
| Linguagem | Versão mínima CodeQL CLI do pacote |
|---|---|
| C/C++ | 2.25.0 |
| C# | 2.24.1 |
| Go | 2.24.2 |
| Java | 2.23.8 |
| JavaScript | 2.23.9 |
| Python | 2.23.9 |
| Ruby | 2.23.9 |