コードスキャンの SARIF サポート

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

Code scanningは、Organizationが所有するリポジトリでGitHub Advanced Securityが有効化されていれば利用できます。 詳しい情報については、「GitHub Advanced Security について」を参照してください。

Note: The CodeQLランナー is being deprecated. Please use the CodeQL CLI version 2.6.2 or greater instead. GitHub Enterprise Server 3.3 will be the final release series that supports the CodeQLランナー. On GitHub Enterprise Cloud, the CodeQLランナー will be supported until March 2022. For more information, see the CodeQL runner deprecation.

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 エクスペリエンスの一部としてリポジトリの結果を使用してアラートを表示します。 詳しい情報については、「SARIF ファイルを GitHub にアップロードする」を参照してください。 SARIF 2.1.0 JSON スキーマの詳細については、「sarif-schema-2.1.0.json」を参照してください。

SARIF ファイルに partialFingerprints が含まれていない場合、GitHub Actions を使用して SARIF ファイルをアップロードすると、partialFingerprints フィールドが計算されます。 詳しい情報については「リポジトリに対するcode scanningのセットアップ」あるいは「CIシステムでのCodeQLランナーの実行」を参照してください。

CodeQL CLIを使っているなら、使用するSARIFのバージョンを指定できます。 詳しい情報については「CIシステムでのCodeQL CLIの設定」を参照してください。

同じツールとコミットに対して複数のSARIFファイルをアップロードして、それぞれのファイルをcode scanningを使って分析できます。 それぞれのファイル中でrunAutomationDetails.idを指定することによって、それぞれの分析に対して「カテゴリ」を示すことができます。 同じカテゴリのSARIFファイル同士だけがお互いを上書きします。 このプロパティに関する詳しい情報については、以下のrunAutomationDetails objectを参照してください。

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

SARIF の使用が初めてで、詳細を確認する必要がある場合は、Microsoft の SARIF tutorials リポジトリを参照してください。

フィンガープリントを使用してアラートの重複を防止する

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

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

id は SARIF ファイルの他の部分から参照され、code scanning が GitHub に URL を表示するために使用できます。 upload-sarif アクションを使用して SARIF ファイルをアップロードし、このデータが欠落している場合、GitHub はソースファイルから partialFingerprints フィールドの入力を試みます。 結果のアップロードに関する詳しい情報については、「SARIF ファイルを GitHub にアップロードする」を参照してください。

