Skip to main content

Code scanningの SARIF サポート

GitHub のリポジトリにあるサードパーティの静的分析ツールからの結果を表示するには、code scanning 用に SARIF 2.1.0 JSON スキーマの特定のサブセットをサポートする SARIF ファイルに結果を保存する必要があります。 デフォルトの CodeQL 静的分析エンジンを使用すると、結果は GitHub のリポジトリに自動的に表示されます。

Code scanning は、GitHub Enterprise Server の Organization 所有のリポジトリで利用できます。 この機能には、GitHub Advanced Security のライセンスが必要です。 詳細については、「GitHub Advanced Security について」を参照してください。

SARIF サポートについて

SARIF (Static Analysis Results Interchange Format) は、出力ファイル形式を定義する OASIS 標準です。 SARIF 標準は、静的分析ツールが結果を共有する方法を合理化するために使用されます。 Code scanning は、SARIF 2.1.0 JSON スキーマのサブセットをサポートしています。

サードパーティの静的コード分析エンジンから SARIF ファイルをアップロードするには、アップロードされたファイルが SARIF 2.1.0 バージョンを使用していることを確認する必要があります。 GitHub は SARIF ファイルを解析し、code scanning エクスペリエンスの一部としてリポジトリの結果を使用してアラートを表示します。 詳細については、「GitHub への SARIF ファイルのアップロード」を参照してください。 SARIF 2.1.0 JSON スキーマの詳細については、sarif-schema-2.1.0.json を参照してください。

CodeQL analysis workflow で GitHub Actions を使っている場合、または CodeQL CLI を使っている場合は、SARIF 2.1.0 のサポートされるサブセットが code scanning によって自動的に使われます。 詳しくは、「リポジトリの code scanning の設定」または「CI システムでの CodeQL CLI のインストール」をご覧ください。

同じコミットに対して複数の SARIF ファイルをアップロードし、各ファイルのデータを code scanning の結果として表示できます。 コミット用に複数の SARIF ファイルをアップロードする場合は、分析ごとに "カテゴリ" を指定する必要があります。 カテゴリを指定する方法は、分析方法によって異なります。

  • CodeQL CLI を直接使用して、SARIF ファイルを生成するときに --sarif-category 引数を codeql database analyze コマンドに渡します。 詳細については、「CI システムでの CodeQL CLI の設定」を参照してください。
  • GitHub Actions を codeql-action/analyze で使用すると、ワークフロー名とマトリックス変数 (通常は language) からカテゴリが自動的に設定されます。 これをオーバーライドするには、アクションの category 入力を指定します。これは、単一のワークフローでモノリポジトリのさまざまなセクションを分析する場合に便利です。
  • GitHub Actions を使用して他の静的分析ツールから結果をアップロードする場合、1 つのワークフローで同じツールに対して複数の結果ファイルをアップロードするには、category 入力を指定する必要があります。 詳細については、「GitHub Actions を使用した code scanning 分析のアップロード」を参照してください。
  • これらの方法のいずれかを使用していない場合は、アップロードする SARIF ファイルごとに一意の runAutomationDetails.id を指定する必要があります。 このプロパティの詳細については、下記の「runAutomationDetails オブジェクト」を参照してください。

同じカテゴリと同じツールからコミット用の 2 つ目の SARIF ファイルをアップロードすると、以前の結果が上書きされます。 ただし、1 つの GitHub Actions ワークフロー実行で同じツールとカテゴリに対して複数の SARIF ファイルをアップロードしようとすると、設定ミスが検出され、実行は失敗します。

GitHub は、SARIF ファイルのプロパティを使用してアラートを表示します。 たとえば、shortDescriptionfullDescription は code scanning アラートの先頭に表示されます。 location により、GitHub がコード ファイルにアノテーションを表示できるようになります。 詳細については、「リポジトリの code scanning アラートの管理」を参照してください。

SARIF を使い慣れていなく、詳細を確認したい場合は、Microsoft の SARIF tutorials リポジトリを参照してください。

実行全体で code scanning アラートを追跡するデータを提供する

