À propos de l’analyse incrémentielle
Les analyses complètes CodeQL sur chaque pull request peuvent être lentes, en particulier dans les bases de code volumineuses. Si vous exécutez CodeQL CLI dans votre propre système CI/CD, l’analyse incrémentielle vous permet d’accélérer les choses de deux façons :
- Analyse basée sur les différences signale uniquement les alertes dans les lignes que vous avez ajoutées ou modifiées, afin que les requêtes s’exécutent plus rapidement et que les résultats soient plus pertinents.
- L’analyse de superposition réutilise une base de données mise en cache à partir de votre branche par défaut au lieu de créer une base de données à partir de zéro, ce qui réduit considérablement la création de la base de données et le temps d’évaluation des requêtes.
Vous pouvez utiliser ces fonctionnalités indépendamment ou ensemble. Pour la plupart des équipes analysant les demandes de tirage dans des bases de code établies, nous vous recommandons d’utiliser à la fois l’analyse de superposition pour la création rapide de bases de données et l’évaluation des requêtes, ainsi que l’analyse diff-informée pour les résultats ciblés et pertinents.
Si vous utilisez la configuration par défaut code scanning ou l’option codeql-action sur GitHub, l’analyse incrémentielle est déjà gérée automatiquement. Cet article s’adresse aux équipes qui exécutent directement le CodeQL CLI dans leur propre infrastructure CI/CD.
Prerequisites
Avant de configurer l’analyse incrémentielle, veillez à répondre aux exigences suivantes :
- CodeQL CLI version du bundle : 2.21.0 ou version ultérieure pour l’analyse basée sur les différences ; 2.23.8 ou version ultérieure pour l’analyse par superposition (avec des versions minimales par langue, voir Versions minimales du bundle CLI)
- La racine source doit se trouver à l’intérieur d’un référentiel Git
- Git version 2.38.0 ou ultérieure (requis pour l’analyse de superposition, en particulier l’option
--formatutilisée pargit ls-files) - Tous les fichiers d’intérêt doivent être suivis par Git (pas dans
.gitignore) - L’index Git doit refléter avec précision l’arborescence source analysée
- Mode build : L’analyse de superposition prend uniquement
build-mode: noneen charge (les builds tracées ne sont pas prises en charge). Go fonctionne avec l’analyse par superposition bien qu’il ne prenne pas explicitement en charge ce mode.
Choix d’une approche
| Scénario | Diff-informa ment | Overlay |
|---|---|---|
| Push de branche par défaut | Non (pas une demande de tirage) | mode de base de superposition |
| Analyse des PR (première exécution, sans cache) | Yes | Non (exécuter l’analyse complète) |
| Analyse de PR (avec la base en cache) | Yes | mode superposition |
| Branche non-PR, autre que la branche par défaut | No | No |
Pour obtenir des exemples complets et fonctionnels dans différents systèmes CI, consultez le dépôt exemples de configurations de pipeline CodeQL.
Analyse basée sur les différences
L’analyse basée sur les diffs est une optimisation pour l’analyse des pull requests. Au lieu de signaler toutes les alertes trouvées dans la base de code, elle signale uniquement les alertes présentes sur les lignes ajoutées ou modifiées dans le diff de la pull request.
Étape 1 : Identifier les plages de différences
Vous avez besoin des plages de lignes ajoutées ou modifiées à partir du diff de la pull request. L’entrée peut provenir de n’importe quelle source (git diffAPI de votre plateforme CI ou d’un autre mécanisme).
Pour chaque fichier modifié, produisez une liste de plages avec la structure suivante :
path: chemin d’accès absolu au fichier (utilisez toujours des slashs)startLine: ligne de début incluse, indexée à partir de 1endLine: ligne de fin incluse, indexée à partir de 1
Par exemple, étant donné ce diff unifié (généré par 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>`;
}
Les plages de diff résultantes pour src/utils.ts seraient :
["/path/to/repo/src/utils.ts", 16, 17](les deux lignes insérées dans le deuxième segment)["/path/to/repo/src/utils.ts", 27, 27](ligne modifiée dans le troisième bloc)
Le premier bloc contient uniquement une suppression. Il ne produit donc aucune plage. Notez que les plages utilisent les numéros de ligne « to » correspondant au nouveau fichier, et non les numéros de ligne « from » correspondant à l’ancien fichier.
Cas spéciaux :
- Fichiers binaires ou différences très volumineuses (aucun contenu de correctif disponible) : utilisez la plage
{path, startLine: 0, endLine: 0}sentinelle pour indiquer « fichier entier ». - Fichiers renommés sans modification de contenu : renvoyer un tableau vide (aucune plage).
- Diffs tronqués : si votre source de diffs est incomplète pour les pull requests volumineuses (par exemple, une API qui limite le nombre de fichiers modifiés), vous devez ignorer l’analyse basée sur les diffs et exécuter une analyse complète pour cette exécution.
Pour obtenir une implémentation de référence de l’analyse des différences, consultez getDiffRanges() le codeql-action code source.
Étape 2 : Créer un pack d’extensions de données
Créez un répertoire temporaire contenant deux fichiers. Ce pack d’extension alimente le restrictAlertsTo prédicat extensible défini dans la CodeQL bibliothèque standard.
**
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]
Chaque ligne de données est [filePath, lineStart, lineEnd]. Les numéros de ligne commencent à 1. Le cas lineStart = 0, lineEnd = 0 spécial désigne une correspondance dans un fichier entier.
Important
Si le diff ne comporte aucune ligne ajoutée ou modifiée (par exemple, uniquement des suppressions), vous devez tout de même fournir une extension de données non vide avec une entrée sentinelle ["", 0, 0]. Une section vide data laisserait le restrictAlertsTo prédicat inactif, ce qui signifie que toutes les alertes seraient produites, à l’opposé du comportement souhaité.
Étape 3 : Passer le pack d’extension au CodeQL CLI
Lors de l’exécution de requêtes, ajoutez les indicateurs suivants à 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-packsindique CodeQL où trouver le pack sur le disque. Pour plus d’informations, consultez « requêtes d’exécution de base de données ».--extension-packsindique CodeQL de charger le pack d’extension nommé.
Étape 4 : Exclure les requêtes de diagnostic
Lorsque vous utilisez une analyse diff-informée, vous devez exclure les requêtes marquées avec exclude-from-incremental. Ces requêtes de diagnostic ne produisent pas d’alertes (par exemple, des métriques ou une couverture du code), de sorte qu’elles ne fournissent aucune valeur dans un contexte incrémentiel, mais consomment toujours des ressources.
Vous pouvez l’ajouter à votre fichier de configuration d’analyse du code :
query-filters:
- exclude:
tags: exclude-from-incremental
Vous pouvez également créer un fichier de suite de requêtes (.qls) qui exclut ces requêtes :
- description: Pull request queries for Java
- import: codeql-suites/java-code-scanning.qls
from: codeql/java-queries
- exclude:
tags contain: exclude-from-incremental
Pour plus d’informations, consultez « Options de configuration de flux de travail pour l’analyse du code ».
Étape 5 : Filtrer la sortie SARIF
Après CodeQL avoir généré le fichier SARIF, vous devez filtrer la sortie côté CI pour supprimer les résultats dont les emplacements se trouvent en dehors des plages de différences.
Pour chaque résultat du SARIF, vérifiez si l’un de ses locations ou relatedLocations intersecte une plage de différences pour ce fichier. Une position intersecte un intervalle lorsque range.startLine <= location.endLine et location.startLine <= range.endLine. Le cas range.startLine == range.endLine == 0 spécial correspond à n’importe quel emplacement dans le fichier. Assurez-vous que les emplacements des artefacts SARIF sont résolus dans le même format de chemin absolu que celui utilisé dans les plages de diff avant de comparer.
Le restrictAlertsTo prédicat permet, sans toutefois garantir, que les requêtes omettent les alertes en dehors de la plage, donc un filtrage côté CI est nécessaire pour obtenir des résultats stables.
Pour une implémentation de référence du filtrage SARIF, consultez filterAlertsByDiffRange() dans le code source codeql-action.
Synthèse des options de ligne de commande pour l’analyse basée sur les différences
| Commande CLI | Flag | Purpose |
|---|---|---|
codeql database init | --codescanning-config=FILE | Fichier de configuration de l’analyse du code (pour le filtre de requête) |
codeql database run-queries | --additional-packs=DIR | Emplacement du pack d’extension |
codeql database run-queries | --extension-packs=my-ci/ | Nom du pack d’extension à charger |
codeql database interpret-results | --sarif-run-property=incremental | (Facultatif) Balise SARIF avec des métadonnées diff-informées |
Analyse de superposition
L’analyse de superposition accélère la CodeQL création de la base de données et l’évaluation des requêtes pour les demandes d’extraction en s’appuyant sur une base de données « base » préexistante :
- Dans la branche par défaut : Créer une base de données « overlay-base » (une base de données complète avec mise en cache des résultats intermédiaires). Il peut s’agir de n’importe quelle branche de longue durée que ciblent les pull requests.
- Pour les pull requests : Téléchargez la base de données overlay-base en cache, puis créez une base de données overlay légère qui traite uniquement les fichiers modifiés.
Mode de base de superposition (branche par défaut)
Exécutez le mode de base de superposition sur votre branche cible par défaut ou de longue durée après chaque fusion pour créer et mettre en cache une base de données de base.
1. Initialiser la base de données avec --overlay-base
codeql database init \
--overlay-base \
--db-cluster \
PATH_TO_DATABASE \
--source-root=PATH_TO_SOURCE \
--language=LANGUAGE
L’indicateur --overlay-base indique CodeQL de créer une base de données qui peut servir de base pour l’analyse future des superpositions.
2. Compiler et extraire comme d’habitude
Exécutez les étapes de génération et l’extraction comme vous le feriez normalement pour votre projet.
3. Enregistrer les OID du fichier
Une fois l’extraction terminée, enregistrez les ID d’objet Git (OID) de tous les fichiers suivis sous la racine source. Exécutez cette commande à partir de votre répertoire racine source (PATH_TO_SOURCE). Cet instantané est utilisé ultérieurement pour déterminer les fichiers modifiés.
cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'
Analysez cette sortie sous forme de mappage JSON de { "relative/path": "git-oid" } et stockez-la avec la base de données. La sortie inclut des fichiers dans les sous-modules Git, que l’analyse de la couche de superposition doit suivre avec précision afin de prendre en compte toutes les modifications apportées aux fichiers entre la base et la couche de superposition.
4. Exécuter des requêtes et conserver le cache
Lors de l’exécution de requêtes sur une base de données overlay-base, ne pas transmettre --expect-discarded-cache. Les résultats intermédiaires mis en cache sont ce qui rend les builds de pull request rapides. Les supprimer imposerait une réévaluation complète à chaque PR.
5. Nettoyer et mettre en cache la base de données
Après analyse, nettoyez la base de données à l’aide du overlay niveau de nettoyage :
codeql database cleanup PATH_TO_DATABASE --cache-cleanup=overlay
Le overlay niveau de nettoyage conserve plus de données mises en cache que le niveau par défaut clear . Le mode de superposition réutilise ces données mises en cache pour évaluer efficacement les requêtes sur les pull requests ; les supprimer ferait donc disparaître le gain de performances.
Stockez ensuite la base de données (y compris le fichier OIDs) dans votre système de mise en cache pour pouvoir la récupérer ultérieurement lors des builds de pull request.
Mode superposition (demandes de tirage)
Exécutez le mode overlay pour les builds de pull request afin de créer une base de données légère sur la base mise en cache. Si aucune base de données de base de superposition compatible n’est disponible dans le cache (par exemple, lors de la première exécution ou après une CodeQL CLI mise à niveau de version), ignorez --overlay-changes et exécutez plutôt une analyse complète normale. Les clés de cache doivent inclure au moins la version et la CodeQL CLI langue définies pour éviter les bases de données de base incompatibles.
1. Télécharger la base de données de base de superposition mise en cache
Récupérez la base de données de base de superposition la plus récente à partir de votre cache. La base de données doit inclure le fichier d’OID enregistré pendant le mode de superposition de base.
2. Calcul des fichiers modifiés
Comparez les OID enregistrés dans la base de données de base avec l’état Git actuel. Exécutez cette commande à partir du même répertoire racine source (PATH_TO_SOURCE) utilisé lors du mode de superposition de base :
cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'
Comparez les deux mappages pour rechercher des fichiers qui ont été ajoutés, supprimés ou modifiés (différents OID). Écrivez le résultat sous la forme d’un fichier JSON :
{
"changes": ["src/modified-file.ts", "src/new-file.ts", "src/deleted-file.ts"]
}
Les chemins d’accès au fichier doivent être relatifs à la racine source.
3. Initialiser la base de données avec --overlay-changes
Exécutez codeql database init sur le répertoire de base de données overlay-base restauré. Le PATH_TO_DATABASE doit pointer vers la base de données overlay-base restaurée depuis le cache, et non vers un nouveau répertoire vide — la commande étend la base existante pour l’analyse des pull requests.
codeql database init \
--overlay-changes=PATH_TO_OVERLAY_CHANGES_JSON \
--db-cluster \
PATH_TO_DATABASE \
--source-root=PATH_TO_SOURCE \
--language=LANGUAGE
Important
En mode de superposition, ne transmettez ni --overwrite ni --force-overwrite. Vous créez sur la base de données de base mise en cache existante, et vous ne la remplacez pas.
4. Générer, extraire et exécuter des requêtes comme normales
Procédez à la compilation, à l’extraction et à l’exécution des requêtes comme d’habitude. Vous pouvez ajouter l’indicateur --sarif-run-property à votre commande existante codeql database interpret-results pour baliser la sortie SARIF avec des métadonnées de superposition :
codeql database interpret-results \
--format=sarif-latest \
--output=results.sarif \
--sarif-run-property=incrementalMode=overlay \
PATH_TO_DATABASE \
QUERIES_OR_SUITES
Si la superposition et l’analyse basée sur les différences sont activées, utilisez incrementalMode=overlay,diff-informed.
Les alertes de l’analyse incrémentielle apparaissent dans les résultats de l’analyse du code de la pull request de la même manière que les alertes issues d’analyses complètes. Toute base de données de superposition fonctionne indépendamment de l’âge, mais les bases plus fraîches produisent des résultats plus rapides et plus précis.
Comme avec l’analyse diff-informée, excluez les requêtes marquées exclude-from-incremental lors de l’utilisation du mode superposition. Pour plus d’informations, consultez l’étape 4 : Exclure les requêtes de diagnostic.
Résumé des indicateurs CLI pour l’analyse de superposition
| Commande CLI | Flag | Mode | Purpose |
|---|---|---|---|
codeql database init | --codescanning-config=FILE | Superposition | Fichier de configuration de l’analyse du code (pour le filtre de requête) |
codeql database init | --overlay-base | superposition de base | Créer une base de données de base pour une utilisation future de superposition |
codeql database init | --overlay-changes=FILE | Superposition | Générer une base de données de superposition à l’aide de fichiers modifiés uniquement |
codeql database init | |||
(aucun --overwrite) | Superposition | Ne remplacez pas la base de données de base mise en cache | |
codeql database run-queries | |||
(aucun --expect-discarded-cache) | superposition de base | Conserver les résultats intermédiaires mis en cache | |
codeql database cleanup | --cache-cleanup=overlay | superposition de base | Utiliser le niveau de nettoyage spécifique à la superposition |
codeql database interpret-results | --sarif-run-property=incremental | Superposition | Étiqueter SARIF avec des métadonnées de superposition |
Versions minimales du bundle CLI
La version minimale de base pour l’analyse de superposition est 2.23.8. Certaines langues nécessitent des versions minimales supérieures :
| Language | Version minimale du bundle CodeQL CLI |
|---|---|
| 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 |