Skip to main content

Verwenden der inkrementellen Analyse mit der CodeQL CLI

Erhalten Sie schnellere CodeQL Ergebnisse für Pullanforderungen, indem Sie nur das analysieren, was sich geändert hat. Die inkrementelle Analyse kann die Scanzeiten um bis zu 10x reduzieren, wenn Sie das CodeQL CLI in Ihrem eigenen CI/CD-System ausführen.

Wer kann dieses Feature verwenden?

CodeQL ist für die folgenden Repositorytypen verfügbar:

Informationen zur inkrementellen Analyse

Vollständige CodeQL-Scans für jeden Pull Request können langsam sein, insbesondere in umfangreichen Codebasen. Wenn Sie das CodeQL CLI in Ihrem eigenen CI/CD-System ausführen, bietet Ihnen die inkrementelle Analyse zwei Möglichkeiten, die Dinge zu beschleunigen:

  • Diff-informierte Analyse meldet nur Warnungen in Zeilen, die Sie hinzugefügt oder geändert haben, sodass Abfragen schneller ausgeführt werden und Ergebnisse relevanter sind.
  • Die Overlay-Analyse verwendet eine zwischengespeicherte Datenbank aus Ihrem Standard-Branch, anstatt eine Datenbank von Grund auf neu zu erstellen, wodurch die Zeit für die Datenbankerstellung und Abfrageauswertung erheblich verkürzt wird.

Sie können diese Features unabhängig oder gemeinsam verwenden. Für die meisten Teams, die Pullanforderungen in etablierten Codebasen analysieren, empfehlen wir, beides zu verwenden: Überlagerungsanalyse für schnelle Datenbankerstellung und Abfrageauswertung und diff-informierte Analyse für fokussierte, relevante Ergebnisse.

Wenn Sie die code scanning Standardkonfiguration oder die inkrementelle Analyse mit codeql-action auf GitHub verwenden, wird sie bereits automatisch durchgeführt. Dieser Artikel richtet sich an Teams, die die CodeQL CLI direkt in ihrer eigenen CI/CD-Infrastruktur ausführen.

Voraussetzungen

Stellen Sie vor dem Einrichten der inkrementellen Analyse sicher, dass Sie die folgenden Anforderungen erfüllen:

  • CodeQL CLI Bundle-Version: 2.21.0 oder neuer für diff-basierte Analyse; 2.23.8 oder neuer für Overlay-Analyse (Mindestversionen pro Sprache finden Sie unter Minimale CLI-Bundle-Versionen)
  • Quellstamm muss sich innerhalb eines Git-Repositorys befinden
  • Git-Version 2.38.0 oder neuer (erforderlich für die Overlay-Analyse, insbesondere für die von --format verwendete Option git ls-files)
  • Alle interessanten Dateien müssen von Git nachverfolgt werden (nicht in .gitignore)
  • Git-Index muss die zu analysierende Quellstruktur genau widerspiegeln.
  • Buildmodus: Die Overlay-Analyse unterstützt nur build-mode: none (Builds mit Ablaufverfolgung werden nicht unterstützt). Go funktioniert mit der Überlagerungsanalyse, obwohl dieser Modus nicht explizit unterstützt wird.

Auswählen eines Ansatzes

ScenarioDiff-informiertOverlay
Standardverzweigungs-PushNein (keine PR)Overlay-Basismodus
PR-Analyse (zum ersten Mal ohne Cache)YesNein (vollständige Analyse ausführen)
PR-Analyse (mit zwischengespeicherter Basis)YesÜberlagerungsmodus
Kein PR, kein Standard-BranchNoNo

Vollständige Arbeitsbeispiele in verschiedenen CI-Systemen finden Sie im Beispiel-CodeQL-Pipelinekonfigurations-Repository .

Diff-informierte Analyse