新しいコード スキャンの結果がアップロードされるたびに、結果が処理され、アラートがリポジトリに追加されます。 同じ問題に対するアラートの重複を防ぐために、code scanning はフィンガープリントを使用してさまざまな実行結果を照合し、選択したブランチの最新の実行で 1 回だけ表示されるようにします。 これにより、ファイルが編集されたときに、アラートを適切なコードの行に照合させることができます。 結果の ruleID は、分析全体で同じである必要があります。

一貫性のあるファイルパスのレポート

安定したフィンガープリントの計算を可能にするために、ファイルパスは実行全体で一貫している必要があります。 同じ結果に対してファイルパスが異なる場合、新しい分析が行われるたびに新しいアラートが作成され、古いアラートが閉じられます。 これにより、同じ結果に対して複数のアラートが発生します。

フィンガープリント生成用のデータを含める

GitHub は、OASIS 標準の partialFingerprints プロパティを使用して、2 つの結果が論理的に同一の場合に検出します。 詳細については、OASIS ドキュメントの partialFingerprints プロパティのエントリを参照してください。

CodeQL analysis workflow によって、または CodeQL CLI を使って作成された SARIF ファイルには、フィンガープリント データが含まれます。 upload-sarif アクションを使用して SARIF ファイルをアップロードする場合にこのデータが欠落していると、GitHub は partialFingerprints フィールドにソース ファイルからデータの入力を試みます。 結果のアップロードの詳細については、「GitHub への SARIF ファイルのアップロード」を参照してください。

/code-scanning/sarifs API エンドポイントを使用してフィンガープリントデータなしで SARIF ファイルをアップロードする場合、code scanning アラートが処理され表示されますが、アラートが重複して表示される場合があります。 重複するアラートが表示されないようにするには、SARIF ファイルをアップロードする前に、指紋データを計算し、partialFingerprints プロパティを設定する必要があります。 upload-sarif アクションで便利な始点 https://github.com/github/codeql-action/blob/main/src/fingerprints.ts が使用されるスクリプトが見つかる場合があります。 API の詳細については、「SARIF データとして分析をアップロードする」を参照してください。

ルールと結果について

SARIF ファイルは、ルールと結果の両方をサポートします。 これらの要素に格納されている情報は似ていますが、目的は異なります。

  • ルールは、toolComponent オブジェクトに含まれる reportingDescriptor オブジェクトの配列です。 ここに、分析中に実行されるルールの詳細を格納します。 これらのオブジェクト内の情報は、通常、ツールを更新したときに変更される頻度が低いはずです。

  • 結果は、run オブジェクト内の results の下で、一連の result オブジェクトとして格納されます。 各 result オブジェクトには、コードベース内の 1 つのアラートの詳細が含まれています。 results オブジェクト内で、アラートを検出したルールを参照できます。

異なるコードベースを同じツールとルールで分析して生成された SARIF ファイルを比較すると、分析の結果に違いが見られますが、ルールにはありません。

ソース ファイルのルートの指定

Code scanning は、相対パスで報告された結果を、分析されたリポジトリのルートに対する相対パスとして解釈します。 結果に絶対 URI が含まれている場合、URI は相対 URI に変換されます。 その後、リポジトリにコミットされたファイルに対して相対 URI を照合できます。

絶対 URI から相対 URI への変換のソース ルートは、次のいずれかの方法で指定できます。

  • github/codeql-action/analyze アクションに対する checkout_path 入力
  • SARIF アップロード API エンドポイントに対する checkout_uri パラメーター。 詳しくは、REST API ドキュメントの「Code scanning」をご覧ください。
  • SARIF ファイルの invocation.workingDirectory.uri プロパティ

ソース ルートを指定する場合、絶対 URI を使用して指定された成果物の場所では、同じ URI スキームを使用する必要があります。 ソース ルートの URI スキームと 1 つ以上の絶対 URI の間に不一致がある場合、アップロードは拒否されます。

たとえば、SARIF ファイルは file:///github/workspace のソース ルートを使用してアップロードされます。

# Conversion of absolute URIs to relative URIs for location artifacts

