連載|静的解析×AIエージェントを始めよう! 第1回 SARIFを使う

組込み開発における静的解析の運用負荷にお悩みではありませんか?

本記事では、ツールごとに異なる出力形式の問題を解決する共通フォーマット「SARIF」に注目。AIエージェントを活用して静的解析を効率化するための第一歩として、SARIFの基本と活用方法を解説します。

Artist's impression of a multi-core CPU

この連載の記事一覧

連載|静的解析×AIエージェントを始めよう!

  • 第1回 SARIFを使う
  • 第2回 GitHub Copilot×SARIFの留意点(前編)
  • 第3回 GitHub Copilot×SARIFの留意点(中編)
  • 第4回 GitHub Copilot×SARIFの留意点(後編)
  • 第5回 タイトル未定

1. はじめに

組込みソフトウェア開発の現場では、「静的解析をやってはいるものの、運用負荷が大きく十分に活用できていない」という声も少なくありません。大量の警告、レビューの手間、誤検出の仕分け……こうした「運用の重さ」に、長年悩まされてきた方もいるのではないでしょうか。

近年は、こうした静的解析の運用負荷をAIエージェントで軽減しようとする取り組みも出てきています。しかし、AIエージェントに静的解析結果を読ませようとすると、最初にぶつかる壁があります。それは、ツールごとに出力フォーマットがバラバラという問題です。静的解析ツールは、CSV、XML、JSON、SARIFなど、さまざまな形式で結果を出力します。この状態のままAIエージェントと組み合わせようとすると、あらかじめツールごとに結果を読み解く処理を用意する必要があります。

この課題を解決する共通言語が、SARIF(Static Analysis Results Interchange Format)です。このコラムでは、まずはSARIFの基本を整理し、次に実際に手元でSARIFを出力して、静的解析×AIエージェント連携の最初の一歩を踏み出してみます。なお、本コラムでは、静的解析ツールとAIエージェントの連携を「静的解析×AIエージェント」と表記します。

2. SARIFとは何か

SARIF(Static Analysis Results Interchange Format)は、静的解析ツールの検査結果を一つにまとめるための共通フォーマットです。JSONベースで記述され、OASIS という標準化団体によって仕様が策定されています。本コラム執筆時の最新版はSARIF v2.1.0で、OASIS Standardとして承認されています。

OASISのSARIF仕様では、SARIFの目的として次の項目が挙げられています。

  • Comprehensively capture the range of data produced by commonly used static analysis tools.
  • Be a useful format for analysis tools to emit directly, and also an effective interchange format into which the output of any analysis tool can be converted.
  • Be suitable for use in a variety of scenarios related to analysis result management and be extensible for use in new scenarios.
  • Reduce the cost and complexity of aggregating the results of various analysis tools into common workflows.
  • Capture information that is useful for assessing a project’s compliance with corporate policy or certification standards.
  • Adopt a widely used serialization format that can be parsed by readily available tools.
  • Represent analysis results for all kinds of artifacts, including source code and object code.

出典:OASIS:Static Analysis Results Interchange Format (SARIF) V2.1.0

要約すると、SARIFは「さまざまな静的解析ツールが出力する情報を包括的に表現できること」と「複数ツールの結果を、共通のワークフローに集約しやすくすること」を目的としたフォーマットです。

開発チームが複数の静的解析ツールを併用するのは珍しくありませんが、ツールごとに出力形式が異なると、それらの結果を集約して全体像をつかむのが難しくなります。SARIFはこの問題に対する標準化されたアプローチとして策定されました。

SARIFは、SARIF ( OASIS Static Analysis Results Interchange Format ) TC によって仕様策定が進められました。OASISでのTC設立に向けた呼びかけは2017年に行われ、SARIF v2.1.0は2019年7月にOASIS Committee Specification 01、2020年3月にOASIS Standardとして承認されています。

3. なぜSARIFが「静的解析×AIエージェント」の第一歩なのか?

