VS Code の CodeQL 拡張と Starter workspace でコード分析する

| 11 min read
Author: masahiro-kondo masahiro-kondoの画像

これは、豆蔵デベロッパーサイトアドベントカレンダー2022第6日目の記事です。

6月の「GitHub の脆弱性検出機能 Code scanning alerts と CodeQL について」の記事で、CodeQL の概要と Code scanning alerts を GitHub Actions ワークフローを使って有効化する方法を紹介しました。

9月に VS Code の CodeQL 拡張で GitHub から CodeQL のデータベースを直接ダウンロードできるようになったことが発表されました。

CodeQL for VS Code: download CodeQL databases from GitHub.com | GitHub Changelog

この記事では、CodeQL 拡張で CodeQL データベースを取得し分析する方法を見ていきます。また、ローカル環境で CodeQL データベースを作る手順も試してみます。

CodeQL 拡張のインストール

#

まず、CodeQL 拡張をインストールします。

CodeQL - Visual Studio Marketplace

拡張をインストールすると CodeQL CLI のインストールが始まりました。

CodeQL CLI インストール

CodeQL CLI は CodeQL のデータベース作成やコード解析を行うための CLI です。

CodeQL 拡張の Cli: Executable Path 設定の説明には以下のようにあり、CodeQL CLI がインストールされていない場合は、拡張側でダウンロードし管理するようです。

Path to the CodeQL executable that should be used by the CodeQL extension. The executable is named codeql on Linux/Mac and codeql.exe on Windows. If empty, the extension will look for a CodeQL executable on your shell PATH, or if CodeQL is not on your PATH, download and manage its own CodeQL executable.

Starter workspace リポジトリの取得

#

VS Code と CodeQL 拡張で CodeQL データベースを解析したり CodeQL クエリを開発したりする作業を支援するための Starter workspace のリポジトリが公開されています。

GitHub - github/vscode-codeql-starter: Starter workspace to use with the CodeQL extension for Visual Studio Code.

Information

workspace は VS Code で複数のプロジェクトをまとめて取り扱うことのできる作業スペースで、code-workspace という拡張子の JSON ファイルで構成されます。

このリポジトリは CodeQL 本体のリポジトリ[1]に依存しており、Git の submodule として利用します。

GitHub - github/codeql: CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security

Starter workspace をクローンします。submodule を利用するため、--recursive フラグを付与します。GitHub CLI を利用する場合は以下のようになります。

gh repo clone github/vscode-codeql-starter -- --recursive

クローンしたプロジェクトの vscode-codeql-starter.code-workspace を VS Code で開くと各プログラミング言語用のカスタムクエリ開発用のテンプレート共に、submodule として取得された codeql リポジトリが ql ディレクトリ配下に展開されます。

workspace explorer

Information

発表当時の9月に試したら submodule が workspace に展開されない状態でした。現在はちゃんと使えるようになっています。

GitHub からの CodeQL データベースのダウンロード

#

Starter workspace の準備ができたので、早速 GitHub から CodeQL データベースを取得してみます。

CodeQL 拡張の画面にはデータベース用のパネルがあり、データベースが取得されていない状態では取得用のボタンが並んでいて一番下に From GitHub があります。

Database panel

From GitHub をクリックするとリポジトリ指定用のテキストボックスが出ますので、リポジトリの URL か <owner>/<repo> 形式で取得先を指定します。

取得先リポジトリの指定

試しに Minikube のリポジトリを指定してみました。

Minikube repo

言語のデータベースとして Go を選択

Choice Language

12MB程度で10数秒でダウンロードが完了し、データベースのパネルに追加されました。

追加されたデータベース

データベースが追加された状態ではパネル右上のツールバー的な UI でデータベースを追加することになります。

追加用ツールバー

Apache Kafka のデータベースを追加してみました。のついているデータベースがカレントの分析対象データベースとなります。Set Current Database をクリックすることでカレントのデータベースを切り替え可能です。

Kafka のデータベースを追加

Information

9月の発表時点で、GitHub には 20万を超える CodeQL データベースが存在するとありました。著名 OSS だけでなく Code scanning を有効化している Public リポジトリのデータベースも取得可能です。
Code QL データベースは Code QL 拡張を使わずに、GitHub の REST API を使って取得することもできます。

CodeQL データベースを使ってコード分析

#

Starter workspace に分析対象のデータベースと CodeQL リポジトリが整ったので、既存のクエリを実行してみます。Minikube のデータベースをカレントに指定した状態で VS Code のエクスプローラーを開きます。Minikube は Go のプロジェクトなので ql/go/ql/go/src を開きます。Go 言語用の CodeQL クエリーが MNetricsSecurity などの分類で格納されています。

Go の CodeQL ディレクトリ

Metrics ディレクトリ配下にはコードの行数やコメント行数を取得する QL ファイルが格納されています。

Metrics の行数取得のクエリファイル

