増分分析について
すべてのプル要求に対するフル CodeQL スキャンは、特に大規模なコードベースでは低速になる可能性があります。 独自の CI/CD システムで CodeQL CLI を実行する場合、増分分析では、次の 2 つの方法で処理を高速化できます。
- 差分に基づく分析では、追加または変更した行のアラートのみを表示するため、クエリの実行が高速になり、より関連性の高い結果が得られます。
- オーバーレイ分析 では、既定のブランチからキャッシュされたデータベースが再利用され、最初からデータベースを構築する代わりに、データベースの作成とクエリの評価時間が大幅に短縮されます。
これらの機能は、個別に使用することも、一緒に使用することもできます。 確立されたコードベースでプル要求を分析するほとんどのチームでは、高速なデータベース作成とクエリ評価のためのオーバーレイ分析と、フォーカスされた関連する結果の差分情報分析の両方を使用することをお勧めします。
既定code scanningセットアップまたはcodeql-actionのGitHubを使用する場合、増分分析は既に自動的に処理されます。 この記事は、独自の CI/CD インフラストラクチャで CodeQL CLI を直接実行するチームを対象としています。
Prerequisites
増分分析を設定する前に、次の要件を満たしていることを確認してください。
- CodeQL CLI バンドル バージョン: 差分情報分析用の 2.21.0 以降、オーバーレイ分析用の 2.23.8 以降 (言語ごとの最小値については、 CLI バンドルの最小バージョンを参照)
- ソース ルート は Git リポジトリ内にある必要があります
- Git バージョン 2.38.0 以降 (オーバーレイ分析に必要、特に
--formatで使用されるgit ls-filesオプション) - 関心のあるすべてのファイル は Git で追跡する必要があります (
.gitignoreではありません) - Git インデックス は、分析対象のソース ツリーを正確に反映する必要があります
- ビルド モード: オーバーレイ分析では、
build-mode: noneのみがサポートされます (トレースされたビルドはサポートされていません)。 Go は、このモードを明示的にサポートしていないにもかかわらず、オーバーレイ分析で機能します。
アプローチの選択
| シナリオ | 差分情報に基づく | オーバーレイ |
|---|---|---|
| 既定のブランチ プッシュ | いいえ (PR ではありません) | オーバーレイベース モード |
| PR 分析 (初回、キャッシュなし) | はい | いいえ (完全な分析を実行) |
| PR 分析 (キャッシュベースあり) | はい | オーバーレイ モード |
| PR でも既定ブランチでもないブランチ | いいえ | いいえ |
さまざまな CI システムの完全な動作例については、 サンプルの CodeQL パイプライン構成リポジトリを 参照してください。
差分情報分析
差分情報に基づく解析は、プルリクエスト解析を最適化する機能です。 コードベースで検出されたすべてのアラートを報告する代わりに、プルリクエストの差分で追加または変更された行内のアラートのみを報告します。
手順 1: 差分範囲を特定する
pull request diff から追加または変更された行範囲が必要です。 入力は、任意のソース (git diff、CI プラットフォームの API、または別のメカニズム) から取得できます。
変更されたファイルごとに、次の構造を持つ範囲の一覧を生成します。
path: 絶対ファイルパス (常にフォワードスラッシュを使用)startLine: 1 から始まる包括的な開始行endLine: 1 から始まる包括的な終了行
たとえば、この統合された差分 ( 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>`;
}
src/utils.tsの結果の差分範囲は次のようになります。
["/path/to/repo/src/utils.ts", 16, 17](第2ハンクに挿入された2行)["/path/to/repo/src/utils.ts", 27, 27](3番目のハンクの変更された行)
最初のハンクには削除のみが含まれているため、範囲は生成されません。 範囲指定には、"from"(古いファイル)の行番号ではなく、"to"(新しいファイル)の行番号が使用されることに注意してください。
特殊なケース:
- バイナリファイルまたは非常に大きな差分(パッチコンテンツは利用できません): 「ファイル全体」を示すには、センチネル範囲
{path, startLine: 0, endLine: 0}を使用してください。 - コンテンツが変更されていない名前のファイル: 空の配列 (範囲なし) を返します。
- 切り捨てられた差分: 大きなプル要求 (変更されたファイルの数を制限する API など) に対して差分ソースが不完全な場合は、差分情報に基づく分析をスキップし、その実行に対して完全な分析を実行する必要があります。
差分解析の参照実装については、getDiffRanges()ソース コードのcodeql-actionを参照してください。
手順 2: データ拡張機能パックを作成する
2 つのファイルを含む一時ディレクトリを作成します。 この拡張パックは、restrictAlertsTo標準ライブラリで定義されている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]
各データ行は [filePath, lineStart, lineEnd]。 行番号は 1 から始まります。 特殊なケース lineStart = 0, lineEnd = 0 は、ファイル全体の一致を表します。
重要
差分に追加行または変更行が 0 行しかない場合(たとえば削除のみの場合)でも、センチネル エントリ ["", 0, 0] を含む空でないデータ拡張を提供する必要があります。 空の data セクションでは、 restrictAlertsTo 述語は非アクティブのままになり、すべてのアラートが生成され、目的の動作とは逆になります。
手順 3: 拡張機能パックを CodeQL CLI に渡す
クエリを実行するときは、次のフラグを 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は CodeQL ディスク上のパックを見つける場所を指示します。 詳細については、「データベース実行クエリ」を参照してください。--extension-packsは、名前付き拡張パックを読み込むよう CodeQL に指示します。
手順 4: 診断クエリを除外する
差分情報分析を使用する場合は、 exclude-from-incrementalでタグ付けされたクエリを除外する必要があります。 これらの診断クエリはアラート (メトリックやコード カバレッジなど) を生成しないため、増分コンテキストでは値は提供されませんが、リソースは引き続き使用されます。
これをコード スキャン構成ファイルに追加できます。
query-filters:
- exclude:
tags: exclude-from-incremental
または、これらのクエリを除外するクエリ スイート ファイル (.qls) を作成します。
- description: Pull request queries for Java
- import: codeql-suites/java-code-scanning.qls
from: codeql/java-queries
- exclude:
tags contain: exclude-from-incremental
詳細については、「コード スキャンのワークフロー構成オプション」を参照してください。
手順 5: SARIF 出力をフィルター処理する
SARIF ファイル CodeQL 生成した後、CI 側の出力をフィルター処理して、場所が差分範囲外の結果を削除する必要があります。
SARIF の各結果について、その locations または relatedLocations がそのファイルの差分範囲と交差しているかどうかを確認します。
range.startLine <= location.endLineとlocation.startLine <= range.endLineすると、位置は範囲と交差します。 特殊なケース range.startLine == range.endLine == 0 は、ファイル内の任意の場所と一致します。 比較する前に、SARIF アーティファクトの場所が差分範囲で使用されているのと同じ絶対パス形式に解決されていることを確認します。
restrictAlertsTo述語では許可されますが、クエリが範囲外のアラートを省略することは保証されないため、安定した結果を得るには CI 側のフィルター処理が必要です。
SARIF フィルター処理のリファレンス実装については、filterAlertsByDiffRange()ソース コードのcodeql-actionを参照してください。
差分情報分析のための CLI フラグの概要
| CLI コマンド | フラグ | Purpose |
|---|---|---|
codeql database init | --codescanning-config=FILE | コード スキャン構成ファイル (クエリ フィルター用) |
codeql database run-queries | --additional-packs=DIR | 拡張パックの場所 |
codeql database run-queries | --extension-packs=my-ci/pr-diff-range | 読み込む拡張パックの名前 |
codeql database interpret-results | --sarif-run-property=incrementalMode=diff-informed | (省略可能)差分情報メタデータを使用して SARIF にタグを付け |
オーバーレイ分析
オーバーレイ分析では、既存の "ベース" データベースを基に構築することで、pull request のデータベース作成とクエリの評価 CodeQL 高速化します。
- 既定のブランチで次の手順を実行します。 "オーバーレイ ベース" データベース (中間結果がキャッシュされた完全なデータベース) を構築します。 これは、プルリクエストの対象となる長期間運用される任意のブランチにできます。
- プル要求の場合: キャッシュされたオーバーレイ ベース データベースをダウンロードし、変更されたファイルのみを処理する軽量の "オーバーレイ" データベースを作成します。
オーバーレイベース モード(既定のブランチ)
各マージの後に既定または有効期間の長いターゲット ブランチでオーバーレイ ベース モードを実行し、ベース データベースを作成してキャッシュします。
1. 次を使用してデータベースを初期化します。 --overlay-base
codeql database init \
--overlay-base \
--db-cluster \
PATH_TO_DATABASE \
--source-root=PATH_TO_SOURCE \
--language=LANGUAGE
--overlay-base フラグは、将来のオーバーレイ分析のベースとして機能するデータベースを構築するようにCodeQLに指示します。
2. 通常どおりにビルドして抽出する
通常のプロジェクトと同様に、ビルドステップと抽出を実行します。
3. ファイル OID を記録する
抽出が完了したら、ソース ルートの下にあるすべての追跡対象ファイルの Git オブジェクト ID (OID) を記録します。 ソース ルート ディレクトリ (PATH_TO_SOURCE) からこのコマンドを実行します。 このスナップショットは、後で変更されたファイルを特定するために使用されます。
cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'
この出力を { "relative/path": "git-oid" } の JSON マップに解析し、データベースと共に格納します。 出力には Git サブモジュール内のファイルが含まれています。オーバーレイ分析では、ベースとオーバーレイの間のすべてのファイル変更を正確に追跡する必要があります。
4. クエリを実行してキャッシュを保持する
オーバーレイ ベース データベースでクエリを実行する場合は、**** を渡--expect-discarded-cache。 キャッシュされた中間結果は、pull request ビルドを高速にする結果です。 これらを破棄すると、すべての PR で完全な再評価が強制されます。
5. データベースをクリーンアップしてキャッシュする
分析後、 overlay クリーンアップ レベルを使用してデータベースをクリーンアップします。
codeql database cleanup PATH_TO_DATABASE --cache-cleanup=overlay
overlay クリーンアップ レベルでは、既定のclear レベルよりも多くのキャッシュ データが保持されます。 オーバーレイ モードでは、このキャッシュされたデータを再利用して pull request の効率的なクエリ評価を行うので、破棄するとパフォーマンス上の利点がなくなります。
次に、データベース (OID ファイルを含む) をキャッシュ システムに格納し、後で pull request ビルドを使用して取得できるようにします。
オーバーレイ モード (プル要求)
プル要求ビルドでオーバーレイ モードを実行して、キャッシュされたベースの上に軽量データベースを作成します。 互換性のあるオーバーレイ ベース データベースがキャッシュで使用できない場合 (たとえば、最初の実行時や CodeQL CLI バージョンのアップグレード後) は、 --overlay-changes スキップし、通常の完全な分析を代わりに実行します。 キャッシュ キーには、互換性のない基本データベースを回避するために、少なくとも CodeQL CLI バージョンと言語セットが含まれている必要があります。
1. キャッシュされたオーバーレイ ベース データベースをダウンロードする
キャッシュから最新のオーバーレイ ベース データベースを取得します。 データベースには、オーバーレイ ベース モード中に記録された OID ファイルが含まれている必要があります。
2. 変更されたファイルを計算する
ベース データベースに記録されている OID を現在の Git 状態と比較します。 オーバーレイ ベース モードで使用したのと同じソース ルート ディレクトリ (PATH_TO_SOURCE) から次のコマンドを実行します。
cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'
2 つのマップを比較して、追加、削除、または変更されたファイル (異なる OID) を見つけます。 結果を JSON ファイルとして書き込みます。
{
"changes": ["src/modified-file.ts", "src/new-file.ts", "src/deleted-file.ts"]
}
ファイル パスは、ソース ルートに対する相対パスである必要があります。
3. 次を使用してデータベースを初期化します。 --overlay-changes
復元されたオーバーレイベースデータベースディレクトリに対して codeql database init を実行します。
PATH_TO_DATABASEは、新しい空のディレクトリではなく、復元されたキャッシュされたオーバーレイ ベース データベースを指す必要があります。このコマンドは、プル要求分析用に既存のベースを拡張します。
codeql database init \
--overlay-changes=PATH_TO_OVERLAY_CHANGES_JSON \
--db-cluster \
PATH_TO_DATABASE \
--source-root=PATH_TO_SOURCE \
--language=LANGUAGE
重要
オーバーレイ モードでは、 --overwrite または --force-overwriteを渡さないでください。 既存のキャッシュされたベース データベースの上に構築し、置き換える必要はありません。
4. 通常どおりクエリを作成、抽出、実行する
通常どおり、ビルド、抽出、クエリの実行に進みます。 既存の --sarif-run-property コマンドに codeql database interpret-results フラグを追加して、SARIF 出力にオーバーレイ メタデータをタグ付けできます。
codeql database interpret-results \
--format=sarif-latest \
--output=results.sarif \
--sarif-run-property=incrementalMode=overlay \
PATH_TO_DATABASE \
QUERIES_OR_SUITES
オーバーレイ分析と差分情報分析の両方がアクティブな場合は、 incrementalMode=overlay,diff-informedを使用します。
増分分析からのアラートは、プル要求のコード スキャン結果に、フル スキャンからのアラートと同じ方法で表示されます。 オーバーレイ ベース データベースは、年齢に関係なく機能しますが、新しいベースでは、より高速で正確な結果が生成されます。
差分情報分析と同様に、オーバーレイ モードを使用する場合は、 exclude-from-incremental タグ付けされたクエリを除外します。 詳細については、「 手順 4: 診断クエリを除外する」を参照してください。
オーバーレイ分析用の CLI フラグの概要
| CLI コマンド | フラグ | モード | Purpose |
|---|---|---|---|
codeql database init | --codescanning-config=FILE | オーバーレイ | コード スキャン構成ファイル (クエリ フィルター用) |
codeql database init | --overlay-base | overlay-base | 将来オーバーレイを使用するためのベース データベースを構築する |
codeql database init | --overlay-changes=FILE | オーバーレイ | 変更されたファイルのみを使用してオーバーレイ データベースを構築する |
codeql database init | |||
( --overwriteなし) | オーバーレイ | キャッシュされたベース データベースを上書きしない | |
codeql database run-queries | |||
( --expect-discarded-cacheなし) | overlay-base | キャッシュされた中間結果を保持する | |
codeql database cleanup | --cache-cleanup=overlay | overlay-base | オーバーレイ固有のクリーンアップ レベルを使用する |
codeql database interpret-results | --sarif-run-property=incrementalMode=overlay | オーバーレイ | オーバーレイ メタデータを使用して SARIF にタグを付け |
CLI バンドルの最小バージョン
オーバーレイ分析の基本最小バージョンは 2.23.8 です。 一部の言語では、より高い最小バージョンが必要です。
| Language | 最小 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 |