静的解析×AIエージェントについては、既に業界でも手法が報告されています。例えば、ウーブン・バイ・トヨタ株式会社様は、MISRA準拠エラーに対するコード修正案をAIエージェントで生成・評価する「MISRA Copilot」の実証実験を報告 しています。

いきなり、このような大規模なシステムを組み上げるのは容易ではありません。それゆえに、当社は静的解析×AIエージェントを出発点として、既存の静的解析ツールの出力を、SARIFという共通フォーマットに揃えることを提案します。

  • 解析ロジックそのものは変えなくてよい(ツールの入れ替えや大改修は不要)
  • Visual Studio Code(VS Code)やVisual StudioではSARIF Viewerなどを通じて確認でき、GitHubではCode scanningに、GitLabでは脆弱性レポートにSARIFの検出結果を取り込める
  • 出力をSARIFに統一することで、AIエージェントに渡すための「共通の入口」ができる
  • 一度この入口ができれば、複数の静的解析ツールを併用していても、AIエージェント側の処理を共通化しやすくなる

SARIFは、静的解析ツールとAIエージェントの間に立つ「翻訳レイヤー」のような役割を果たします。ツール側の出力形式に依存せず、AIエージェントはSARIFの構造を前提に処理できるため、トリアージ(警告の要否判断)、誤検出の仕分け、修正案の提示といった処理を、ツールをまたいで共通の仕組みとして組み立てやすくなります。

嬉しいことに、現在はOSS・商用を問わず、SARIF形式での出力やSARIFへの変換に対応する静的解析ツールも増えています。

4. 実際のSARIFを見ながら構造をつかむ

SARIFは、JSON形式で記述されたファイルです。大きく分けると、「どのツールが」「何を」「どこで」検出したかという情報を階層的に持っています。細部は仕様上かなり多機能ですが、まず押さえておきたい要素は以下の通りです。

要素意味
version / $schemaSARIFのバージョンとJSONスキーマ情報
runs[]解析実行を表す run オブジェクトの配列
runs[].tool​.driver​.name解析を行ったツール本体(driver)の名前
runs[]​.tool​.driver​.rules[]ツールが定義する解析ルールの一覧。id や説明文などを含む
runs[]​.results[]実際に検出された指摘(結果)の配列
runs[]​.results[]​.ruleIdどのルールによる検出かを示すID
runs[]​.results[]​.level重大度レベル(error / warning / note / none など)
runs[]​.results[]​.message​.text指摘内容のメッセージ本文
runs[]​.results[]​.locations[]​.physicalLocation検出箇所の物理的な位置。ファイルURIや行・列などを含む

「習うより慣れよ」ということで、実際に手元でSARIFを出力してみましょう。ここでは、OSS(GPL-3.0)のC/C++向け静的解析ツール Cppcheck を使います。Cppcheckはバージョン2.16.0以降、`--output-format=sarif` オプションでSARIF出力に対応しています。

解析対象ソースコード(`null_ptr.c`)は以下とします。

#include <stddef.h>
int main(void)
{
    int *ptr = NULL;
    return *ptr;
}

このコードに対して、以下のコマンドでCppcheckを使ってSARIFファイルを出力します。

cppcheck --enable=all --output-format=sarif null_ptr.c 2> report.sarif

これだけで、report.sarif というSARIFファイルが生成されます。SARIFはJSONベースのフォーマットなので、テキストエディタでも中身を確認できます。
実際の出力のうち、NULLポインタ参照に関する指摘だけを抜粋すると、次のようになります。実際のSARIFには、システムヘッダに関する `note` や、`constVariablePointer` など別の指摘も含まれていましたが、ここでは構造を見やすくするために省略しています。