QL ファイルまたは、QL ファイルが格納されたディレクトリを選択した状態でエクスプローラー上でコンテキストメニューを出すか、QL ファイルを開いた状態でコードエディタでコンテキストメニューを出すと、カレントデータベースに対してクエリを実行できます。

Run Queries メニュー

ディレクトリを選択した状態だと、配下のクエリーをまとめて実行できます。Metrics ディレクトリを選択して実行すると、2つのクエリを実行するという確認ダイアログが出ますので、Yes をクリック。

クエリ実行確認ダイアログ

実行が成功すると、Code QL 拡張の Query History パネルから結果をブラウズできるようになります。

クエリー履歴

クエリー結果を選択すると、CodeQL Query Results というタブが開いて、結果のサマリー、詳細結果へのリンク、実行したクエリーへのリンクが表示されます。

クエリー結果

raw results をクリックすると結果の詳細(この場合はソースコードファイルごとの行数)が表示されます。

結果詳細

詳細結果の行を選択すると、CodeQL データベースから実際のソースコードの該当箇所を開くことができます。エクスプローラーに切り替えると、データベースのソースコードアーカイブから該当のソースコードが選択状態になっています。

アーカイブのソースコードを閲覧

Open xxx.ql をクリックすると実行したクエリーのソースコードが開きます。

実行したクエリーの参照

Information

ちなみに Security 配下には CWE (Common Weakness Enumeration: 共通脆弱性タイプ一覧) の脆弱性検出用のクエリーが格納されています。
CWE クエリ

これらを一気に実行しようとすると、以下のようなエラーメッセージが出ます。一度に実行できるクエリーは Max 20個までのようです。

クエリーが多すぎるときのエラーメッセージ

Minikube のプロジェクトに対して CWE-20 のディレクトリを選択して実行した結果では、いくつか該当箇所が抽出されていました。

CWE20クエリー結果

以上のように Starter workspace では分析対象のプロジェクトの言語に応じたクエリーの実行と結果の閲覧が可能です。

Information

Starter workspace では既存の CodeQL クエリーを実行するだけでなく、クエリーを開発するためのワークベンチとしても利用できます。
Code QL 拡張でコード補完も効きますし、多くのサンプルが submodule の codeql リポジトリに格納されていますので、参照しながらカスタムクエリーを開発することも可能でしょう。

CodeQL データベースをローカルで作成する

#

CodeQL データベースは、GitHub のリポジトリから取得するだけでなく、CodeQL CLI を使ってローカルに作成できます。プライベートなリポジトリで開発しているプロジェクトでも自前でデータベースを構築して分析可能です。

CodeQL CLI をインストールするには、codeql-action の最新安定版リリースのページから利用する OS 用のバイナリをダウンロードします。

Caution

CodeQL CLI をダウンロードしてローカルで実行するのは問題ありませんが、private リポジトリの CI で使用するには、GitHub Advanced Security ライセンスが必要になるのでご注意ください。

About using the CodeQL CLI for code scanning

Apple シリコン Mac 用バイナリはリリースされていませんが、Rosetta 2が入っていれば Intel 用のバイナリ(codeql-bundle-osx64.tar.gz)を利用可能です。

ダウンロードしたアーカイブを展開してできる codeql-bundle ディレクトリをホームディレクトリなどに置いてパスを通します。実行用のバイナリと必要なライブラリやクエリーファイルが格納されていますので、このディレクトリにパスを通す必要があります。

export PATH=$PATH:~/codeql-bundle

対象プロジェクトのルートに移動して、codeql datebase create--language オプションを指定して実行します。以下は Go のプロジェクトで実行した例です。

codeql database create sb2md-codeqldb --language=go
Initializing database at /Users/masahiro-kondo/dev/sb2md/sb2md-codeqldb.
Running build command: [/Users/masahiro-kondo/codeql-bundle/go/tools/autobuild.sh]
[2022-12-03 17:33:30] [build-stderr] 2022/12/03 17:33:30 Autobuilder was built with go1.19.3, environment has go1.19
[2022-12-03 17:33:30] [build-stderr] 2022/12/03 17:33:30 LGTM_SRC is /Users/masahiro-kondo/dev/sb2md
[2022-12-03 17:33:30] [build-stderr] 2022/12/03 17:33:30 Found go.mod, enabling go modules
[2022-12-03 17:33:30] [build-stderr] 2022/12/03 17:33:30 Unable to determine import path, as neither LGTM_INDEX_IMPORT_PATH nor GITHUB_REPOSITORY is set
[2022-12-03 17:33:30] [build-stderr] 2022/12/03 17:33:30 Build failed, continuing to install dependencies.
[2022-12-03 17:33:30] [build-stderr] 2022/12/03 17:33:30 Installing dependencies using `go get -v ./...`.
[2022-12-03 17:33:31] [build-stderr] 2022/12/03 17:33:31 Running extractor command '/Users/masahiro-kondo/codeql-bundle/go/tools/osx64/go-extractor [./...]' from directory '/Users/masahiro-kondo/dev/sb2md'.
[2022-12-03 17:33:31] [build-stderr] 2022/12/03 17:33:31 Build flags: ''; patterns: './...'
[2022-12-03 17:33:31] [build-stderr] 2022/12/03 17:33:31 Running packages.Load.
:
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Extracting /Users/masahiro-kondo/dev/sb2md/cmd/cmd_util.go
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting /Users/masahiro-kondo/dev/sb2md/go.mod (3ms)
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Extracting /Users/masahiro-kondo/dev/sb2md/go.mod
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting /Users/masahiro-kondo/dev/sb2md/go.mod (0ms)
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Extracting /Users/masahiro-kondo/dev/sb2md/main.go
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting /Users/masahiro-kondo/dev/sb2md/main.go (0ms)
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting /Users/masahiro-kondo/dev/sb2md/cmd/root.go (23ms)
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting /Users/masahiro-kondo/dev/sb2md/cmd/cmd_util.go (24ms)
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting /Users/masahiro-kondo/dev/sb2md/cmd/md.go (29ms)
[2022-12-03 17:33:37] [build-stderr] 2022/12/03 17:33:37 Done extracting packages.
Finalizing database at /Users/masahiro-kondo/dev/sb2md/sb2md-codeqldb.
[2022-12-03 17:33:37] [build-stderr] Scanning for files in /Users/masahiro-kondo/dev/sb2md...
Successfully created database at /Users/masahiro-kondo/dev/sb2md/sb2md-codeqldb.