Die Diff-basierte Analyse ist eine Optimierung der Pull-Request-Analyse. Anstatt alle Warnungen in der Codebasis zu melden, meldet sie nur Warnungen in Zeilen, die im Pullanforderungs-Diff hinzugefügt oder geändert wurden.

Schritt 1: Diff-Bereiche identifizieren

Sie benötigen die hinzugefügten oder geänderten Zeilenbereiche im Pull-Request-Diff. Die Eingabe kann aus einer beliebigen Quelle (git diffder API Ihrer CI-Plattform oder einem anderen Mechanismus) stammen.

Erstellen Sie für jede geänderte Datei eine Liste von Bereichen mit der folgenden Struktur:

  • path: Absoluter Dateipfad (immer Schrägstriche verwenden)
  • startLine: 1-basiert, einschließlich der Startzeile
  • endLine: 1-basiert, inklusive Endzeile

Zum Beispiel bei diesem Unified Diff (generiert von 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>`;
 }

Die resultierenden Diff-Bereiche für src/utils.ts wären folgende:

  • ["/path/to/repo/src/utils.ts", 16, 17] (die beiden eingefügten Zeilen im zweiten Block)
  • ["/path/to/repo/src/utils.ts", 27, 27] (die geänderte Zeile im dritten Block)

Der erste Block enthält nur einen Löschvorgang, sodass kein Bereich erzeugt wird. Beachten Sie, dass Bereiche die Zeilennummern von „to“ (neue Datei) verwenden, nicht die von „from“ (alte Datei).

Sonderfälle:

  • Binäre Dateien oder sehr große Diffs (keine Patchinhalte verfügbar): Verwenden Sie den Sentinel-Bereich {path, startLine: 0, endLine: 0}, um „die gesamte Datei“ anzugeben.
  • Umbenannte Dateien ohne Inhaltsänderungen: Zurückgeben eines leeren Arrays (keine Bereiche).
  • Abgeschnittene Diffs: Wenn Ihre Diff-Quelle für große Pullanforderungen unvollständig ist (z. B. eine API, die die Anzahl der geänderten Dateien begrenzt), sollten Sie die diff-informierte Analyse überspringen und die vollständige Analyse für diese Ausführung ausführen.

Eine Referenzimplementierung der Diff-Analyse finden Sie getDiffRanges() im codeql-action Quellcode.

Schritt 2: Erstellen eines Datenerweiterungspakets

Erstellen Sie ein temporäres Verzeichnis mit zwei Dateien. Dieses Erweiterungspaket greift auf das erweiterbare Prädikat restrictAlertsTo zurück, das in der Standardbibliothek CodeQL definiert ist.

** 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]

Jede Datenzeile ist [filePath, lineStart, lineEnd]. Die Zeilennummerierung beginnt bei 1. Der Sonderfall lineStart = 0, lineEnd = 0 gibt eine Übereinstimmung mit einer ganzen Datei an.

Wichtig

Wenn der Diff null hinzugefügte oder geänderte Zeilen enthält (z. B. nur Löschvorgänge), müssen Sie dennoch eine nicht leere Datenerweiterung mit einem Sentinel-Eintrag ["", 0, 0]bereitstellen. Ein leerer data Abschnitt würde das restrictAlertsTo Prädikat inaktiv lassen, was bedeutet, dass alle Warnungen erstellt würden – das Gegenteil des gewünschten Verhaltens.

Schritt 3: Übergeben Sie das Erweiterungspaket an CodeQL CLI

Fügen Sie beim Ausführen von Abfragen die folgenden Flags hinzu: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-packs teilt mit CodeQL , wo das Paket auf dem Datenträger gefunden werden soll. Weitere Informationen findest du unter Abfragen in der Datenbank ausführen.
  • --extension-packs weist CodeQL an, das benannte Erweiterungspaket zu laden.

Schritt 4: Ausschließen von Diagnoseabfragen

Wenn Sie diff-informierte Analysen verwenden, sollten Sie Abfragen ausschließen, die mit exclude-from-incrementalkategorisiert sind. Diese Diagnoseabfragen erzeugen keine Warnungen (z. B. Metriken oder Codeabdeckung), sodass sie keinen Wert in einem inkrementellen Kontext bereitstellen, aber dennoch Ressourcen verbrauchen.

Sie können dies zu Ihrer Codeüberprüfungskonfigurationsdatei hinzufügen:

query-filters:
  - exclude:
      tags: exclude-from-incremental

Erstellen Sie alternativ eine Abfragesuitedatei (.qls), die diese Abfragen ausschließt:

- description: Pull request queries for Java
- import: codeql-suites/java-code-scanning.qls
  from: codeql/java-queries
- exclude:
    tags contain: exclude-from-incremental

Weitere Informationen findest du unter Workflowkonfigurationsoptionen für die Codeüberprüfung.

Schritt 5: Filtern der SARIF-Ausgabe

Nachdem CodeQL die SARIF-Datei generiert hat, müssen Sie die Ausgabe auf CI-Seite filtern, um Ergebnisse zu entfernen, deren Positionen außerhalb der Diff-Bereiche liegen.

Überprüfen Sie für jedes Ergebnis im SARIF, ob sich locations oder relatedLocations mit einem Diff-Bereich für die betreffende Datei überschneiden. Eine Position überschneidet einen Bereich, wenn range.startLine <= location.endLine und location.startLine <= range.endLine. Der Sonderfall range.startLine == range.endLine == 0 entspricht einem beliebigen Speicherort in der Datei. Stellen Sie sicher, dass SARIF-Artefaktpfade in dasselbe absolute Pfadformat aufgelöst werden, das in den Diff-Bereichen verwendet wird, bevor ein Vergleich erfolgt.

Das restrictAlertsTo Prädikat erlaubt, garantiert jedoch nicht, dass Abfragen Warnungen außerhalb des Bereichs auslassen, sodass für stabile Ergebnisse eine Filterung auf CI-Seite erforderlich ist.

Eine Referenzimplementierung der SARIF-Filterung finden Sie filterAlertsByDiffRange() im codeql-action Quellcode.

Zusammenfassung der CLI-Flags für diff-informierte Analysen

CLI-BefehlFlagPurpose
codeql database init--codescanning-config=FILECodeüberprüfungskonfigurationsdatei (für Abfragefilter)
codeql database run-queries--additional-packs=DIRSpeicherort des Erweiterungspakets
codeql database run-queries--extension-packs=my-ci/pr-diff-rangeName des zu ladenden Erweiterungspakets
codeql database interpret-results--sarif-run-property=incrementalMode=diff-informedOptional: SARIF mit diff-basierten Metadaten kennzeichnen

Überlagerungsanalyse

Die Überlagerungsanalyse beschleunigt die CodeQL Erstellung von Datenbanken und die Abfrageauswertung für Pullanforderungen, indem sie auf einer bereits vorhandenen "Basisdatenbank" aufbauen:

  1. Auf dem Standard-Branch: Erstellen Sie eine „overlay-base“-Datenbank (eine vollständige Datenbank mit zwischengespeicherten Zwischenergebnissen). Dies kann ein beliebiger langlebiger Branch sein, auf den Pull Requests abzielen.
  2. Bei Pullanforderungen: Laden Sie die zwischengespeicherte Overlaybasisdatenbank herunter, und erstellen Sie dann eine einfache "Overlay"-Datenbank, die nur die geänderten Dateien verarbeitet.

Überlagerungsbasismodus (Standardverzweigung)

Führen Sie den overlay-base-Modus nach jedem Merge auf Ihrem Standard- oder langlebigen Ziel-Branch aus, um eine Basisdatenbank zu erstellen und zwischenzuspeichern.

1. Initialisieren der Datenbank mit --overlay-base

codeql database init \
  --overlay-base \
  --db-cluster \
  PATH_TO_DATABASE \
  --source-root=PATH_TO_SOURCE \
  --language=LANGUAGE

Das --overlay-base Flag weist CodeQL an, eine Datenbank zu erstellen, die als Basis für zukünftige Überlagerungsanalysen dienen kann.

2. Erstellen und extrahieren wie gewohnt

Führen Sie alle Buildschritte und Extraktionen wie gewohnt für Ihr Projekt aus.

3. OIDs der Datensatzdatei erfassen

Zeichnen Sie nach Abschluss der Extraktion die Git-Objekt-IDs (OIDs) aller nachverfolgten Dateien unter dem Quellstamm auf. Führen Sie diesen Befehl aus Ihrem Quellstammverzeichnis (PATH_TO_SOURCE) aus. Diese Momentaufnahme wird später verwendet, um zu bestimmen, welche Dateien geändert wurden.

cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'

Parsen Sie diese Ausgabe in eine JSON-Zuordnung von { "relative/path": "git-oid" } um und speichern Sie sie neben der Datenbank. Die Ausgabe enthält Dateien in Git-Untermodulen, bei denen die Overlayanalyse alle Dateiänderungen zwischen der Basis und dem Overlay genau nachverfolgen muss.

4. Ausführen von Abfragen und Beibehalten des Caches

Übergeben Sie beim Ausführen von Abfragen in einer Overlay-Basisdatenbank nicht--expect-discarded-cache. Die zwischengespeicherten Ergebnisse sorgen dafür, dass Pull-Request-Builds schnell sind. Ihr Verwerfen würde bei jeder PR eine vollständige Neubewertung erzwingen.

5. Bereinigen und Zwischenspeichern der Datenbank

Bereinigen Sie die Datenbank nach der Analyse mithilfe der overlay Bereinigungsebene:

codeql database cleanup PATH_TO_DATABASE --cache-cleanup=overlay

Die overlay Bereinigungsebene behält mehr zwischengespeicherte Daten als die Standardebene clear bei. Im Überlagerungsmodus werden diese zwischengespeicherten Daten für die effiziente Auswertung von Abfragen bei Pull Requests wiederverwendet, sodass ihr Verwerfen den Leistungsvorteil zunichtemachen würde.

Speichern Sie dann die Datenbank (einschließlich der OIDs-Datei) in Ihrem Caching-System für den späteren Abruf durch Pull-Request-Builds.

Überlagerungsmodus (Pullanforderungen)

Führen Sie den Overlay-Modus für Pull-Request-Builds aus, um auf der zwischengespeicherten Basis eine leichtgewichtige Datenbank zu erstellen. Wenn keine kompatible Überlagerungsbasisdatenbank im Cache verfügbar ist (z. B. bei der ersten Ausführung oder nach einem CodeQL CLI Versionsupgrade), überspringen --overlay-changes und führen Sie stattdessen eine normale vollständige Analyse aus. Cacheschlüssel sollten mindestens die Version und sprache CodeQL CLI enthalten, um inkompatible Basisdatenbanken zu vermeiden.

1. Herunterladen der zwischengespeicherten Overlaybasisdatenbank

Rufen Sie die neueste Overlaybasisdatenbank aus Dem Cache ab. Die Datenbank sollte die im Overlay-Base-Modus aufgezeichnete OIDs-Datei enthalten.

2. Berechnen geänderter Dateien

Vergleichen Sie die in der Basisdatenbank aufgezeichneten OIDs mit dem aktuellen Git-Zustand. Führen Sie diesen Befehl aus demselben Quellstammverzeichnis (PATH_TO_SOURCE) aus, das im Overlay-Basismodus verwendet wird:

cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'

Vergleichen Sie die beiden Abbildungen, um Dateien zu finden, die hinzugefügt, entfernt oder geändert wurden (mit unterschiedlicher OID). Schreiben Sie das Ergebnis als JSON-Datei:

{
  "changes": ["src/modified-file.ts", "src/new-file.ts", "src/deleted-file.ts"]
}

Die Dateipfade müssen relativ zum Quellstamm sein.

3. Initialisieren der Datenbank mit --overlay-changes

Führen Sie die Ausführung codeql database init für das wiederhergestellte Overlaybasisdatenbankverzeichnis aus. Der PATH_TO_DATABASE Befehl muss auf die wiederhergestellte zwischengespeicherte Overlaybasisdatenbank und nicht auf ein neues leeres Verzeichnis verweisen. Der Befehl erweitert die vorhandene Basis für die Pullanforderungsanalyse.

codeql database init \
  --overlay-changes=PATH_TO_OVERLAY_CHANGES_JSON \
  --db-cluster \
  PATH_TO_DATABASE \
  --source-root=PATH_TO_SOURCE \
  --language=LANGUAGE

Wichtig

Übergeben Sie im Überlagerungsmodus nicht --overwrite oder --force-overwrite. Sie bauen auf der vorhandenen zwischengespeicherten Basisdatenbank auf und ersetzen sie nicht.

4. Erstellen, extrahieren und führen Sie Abfragen wie gewohnt aus

Fahren Sie mit der Build-, Extraktions- und Abfrageausführung wie gewohnt fort. Sie können dem vorhandenen --sarif-run-property Befehl das codeql database interpret-results Kennzeichen hinzufügen, um die SARIF-Ausgabe mit Overlaymetadaten zu markieren:

codeql database interpret-results \
  --format=sarif-latest \
  --output=results.sarif \
  --sarif-run-property=incrementalMode=overlay \
  PATH_TO_DATABASE \
  QUERIES_OR_SUITES

Wenn sowohl Overlay- als auch diff-informierte Analysen aktiv sind, verwenden Sie incrementalMode=overlay,diff-informed.

Warnungen aus der inkrementellen Analyse werden in den Codeüberprüfungsergebnissen der Pullanforderung auf die gleiche Weise wie Warnungen aus vollständigen Scans angezeigt. Jede Overlaybasisdatenbank funktioniert unabhängig vom Alter, aber frischere Basen erzeugen schnellere und genauere Ergebnisse.

Schließen Sie wie bei der diff-informierten Analyse bei Verwendung des Überlagerungsmodus mit exclude-from-incremental markierte Abfragen aus. Ausführliche Informationen finden Sie unter Schritt 4: Ausschließen von Diagnoseabfragen.

Zusammenfassung der CLI-Flags für die Überlagerungsanalyse

CLI-BefehlFlagModusPurpose
codeql database init--codescanning-config=FILEOverlayCodeüberprüfungskonfigurationsdatei (für Abfragefilter)
codeql database init--overlay-baseOverlaybasisErstellen einer Basisdatenbank für die zukünftige Überlagerungsverwendung
codeql database init--overlay-changes=FILEOverlayErstellen einer Überlagerungsdatenbank mit nur geänderten Dateien
codeql database init
(nein --overwrite)OverlayÜberschreiben Sie die zwischengespeicherte Basisdatenbank nicht
codeql database run-queries
(nein --expect-discarded-cache)OverlaybasisZwischengespeicherte Zwischenergebnisse beibehalten
codeql database cleanup--cache-cleanup=overlayOverlaybasisOverlay-spezifische Bereinigungsstufe verwenden
codeql database interpret-results--sarif-run-property=incrementalMode=overlayOverlaySARIF mit Überlagerungsmetadaten markieren

Mindest-CLI-Bundleversionen

Die Basis-Mindestversion für die Überlagerungsanalyse ist 2.23.8. Für einige Sprachen sind höhere Mindestversionen erforderlich:

SpracheMinimale CodeQL CLI Bundle-Version
C/C++2.25.0
C#2.24.1
Go2.24.2
Java2.23.8
Javascript2.23.9
Python2.23.9
Ruby2.23.9