{
  "version": "2.1.0",
  $schema: "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
  "runs": [
    {
      "results": [
        {
          "level": "error",
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "null_ptr.c"
                },
                "region": {
                  "startLine": 5,
                  "startColumn": 16,
                  "endLine": 5,
                  "endColumn": 16
                }
              }
            },
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "null_ptr.c"
                },
                "region": {
                  "startLine": 7,
                  "startColumn": 13,
                  "endLine": 7,
                  "endColumn": 13
                }
              }
            }
          ],
          "message": {
            "text": "Null pointer dereference: ptr"
          },
          "partialFingerprints": {
            "hash/v1": "5628042425796901966"
          },
          "ruleId": "nullPointer"
        }
      ],
      "tool": {
        "driver": {
          "informationUri": "https://cppcheck.sourceforge.io",
          "name": "Cppcheck",
          "semanticVersion": "2.22"
        }
      }
    }
  ]}
}

この出力では、tool.driver.name から解析ツールが Cppcheck であることが分かります。また、tool.driver.semanticVersion には使用したCppcheckのバージョンとして 2.22 が入っています。

実際の指摘は、results[] に入ります。ここでは、 ruleId が nullPointer、level が error となっており、message.text には "Null pointer dereference: ptr" という指摘内容が入っています。

また、locations には2つの位置が記録されています。5行目は ptr に NULL を代入している箇所、7行目はその ptr を参照して実際にNULLポインタ参照が発生する箇所です。このように、SARIFでは1つの指摘に対して、原因箇所や実際の問題箇所など、複数のコード位置が紐づくことがあります。

ポイントは、「ツール名」「ルールID」「重大度」「指摘内容」「ファイル位置」が共通の構造で表現されることです。ツールが変わっても、AIエージェント側はこの構造を読み取れば、どの指摘がどのファイルの何行目にあるかを機械的に扱えます。

CodeSonarのような商用ツールも同様にSARIF出力に対応しているものが多く、また対応していないツールでも、XMLやJSON形式の出力をSARIFに変換するコンバータが用意されているケースがあります。まずは、「そのツールがSARIFを直接出力できるか」「変換ツールを挟む必要があるか」を確認してみましょう。

5. 出力したSARIFを「見る」

SARIFファイルは生のJSONのままでも情報としては十分ですが、人が確認する際はビューアを使うと格段に見やすくなります。代表的な方法を2つ紹介します。

5.1 VS CodeのSARIF Viewer拡張機能で見る

Microsoftが公開しているSARIF Viewer Visual Studio Marketplace )をVS Codeにインストールすると、SARIFファイルを開くだけで、検出結果の一覧、ルールごとの集計、該当コード行へのジャンプなどをGUIで確認できます。指摘を選択すると、対応するソースコードの該当箇所がハイライトされるため、コードとSARIFの結果を並べて確認する用途に向いています。

以下の画像は、前項で作成したSARIFファイルをVS CodeのSARIF Viewerで表示したものです。(本コラムでは、VS Code Version: 1.134.0を利用しています。)

以下の画像は、前項で作成したSARIFファイルをVS CodeのSARIF Viewerで表示したものです。

問題が発生しているコード部分は、赤線や黄色線で強調されます。

コード上だけでなく、画面下部のPROBLEMS(問題)パネルからも、検出結果を確認できます。

注意

今回のコードで実際にNULLポインタ参照が発生するのは、7行目の `return *ptr;` です。

CppcheckのSARIFでは、`nullPointer` の `locations[]` に、`ptr` に `NULL` を代入した5行目と、その `ptr` を参照している7行目の両方が含まれています。VS CodeのSARIF Viewerでは、このうち先頭の `location` である5行目が、PROBLEMS上の代表位置として表示されています。

一方、同じコードをCodeSonarで解析してSARIF形式で出力した場合、ビューア上では実際にNULLポインタ参照が発生する7行目が指摘箇所として表示されます。また、5行目で `ptr` が `NULL` になり、7行目で参照される、という流れも画面上で確認できます。

このように、SARIFという共通フォーマットを使っていても、同じ事象をどの位置情報として出力し、ビューア上でどう表示するかは、ツールによって違いがあります。なおSARIFでは、発生箇所だけでなく、そこに至る流れを表現するための任意項目も用意されています。ツールによっては、その情報を活用することで、原因箇所から発生箇所までの流れをビューア上で確認できます。