/code-scanning/sarifs API エンドポイントを使用してフィンガープリントデータなしで SARIF ファイルをアップロードする場合、code scanning アラートが処理され表示されますが、アラートが重複して表示される場合があります。 アラートが重複して表示されないようにするには、フィンガープリントデータを計算し、partialFingerprints プロパティを入れてから SARIF ファイルをアップロードする必要があります。 upload-sarif アクションが使用しているスクリプト (https://github.com/github/codeql-action/blob/main/src/fingerprints.ts) は、取っ掛かりとして役立つかもしれません。 API に関する詳しい情報については、「解析を SARIF データとしてアップロードする」を参照してください。

SARIF ファイルを検証する

SARIF ファイルが code scanning と互換性があるかどうかは、GitHub 収集ルールと照らし合わせることで確認できます。 詳しい情報については、Microsoft SARIF validator にアクセスしてください。

ノート:

  • SARIF upload supports a maximum of 5000 results per upload. この制限を超えた結果は無視されます。 ツールがあまりに多くの結果を生成する場合、最も重要なルールやクエリに対する結果に焦点を当てるよう、設定を更新すべきです。

  • For each upload, SARIF upload supports a maximum size of 10 MB for the gzip-compressed SARIF file. Any uploads over this limit will be rejected. If your SARIF file is too large because it contains too many results, you should update the configuration to focus on results for the most important rules or queries.

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

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

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

sarifLog オブジェクト

名前説明
$schema必須。バージョン 2.1.0 の SARIF JSON スキーマの URI。 例: https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-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.name必須。分析ツールの名前。 Code scanning は、GitHub に名前を表示して、ツールで結果をフィルタできるようにします。
tool.driver.version任意。分析ツールのバージョン。 Code scanning は、バージョン番号を使用して、分析されているコードでの変更ではなく、ツールのバージョン変更により結果が変更された可能性がある場合に追跡します。 SARIF ファイルに semanticVersion フィールドが含まれている場合、version は code scanning で使用されません。
tool.driver.semanticVersion任意。セマンティックバージョニング 2.0 形式で指定された分析ツールのバージョン。 Code scanning は、バージョン番号を使用して、分析されているコードでの変更ではなく、ツールのバージョン変更により結果が変更された可能性がある場合に追跡します。 SARIF ファイルに semanticVersion フィールドが含まれている場合、version は code scanning で使用されません。 詳しい情報については、セマンティックバージョニングのドキュメントの「セマンティックバージョニング 2.0.0」を参照してください。
tool.driver.rules[]必須。ルールを表す reportingDescriptor オブジェクトの配列。 分析ツールはルールを使用して、分析対象のコードの問題を見つけます。 詳しい情報については、「reportingDescriptor オブジェクト」を参照してください。
results[]必須。分析ツールの結果。 Code scanning は GitHub に結果を表示します。 詳しい情報については、「result オブジェクト」を参照してください。

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.severityRecommended. A string that indicates the level of severity of any alerts generated by a non-security query. This, with the properties.precision property, determines whether the results are displayed by default on GitHub so that the results with the highest problem.severity, and highest precision are shown first. Can be one of: error, warning, or recommendation.
properties.security-severityRecommended. A score that indicates the level of severity, between 0.0 and 10.0, for security queries (@tags includes security). This, with the properties.precision property, determines whether the results are displayed by default on GitHub so that the results with the highest security-severity, and highest precision are shown first. Code scanning translates numerical scores as follows: over 9.0 is critical, 7.0 to 8.9 is high, 4.0 to 6.9 is medium and 3.9 or less is low.

result オブジェクト

ノート:

  • SARIF upload supports a maximum of 5000 results per upload. この制限を超えた結果は無視されます。 ツールがあまりに多くの結果を生成する場合、最も重要なルールやクエリに対する結果に焦点を当てるよう、設定を更新すべきです。

  • For each upload, SARIF upload supports a maximum size of 10 MB for the gzip-compressed SARIF file. Any uploads over this limit will be rejected. If your SARIF file is too large because it contains too many results, you should update the configuration to focus on results for the most important rules or queries.

名前説明
ruleId任意。ルールの一意の識別子(reportingDescriptor.id)。 詳しい情報については、「reportingDescriptor オブジェクト」を参照してください。 Code scanning は、ルール識別子を使用して、GitHub のルールで結果をフィルタします。
ruleIndex任意。ツールコンポーネントの rules 配列内の関連するルール(reportingDescriptor オブジェクト)のインデックス。 詳しい情報については、「run オブジェクト」を参照してください。
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 がある場合、それを使用しようとします。 upload-action を使用してサードパーティの SARIF ファイルをアップロードする場合、SARIF ファイルに含まれていないときに、アクションによって partialFingerprints が作成されます。 詳しい情報については、「フィンガープリントを使用してアラートの重複を防止する」を参照してください。 注釈: Code scanning は、primaryLocationLineHash のみを使用します。
codeFlows[].threadFlows[].locations[]任意。threadFlow オブジェクトに対する location オブジェクトの配列。実行スレッドを通してプログラムの進行状況を記述します。 codeFlow オブジェクトは、結果の検出に使用されるコード実行パターンを記述します。 コードフローが入力されている場合、code scanning は、関連する結果の GitHub のコードフローを拡張します。 詳しい情報については、「location オブジェクト」を参照してください。
relatedLocations[]この結果に関連する場所。 結果メッセージに埋め込まれている場合、Code scanning は、関連する場所にリンクします。 詳しい情報については、「location オブジェクト」を参照してください。

location オブジェクト

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

名前説明
location.id任意。この場所を単一の結果オブジェクト内の他のすべての場所と区別する一意の識別子。
location.physicalLocation必須。アーティファクトとリージョンを識別します。 詳しい情報については、「physicalLocation」を参照してください。
location.message.text任意。場所に関連するメッセージ。

physicalLocation オブジェクト

名前説明
artifactLocation.uri必須。アーティファクトの場所を示す URI(通常はリポジトリ内のファイル、またはビルド中に生成されたファイル)。 URI が相対の場合、分析されている GitHub リポジトリのルートに相対である必要があります。 たとえば、main.js または src/script.js は、リポジトリのルートを基準にしています。 URI が絶対の場合、code scanning は URI を使用してアーティファクトをチェックアウトし、リポジトリ内のファイルを照合できます。 例: https://github.com/ghost/example/blob/00/src/promiseUtils.js
region.startLine必須。リージョンの最初の文字の行番号。
region.startColumn必須。リージョンの最初の文字の列番号。
region.endLine必須。リージョンの最後の文字の行番号。
region.endColumn必須。リージョンの末尾に続く文字の列番号。

runAutomationDetailsオブジェクト

runAutomationDetailsオブジェクトには、実行のアイデンティティを指定する情報が含まれています。

ノート: 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はその後のすべての文字列になります。

idカテゴリrun_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 objectを参照してください。

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

SARIF 出力ファイルの例

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

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

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

{
  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-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://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-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"
    }
  ]
}

このドキュメントは役立ちましたか?

プライバシーポリシー

これらのドキュメントを素晴らしいものにするのを手伝ってください!

GitHubのすべてのドキュメントはオープンソースです。間違っていたり、はっきりしないところがありましたか?Pull Requestをお送りください。

コントリビューションを行う

OR, コントリビューションの方法を学んでください。

問題がまだ解決していませんか?