file:///github/workspace/src/main.go -> src/main.go
file:///tmp/go-build/tmp.go          -> file:///tmp/go-build/tmp.go

両方の絶対 URI でソース ルートと同じ URI スキームが使用されると、ファイルが正常にアップロードされます。

SARIF ファイルを検証する

SARIF ファイルが code scanning と互換性があるかどうかは、GitHub 収集ルールと照らし合わせることで確認できます。 詳細については、Microsoft SARIF 検証ツールを参照してください。

注:

  • SARIF アップロードでは、アップロードごとに最大 5,000 件の結果がサポートされます。 この制限を超える結果はすべて無視されます。 ツールで生成される結果が多すぎる場合は、最も重要なルールまたはクエリの結果に焦点を当てるように構成を更新する必要があります。

  • SARIF アップロードでサポートされる gzip 圧縮の SARIF ファイルの最大サイズは、アップロードごとに 10 MB となります。 この制限を超えるアップロードはすべて拒否されます。 含まれる結果が多すぎるために SARIF ファイルが大きくなりすぎた場合は、最も重要なルールまたはクエリの結果に焦点を当てるように構成を更新する必要があります。

サポートされている SARIF 出力ファイルのプロパティ

CodeQL 以外のコード分析エンジンを使用する場合、サポートされている SARIF プロパティを確認して、GitHub での分析結果の表示方法を最適化できます。

注: "必須" としてマークされたプロパティには、明示的な値を指定する必要があります。 空の文字列は、必須のプロパティではサポートされていません。

有効な SARIF 2.1.0 出力ファイルはすべてアップロードできますが、code scanning は以下のサポートされているプロパティのみを使用します。

sarifLog オブジェクト

名前説明
$schema必須。 バージョン 2.1.0 の SARIF JSON スキーマの URI。 たとえば、https://json.schemastore.org/sarif-2.1.0.json のようにします。
version必須。 Code scanning では、SARIF バージョン 2.1.0 のみがサポートされます。
runs[]必須。 SARIF ファイルには、1 つ以上の実行の配列が含まれています。 各実行は、分析ツールの 1 回の実行を表します。 run の詳細については、「run オブジェクト」を参照してください。

run オブジェクト

Code scanning は run オブジェクトを使用して、ツールで結果をフィルターし、結果のソースに関する情報を提供します。 run オブジェクトには、結果を生成したツールに関する情報を含む tool.driver ツール コンポーネント オブジェクトが含まれます。 run ごとに、1 つの分析ツールの結果のみを取得できます。

名前説明
tool.driver必須。 分析ツールについて説明する toolComponent オブジェクト。 詳細については、「toolComponent オブジェクト」を参照してください。
tool.extensions[]省略可。 分析中にツールによって使用されるプラグインまたは拡張機能を表す toolComponent オブジェクトの配列。 詳細については、「toolComponent オブジェクト」を参照してください。
invocation.workingDirectory.uri省略可。 このフィールドは、checkout_uri (SARIF アップロード API のみ) または checkout_path (GitHub Actions のみ) が指定されていない場合にのみ使用されます。 この値は、physicalLocation オブジェクトで使用される絶対 URI を相対 URI に変換するために使用されます。 詳しくは、「ソース ファイルのルートの指定」を参照してください。
results[]必須。 分析ツールの結果。 Code scanning は GitHub に結果を表示します。 詳細については、「result オブジェクト」を参照してください。

toolComponent オブジェクト

名前説明
name必須。 分析ツールの名前。 Code scanning は、GitHub に名前を表示して、ツールで結果をフィルタできるようにします。
version省略可。 分析ツールのバージョン。 Code scanning は、バージョン番号を使用して、分析されているコードでの変更ではなく、ツールのバージョン変更により結果が変更された可能性がある場合に追跡します。 SARIF ファイルに semanticVersion フィールド含まれている場合、code scanning では version が使用されません。
semanticVersion省略可。 セマンティック バージョニング 2.0 形式で指定された分析ツールのバージョン。 Code scanning は、バージョン番号を使用して、分析されているコードでの変更ではなく、ツールのバージョン変更により結果が変更された可能性がある場合に追跡します。 SARIF ファイルに semanticVersion フィールド含まれている場合、code scanning では version が使用されません。 詳細については、セマンティック バージョニング ドキュメントの「セマンティック バージョニング 2.0.0」を参照してください。
rules[]必須。 ルールを表す reportingDescriptor オブジェクトの配列。 分析ツールはルールを使用して、分析対象のコードの問題を見つけます。 詳細については、「reportingDescriptor オブジェクト」を参照してください。