5.2 GitLab上で見る

GitLabでは、SARIFファイルを脆弱性レポートとして取り込んで表示できます。SARIFファイルは、CI/CDジョブのアーティファクトとして登録します。一般的には、CI/CDジョブの中で静的解析ツールを実行し、その出力をSARIF形式で保存して、`artifacts:reports:sarif` に指定します。(参照:https://docs.gitlab.com/ja-jp/user/application_security/detect/sarif/

一方で、静的解析を別環境で実行し、事前に生成したSARIFファイルをリポジトリに含めておき、GitLab CI/CD上ではそのSARIFをアーティファクトとして登録するだけ、という構成も可能です。この場合、GitLab Runner上に静的解析ツール本体を導入しなくても、GitLabのセキュリティレポート機能で結果を確認できます。

いきなりCI/CD上で静的解析を実行する環境を構築するのが難しい場合は、まずこの方法で、ローカル環境にある静的解析ツールの結果をGitLab上で確認する手法をおすすめします。

実際に、前述のSARIFファイルをGitLab上で表示したのが下図になります。

この例では、GitLab CI/CDジョブ内で静的解析ツール本体は実行していません。事前に作成しておいたSARIFファイルをリポジトリに含めておき、特定ブランチへのpushをトリガーに実行されるジョブで、そのSARIFファイルを `artifacts:reports:sarif` として登録しています。

組込みソフトウェア開発では、コンパイル環境や静的解析ツールのライセンスなどの兼ね合いで、Runner上に解析環境を構築するのが難しい場合があります。そのような場合でも、事前に生成したSARIFだけを取り込む形にすれば、GitLabのUI上で検出結果を確認できます。

6. SARIFを起点にしてAIエージェントを使ってみよう

6.1 まずは試してみる

SARIFという共通フォーマットが手に入ると、静的解析結果をAIエージェントに渡すための入口を作りやすくなります。

もちろん、SARIFだけで高精度な誤検出判断や修正判断が完結するわけではありません。実務で精度を上げるには、対象コード、ビルド条件、設計情報、過去の対応履歴、プロジェクト固有のルールなど、SARIF以外のコンテキストも重要です。しかし、最初は、そこまで大きな仕組みを作らなくても構いません。VS Code上でSARIF Viewerを使って指摘箇所を確認し、該当コードに対してGitHub Copilot ChatのExplainやFixを実行するだけでも、静的解析結果とAIエージェントを組み合わせる感覚をつかめます。

この段階で試しやすいこととしては、たとえば以下があります。

  1. 指摘内容の理解:SARIF Viewerで表示された指摘内容や該当コードをもとに、GitHub Copilot ChatのExplainで「なぜ問題なのか」を確認する
  2. 修正案のたたき台作成:該当コードに対してFixを実行し、修正案とその意図を確認する
  3. 人による妥当性確認:AIエージェントが提示した修正案が、仕様や設計意図に合っているかを開発者が確認する
  4. 再チェックへのループ:修正後に静的解析を再実行し、再びSARIFを生成して、指摘が解消されたかを確認する

6.2 SARIFである必要はないのでは?

上記のような使い方は、SARIFでなければ実現できないわけではありません。従来のCSVやXML、各ツール固有のJSON出力でも、必要な変換処理や表示方法を用意すれば、AIエージェントとの連携は可能です。

それでも当社が最初にSARIFを提案するのは、手軽に始めやすいからです。SARIFは静的解析結果を表す標準のフォーマットであり、VS CodeのSARIF Viewer、GitLabの脆弱性レポートなど、既存の開発エコシステムで扱いやすくなっています。

特にVS Codeでは、SARIF Viewerで指摘箇所に移動し、その場でGitHub Copilot ChatのExplainやFixを使うことで、追加の専用システムを作らなくても、静的解析結果を起点にしたAI支援を試すことができます。まずはこのような小さな連携から始め、将来的には設計情報やビルド条件、過去の対応履歴などを組み合わせて、より精度の高い仕組みに発展させていく、という進め方が現実的です。

6.3 GitHub Copilotでやってみよう

実際に、SARIF Viewerで表示した静的解析結果を起点に、GitHub Copilot Chatに説明や修正案を生成させてみましょう。

  1. はじめに、VS CodeにGitHub Copilot Chat拡張機能をインストールします。インストール後、GitHubアカウントでサインインし、GitHub Copilot Chatを利用できる状態にしてください。(※VS Code Version 1.116以降では、GitHub Copilot Chat拡張機能が標準で搭載されています。)
  2. SARIFファイルをSARIF Viewerで開き、VS Code上で静的解析の結果を確認できるようにします。SARIF Viwerが起動しないときは、コマンドパレットから、"SARIF: Show Panel"を実行するとファイル選択が可能になりますので、そこから該当するSARIFファイルを選択してください。
  3. PROBLEMS(問題)パネル上で表示されているSARIFで取り込んだ静的解析の警告の上で右クリックしてみてください。環境によっては Explain、Fix などのGitHub Copilot Chat関連の操作が表示されます。これらを実行することで、検出された指摘の説明や修正案をGitHub Copilotに生成させることができます。

  4. 同じ操作は、コードエディタ上からも実行できます。赤線や黄色線が表示されているコード部分、または修正したいコード範囲を選択して右クリックすると、ExplainFix などの操作が表示されます。これを実行すると、該当部分の説明や修正コードの案をGitHub Copilotに提案させることができます。

注意

右クリックで表示される FixExplain などの項目は、GitHub Copilot / GitHub Copilot Chat拡張機能をインストールすることで利用できます。

ただし、これらの機能を通して行う推論(説明や修正案)には制約があります。この点については、今後のコラムで別途説明いたします。

7. まとめ

  • SARIFという共通フォーマットは、AIエージェントで静的解析結果の選別・理解・誤検出の仕分け・修正案作成・再チェックを試すための「共通の入口」になる
  • ツールごとにバラバラな出力形式を統一することで、複数ツールの結果を共通のワークフローに載せやすくなる
  • CppcheckをはじめSARIFに直接対応するツールが増えており、対応していないツールでも変換ツールが用意されているケースが多い
  • 出力したSARIFは、VS CodeのSARIF Viewer拡張機能やGitLabの脆弱性レポート機能などで可視化できる

この連載の記事一覧

連載|静的解析×AIエージェントを始めよう!

  • 第1回 SARIFを使う
  • 第2回 GitHub Copilot×SARIFの留意点(前編)
  • 第3回 GitHub Copilot×SARIFの留意点(中編)
  • 第4回 GitHub Copilot×SARIFの留意点(後編)
  • 第5回 タイトル未定

静的解析ツールを入れ替えたり、大がかりな基盤を構築したりする必要はありません。まずは今使っている静的解析ツールの出力をSARIFに揃えるところから、静的解析×AIエージェントの第一歩を始めてみてはいかがでしょうか。

次回以降はSARIFをGitHub Copilot Chatと組み合わせた際の挙動を検証します。第2回でDiagnostic化の過程、第3回でCopilotが受け取る情報の範囲、第4回でcodeFlowsの扱いまでを解説いたします。静的解析×AIエージェントの実像に迫ります。

このコラムの著者

株式会社ユビキタスAI

エンベデッド第3部 セールス&PM セクション

藤江 克彦​(ふじえ かつひこ)

より詳しく技術や​関連製品について​知りたい方へ

本コラムに関係する技術や関連する製品について知りたい方は、お気軽にご相談ください。


製品情報

高精度静的解析ツール

CodeSonar

世界トップレベルの解析能力で不具合や脆弱性の原因となるソースコードのバグを検出
製品ページを見る

CWE-1000は脆弱性じゃない⁉ CWEが直感的に分かりにくい理由

コラムを読む
メニューを閉じる
一つ前に戻る