Starter workspace に取り込むには、データベースパネルの Choose Database from Folder をクリックして作成したデータベースのパスを指定します。

Choose Database from Folder

Select Database Folder

これでデータベースが取り込まれますので、他のデータベースと同様クエリーを実行して分析ができるようになります。

ディレクトリから追加されたデータベース

Information

単に静的コード分析をローカルで実行するだけであれば CodeQL 拡張や Starter workspace は不要で、CodeQL CLI と VS Code の SARIF Viewer 拡張だけで完結します。以下はデータベースを解析して Sarif 形式で出力する例です。

codeql database analyze sb2md-codeqldb --format=sarif-latest --output result.sarif
Running queries.
[1/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Security/CWE-020/IncompleteHostnameRegexp.qlx.
[2/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Security/CWE-020/IncompleteUrlSchemeCheck.qlx.
[3/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Security/CWE-020/MissingRegexpAnchor.qlx.
:
[27/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Security/CWE-918/RequestForgery.qlx.
[28/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Diagnostics/ExtractionErrors.qlx.
[29/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Diagnostics/SuccessfullyExtractedFiles.qlx.
[30/30] Loaded /Users/masahiro-kondo/codeql-bundle/qlpacks/codeql/go-queries/0.3.4/Summary/LinesOfCode.qlx.
ExtractionErrors.ql               : [1/30 eval 23ms] Results written to codeql/go-queries/Diagnostics/ExtractionErrors.bqrs.
:
LinesOfCode.ql                    : [30/30 eval 43ms] Results written to codeql/go-queries/Summary/LinesOfCode.bqrs.
Shutting down query evaluator.
Interpreting results.
Analysis produced the following diagnostic data:

|         Diagnostic          |  Summary  |
+-----------------------------+-----------+
| Successfully analyzed files | 5 results |

Analysis produced the following metric data:

|                 Metric                 | Value |
+----------------------------------------+-------+
| Total lines of Go code in the database |   238 |

結果を SARIF View で表示しているところです(抽出結果がなかったので空っぽですが)。

Sarif Viewer

詳しくは「GitHub code scanning 結果を VS Code で確認できる SARIF Viewer 拡張」を参照してください。

最後に

#

この記事では、VS Code 上で CodeQL を使ってコード分析を行う方法を紹介しました。セキュリティスキャンとしての利用だけであればこのような環境構築は不要ですが、CodeQL について深く知りたい場合や自分でカスタムクエリーを開発したい場合は非常に役立つ環境だと思います。


参考


  1. CodeQL のライブラリや各言語用のクエリーが管理されています。 ↩︎

豆蔵デベロッパーサイト - 先週のアクセスランキング
  1. 基本から理解するJWTとJWT認証の仕組み (2022-12-08)
  2. Docker+Wasm で WASM をコンテナとして実行する (2023-01-25)
  3. 自然言語処理初心者が「GPT2-japanese」で遊んでみた (2022-07-08)
  4. 直感が理性に大反抗!「モンティ・ホール問題」 (2022-07-04)
  5. Nuxt3入門(第4回) - Nuxtのルーティングを理解する (2022-10-09)
  6. AWS認定資格を12個すべて取得したので勉強したことなどをまとめます (2022-12-12)
  7. Jest再入門 - 関数・モジュールモック編 (2022-07-03)
  8. ORマッパーのTypeORMをTypeScriptで使う (2022-07-27)
  9. Nuxt3入門(第8回) - Nuxt3のuseStateでコンポーネント間で状態を共有する (2022-10-28)
  10. Nuxt3入門(第1回) - Nuxtがサポートするレンダリングモードを理解する (2022-09-25)