reportingDescriptor オブジェクト

ここに、分析中に実行されるルールの詳細を格納します。 これらのオブジェクト内の情報は、通常、ツールを更新したときに変更される頻度が低いはずです。 詳しくは、上の「ルールと結果について」を参照してください。

名前説明
id必須。 ルールの一意の識別子。 id は SARIF ファイルの他の部分から参照され、code scanning が GitHub に URL を表示するために使用できます。
name省略可。 ルールの名前です。 Code scanning は、GitHub のルールで結果をフィルタできるように名前を表示します。
shortDescription.text必須。 ルールの簡潔な説明。 Code scanning は、関連する結果の横にある GitHub の簡単な説明を表示します。
fullDescription.text必須。 ルールの説明。 Code scanning は、関連する結果の横にある GitHub の説明全体を表示します。 文字数は最大 1000 文字に制限されています。
defaultConfiguration.level省略可。 ルールの既定の重大度レベル。 Code scanning は、特定のルールの結果がどの程度重要であるかを理解するために、重要度レベルを使用します。 この値は、result オブジェクト内の level 属性でオーバーライドできます。 詳細については、「result オブジェクト」を参照してください。 既定値:warning
help.text必須。 テキスト形式を使用したルールのドキュメント。 Code scanning は、関連する結果の横にこのヘルプドキュメントを表示します。
help.markdown推奨。 Markdown 形式のルールのドキュメント。 Code scanning は、関連する結果の横にこのヘルプドキュメントを表示します。 help.markdown が使用可能な場合は、help.text の代わりに表示されます。
properties.tags[]省略可。 文字列の配列。 Code scanning は、tags を使用して、GitHub の結果をフィルターできます。 たとえば、security タグを含むすべての結果をフィルターすることができます。
properties.precision推奨。 このルールによって示される結果が true となる頻度を示す文字列。 たとえば、ルールの誤検知率が高いことがわかっている場合、精度は low である必要があります。 Code scanning は、GitHub の精度で結果を並べ替えるため、最高 level の精度と最高 precision の結果が最初に表示されます。 very-highhighmediumlow のいずれかにすることができます。
properties.problem.severity推奨。 セキュリティ以外のクエリによって生成されたアラートの重大度レベルを示す文字列。 これを properties.precision プロパティとともに使用すると、GitHub に既定で結果が表示されるかどうかが決定されるため、最高の problem.severity と最高の precision の結果が最初に表示されます。 errorwarning、または recommendation のいずれかにすることができます。
properties.security-severity推奨。 セキュリティ クエリ (@tags には security が含まれる) の重大度のレベル (0.0 から 10.0) を示すスコアを表す文字列。 これを properties.precision プロパティとともに使用すると、GitHub に既定で結果が表示されるかどうかが決定されるため、最高の security-severity と最高の precision の結果が最初に表示されます。 Code scanning は、数値スコアを次のように変換します。9.0 以上が critical、7.0 から 8.9 が high、4.0 から 6.9 が medium、3.9 以下が low です。

result オブジェクト

result オブジェクトには、コードベース内の 1 つのアラートの詳細が含まれています。 results オブジェクト内で、アラートを検出したルールを参照できます。 詳しくは、上の「ルールと結果について」を参照してください。

注:

  • SARIF アップロードでは、アップロードごとに最大 5,000 件の結果がサポートされます。 この制限を超える結果はすべて無視されます。 ツールで生成される結果が多すぎる場合は、最も重要なルールまたはクエリの結果に焦点を当てるように構成を更新する必要があります。

  • SARIF アップロードでサポートされる gzip 圧縮の SARIF ファイルの最大サイズは、アップロードごとに 10 MB となります。 この制限を超えるアップロードはすべて拒否されます。 含まれる結果が多すぎるために SARIF ファイルが大きくなりすぎた場合は、最も重要なルールまたはクエリの結果に焦点を当てるように構成を更新する必要があります。

名前説明
ruleId省略可。 ルールの一意識別子 (reportingDescriptor.id)。 詳細については、「reportingDescriptor オブジェクト」を参照してください。 Code scanning は、ルール識別子を使用して、GitHub のルールで結果をフィルタします。
ruleIndex省略可。 ツール コンポーネント rules 配列内の関連するルール (reportingDescriptor オブジェクト) のインデックス。 詳細については、「run オブジェクト」を参照してください。 このプロパティに使用できる範囲は 0 から 2^63 - 1 です。
rule省略可。 この結果のルール (レポート記述子) を見つけるために使用される参照。 詳細については、「reportingDescriptor オブジェクト」を参照してください。
level省略可。 結果の重大度。 このレベルは、ルールで定義されているデフォルトの重要度をオーバーライドします。 Code scanning は、レベルを使用して、GitHub の重要度で結果をフィルタします。
message.text必須。 結果を説明するメッセージ。 Code scanning は、結果のタイトルとしてメッセージテキストを表示します。 表示スペースが限られている場合、メッセージの最初の文のみが表示されます。
locations[]必須。 最大 10 個の結果が検出された場所のセット。 指定された場所ごとに変更を加えることでのみ問題を修正できる場合を除き、1 つの場所のみを含める必要があります。 メモ: code scanning が結果を表示するには、少なくとも 1 つの場所が必要です。 Code scanning は、このプロパティを使用して、結果を注釈するファイルを決定します。 この配列の最初の値のみが使用されます。 他のすべての値は無視されます。
partialFingerprints必須。 結果の一意の ID を追跡するために使用される文字列のセット。 Code scanning は、partialFingerprints を使用して、コミットとブランチで同じ結果であるものを正確に識別します。 Code scanning は、partialFingerprints がある場合、それを使用しようとします。 サード パーティーの SARIF ファイルを upload-action でアップロードしているときに partialFingerprints が SARIF ファイルに含まれていない場合は、このアクションで作成されます。 詳しくは、「実行全体でコード スキャン アラートを追跡するデータを提供する」を参照してください。 メモ: Code scanning では primaryLocationLineHash のみが使用されます。
codeFlows[].threadFlows[].locations[]省略可。 実行スレッドを介したプログラムの進行状況を記述する、threadFlow オブジェクトの location オブジェクトの配列。 codeFlow オブジェクトは、結果の検出に使用されるコード実行パターンを記述します。 コードフローが入力されている場合、code scanning は、関連する結果の GitHub のコードフローを拡張します。 詳細については、「location オブジェクト」を参照してください。
relatedLocations[]この結果に関連する場所。 結果メッセージに埋め込まれている場合、Code scanning は、関連する場所にリンクします。 詳細については、「location オブジェクト」を参照してください。

location オブジェクト

プログラミングアーティファクト内の場所(リポジトリ内のファイルやビルド中に生成されたファイルなど)。

名前説明
location.id省略可。 この場所を単一の結果オブジェクト内の他のすべての場所と区別する一意の識別子。 このプロパティに使用できる範囲は 0 から 2^63 - 1 です。
location.physicalLocation必須。 アーティファクトとリージョンを識別します。 詳細については、physicalLocation を参照してください。
location.message.text省略可。 場所に関連するメッセージ。

physicalLocation オブジェクト

名前説明
artifactLocation.uri必須。 アーティファクトの場所を示す URI (通常はリポジトリ内にあるか、ビルド中に生成されたファイル)。 最良の結果を得るには、これが分析対象の GitHub リポジトリのルートからの相対パスであることをお勧めします。 たとえば、「 src/main.js 」のように入力します。 成果物 URI について詳しくは、「ソース ファイルのルートの指定」を参照してください。
region.startLine必須。 リージョンの最初の文字の行番号。
region.startColumn必須。 リージョンの最初の文字の列番号。
region.endLine必須。 リージョンの最後の文字の行番号。
region.endColumn必須。 リージョンの末尾に続く文字の列番号。

runAutomationDetails オブジェクト

runAutomationDetails オブジェクトには、実行の ID を指定する情報が含まれています。

メモ: runAutomationDetails は SARIF v2.1.0 オブジェクトです。 CodeQL CLIを使っているなら、使用するSARIFのバージョンを指定できます。 runAutomationDetails と同等のオブジェクトは、SARIF v1 で <run>.automationId、SARIF v2 で <run>.automationLogicalId です。

名前説明
id省略可。 分析のカテゴリと実行 ID を識別する文字列。 同じツールとコミットに対して、ただし様々な言語やコードの様々な部分にを処理した場合に、複数のSARIFファイルをアップロードする際に使ってください。

runAutomationDetails オブジェクトの使用は省略可能です。

id フィールドには、分析のカテゴリと実行 ID を含めることができます。 id フィールドの実行 ID の部分は使いませんが、保存はされます。

カテゴリを使って、同じツールあるいはコミットに対して行われる、ただし様々な言語やコードの様々な部分に対して行われる複数の分析を区別してください。 実行IDを使って、分析が実行された日付など、特定の分析の実行を識別してください。

idcategory/run-id として解釈されます。 id にスラッシュ (/) が含まれていない場合は、文字列全体が run_id であり、category は空です。 それ以外の場合、category は最後のスラッシュまでの文字列内のすべてであり、run_id はそれ以降のすべてです。

idcategoryrun_id
my-analysis/tool1/2021-02-01my-analysis/tool12021-02-01
my-analysis/tool1/my-analysis/tool1run-id なし
my-analysis for tool1カテゴリなしmy-analysis for tool1
  • "my-analysis/tool1/2021-02-01" という id での実行は、"my-analysis/tool1" というカテゴリに属します。 おそらく、これは2021 年2月2日からの実行です。
  • "my-analysis/tool1/" という id での実行は "my-analysis/tool1" というカテゴリに属しますが、そのカテゴリの他の実行とは区別されません。
  • "my-analysis for tool1" が id の実行は、一意の識別子を持ちますが、いずれかのカテゴリに属していると推定できません。

runAutomationDetails オブジェクトと id フィールドの詳細については、OASIS ドキュメントの「runAutomationDetails オブジェクト」を参照してください。

サポートされている残りのフィールドは無視されることに注意してください。

SARIF 出力ファイルの例

次の例の SARIF 出力ファイルは、サポートされているプロパティと値の例を示しています。

最低限必要なプロパティの例

次の SARIF 出力ファイルには、code scanning の結果が期待どおりに機能するために最低限必要なプロパティを示す値の例が示されています。 プロパティを削除したり、値を省略したり、空の文字列を使用した場合、このデータは正しく表示されないか、GitHub で同期されません。

{
  "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "Tool Name",
          "rules": [
            {
              "id": "R01"
                      ...
              "properties" : {
                 "id" : "java/unsafe-deserialization",
                 "kind" : "path-problem",
                 "name" : "...",
                 "problem.severity" : "error",
                 "security-severity" : "9.8",
               }
            }
          ]
        }
      },
      "results": [
        {
          "ruleId": "R01",
          "message": {
            "text": "Result text. This result does not have a rule associated."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "fileURI"
                },
                "region": {
                  "startLine": 2,
                  "startColumn": 7,
                  "endColumn": 10
                }
              }
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "39fa2ee980eb94b0:1"
          }
        }
      ]
    }
  ]
}

サポートされているすべての SARIF プロパティを示す例

次の SARIF 出力ファイルには、code scanning でサポートされているすべての SARIF プロパティを示す値の例が示されています。

{
  "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "Tool Name",
          "semanticVersion": "2.0.0",
          "rules": [
            {
              "id": "3f292041e51d22005ce48f39df3585d44ce1b0ad",
              "name": "js/unused-local-variable",
              "shortDescription": {
                "text": "Unused variable, import, function or class"
              },
              "fullDescription": {
                "text": "Unused variables, imports, functions or classes may be a symptom of a bug and should be examined carefully."
              },
              "defaultConfiguration": {
                "level": "note"
              },
              "properties": {
                "tags": [
                  "maintainability"
                ],
                "precision": "very-high"
              }
            },
            {
              "id": "d5b664aefd5ca4b21b52fdc1d744d7d6ab6886d0",
              "name": "js/inconsistent-use-of-new",
              "shortDescription": {
                "text": "Inconsistent use of 'new'"
              },
              "fullDescription": {
                "text": "If a function is intended to be a constructor, it should always be invoked with 'new'. Otherwise, it should always be invoked as a normal function, that is, without 'new'."
              },
              "properties": {
                "tags": [
                  "reliability",
                  "correctness",
                  "language-features"
                ],
                "precision": "very-high"
              }
            },
            {
              "id": "R01"
            }
          ]
        }
      },
      "automationDetails": {
        "id": "my-category/"
      },
      "results": [
        {
          "ruleId": "3f292041e51d22005ce48f39df3585d44ce1b0ad",
          "ruleIndex": 0,
          "message": {
            "text": "Unused variable foo."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "main.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 2,
                  "startColumn": 7,
                  "endColumn": 10
                }
              }
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "39fa2ee980eb94b0:1",
            "primaryLocationStartColumnFingerprint": "4"
          }
        },
        {
          "ruleId": "d5b664aefd5ca4b21b52fdc1d744d7d6ab6886d0",
          "ruleIndex": 1,
          "message": {
            "text": "Function resolvingPromise is sometimes invoked as a constructor (for example [here](1)), and sometimes as a normal function (for example [here](2))."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "src/promises.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 2
                }
              }
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "5061c3315a741b7d:1",
            "primaryLocationStartColumnFingerprint": "7"
          },
          "relatedLocations": [
            {
              "id": 1,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "src/ParseObject.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 2281,
                  "startColumn": 33,
                  "endColumn": 55
                }
              },
              "message": {
                "text": "here"
              }
            },
            {
              "id": 2,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "src/LiveQueryClient.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 166
                }
              },
              "message": {
                "text": "here"
              }
            }
          ]
        },
        {
          "ruleId": "R01",
          "message": {
            "text": "Specifying both [ruleIndex](1) and [ruleID](2) might lead to inconsistencies."
          },
          "level": "error",
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "full.sarif",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 54,
                  "startColumn": 10,
                  "endLine": 55,
                  "endColumn": 25
                }
              }
            }
          ],
          "relatedLocations": [
            {
              "id": 1,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "full.sarif"
                },
                "region": {
                  "startLine": 81,
                  "startColumn": 10,
                  "endColumn": 18
                }
              },
              "message": {
                "text": "here"
              }
            },
            {
              "id": 2,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "full.sarif"
                },
                "region": {
                  "startLine": 82,
                  "startColumn": 10,
                  "endColumn": 21
                }
              },
              "message": {
                "text": "here"
              }
            }
          ],
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "physicalLocation": {
                          "region": {
                            "startLine": 11,
                            "endLine": 29,
                            "startColumn": 10,
                            "endColumn": 18
                          },
                          "artifactLocation": {
                            "uriBaseId": "%SRCROOT%",
                            "uri": "full.sarif"
                          }
                        },
                        "message": {
                          "text": "Rule has index 0"
                        }
                      }
                    },
                    {
                      "location": {
                        "physicalLocation": {
                          "region": {
                            "endColumn": 47,
                            "startColumn": 12,
                            "startLine": 12
                          },
                          "artifactLocation": {
                            "uriBaseId": "%SRCROOT%",
                            "uri": "full.sarif"
                          }
                        }
                      }
                    }
                  ]
                }
              ]
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "ABC:2"
          }
        }
      ],
      "columnKind": "utf16CodeUnits"
    }
  ]
}