Skip to main content

此版本的 GitHub Enterprise Server 已于以下日期停止服务 2026-06-02. 即使针对重大安全问题,也不会发布补丁。 为了获得更好的性能、更高的安全性和新功能,请升级到最新版本的 GitHub Enterprise。 如需升级帮助,请联系 GitHub Enterprise 支持

对代码扫描的 SARIF 支持

确保来自第三方工具的 SARIF 文件符合 GitHub标准。

谁可以使用此功能?

Code scanning 可用于以下存储库类型:

  • GitHub.com 上的公共存储库
  • GitHub Team、GitHub Enterprise Cloud 或 GitHub Enterprise Server 上的组织拥有的存储库,已启用 GitHub Advanced Security

GitHub 可以分析第三方工具生成的 SARIF 文件,以在存储库中显示 code scanning 警报。 有关详细信息,请参阅“关于用于代码扫描的 SARIF 文件”。

本文重点介绍 SARIF 文件的关键属性,以帮助上传满足 GitHub其要求的 SARIF 文件,并可以转换为有用的警报。

如果您将 GitHub Actions 与 CodeQL 分析工作流程 配合使用,或者使用 CodeQL CLI,则 code scanning 的结果将自动使用 SARIF 2.1.0 的受支持子集。

用于防止重复警报的数据

每次上传新代码扫描的结果时,都会处理结果并将警报添加到存储库中。 为防止针对同一问题发出重复警报,code scanning 使用指纹匹配不同次运行中的结果,使其只在所选分支的最新一次运行中显示一次。 这样可以在编辑文件时将警报与正确的代码行匹配。 结果的 ruleId 必须在分析中相同。

一致的文件路径

文件路径必须在运行间保持一致,以实现稳定指纹的计算。 如果文件路径对于相同结果有所不同,则每次进行新分析时,都会创建新警报,并关闭旧警报。 这会导致相同结果具有多个警报。

指纹生成

GitHub partialFingerprints使用 OASIS 标准中的属性检测两个结果在逻辑上是否相同。 有关详细信息,请参阅 OASIS 文档中的 partialFingerprints 属性条目。

由 CodeQL 分析工作流程 创建或使用 CodeQL CLI 创建的 SARIF 文件包含指纹数据。 如果您使用 upload-sarif 操作上传 SARIF 文件,并且缺少此数据,GitHub 会尝试根据源文件填充 partialFingerprints 字段。 有关上传结果的详细信息,请参阅 将 SARIF 文件上传到 GitHub

如果使用 API 终结点上传没有指纹数据的 /code-scanning/sarifs SARIF 文件, code scanning 则会处理并显示警报,但用户可能会看到重复的警报。 为避免看到重复警报,应在上传 SARIF 文件之前计算指纹数据并填充 partialFingerprints 属性。 你可能会发现 upload-sarif 操作使用一个有用的起点的脚本: https://github.com/github/codeql-action/blob/main/src/fingerprints.ts 。 有关该 API 的详细信息,请参阅 适用于代码扫描的 REST API 终结点

规则和结果

SARIF 文件支持规则和结果。 这些元素中存储的信息相似,但用途不同。

  • 规则是包含在 reportingDescriptor 对象中的 toolComponent 对象数组。 可在此处存储分析过程中运行的规则的详细信息。 这些对象中的信息应该很少更改,通常在更新工具时更改。
  • 结果存储为 result 对象中 results 下的一系列 run 对象。 每个 result 对象都包含代码库中一个警报的详细信息。 在 results 对象中,可以引用检测到警报的规则。

当比较通过使用相同工具和规则分析不同代码库生成的 SARIF 文件时,你应会看到分析结果(而不是规则)存在差异。

源文件位置

指定源文件位置和代码行可确保代码扫描警报准确显示在包含已识别问题的文件内,以便有针对性地解决问题。

这种精准率提高了代码评审和解决过程的效率,简化了开发工作流,使开发人员能够在他们的代码库上下文中直接解决问题。

Code scanning 还会在拉取请求的检查结果中显示警报,前提是该警报标识出的所有代码行都出现在拉取请求差异中。

若要在拉取请求检查中显示,警报必须满足以下所有条件:

  • 警报标识的所有代码行(包括警报的第一行)都存在于拉取请求差异中。
  • 警报必须存在于拉取请求中添加或编辑的代码行中,而不是已删除的行中。

提交的 SARIF 文件中的 physicalLocation 对象标识警报的代码行。 有关详细信息,请参阅 physicalLocation 对象

源文件的根位置

Code scanning 将使用相对路径报告的结果解释为与分析存储库根目录相关的结果。 如果结果包含绝对 URI,则 URI 会转换为相对 URI。 随后可以将相对 URI 与提交到存储库的文件进行匹配。

可以通过以下方法之一提供源根,用于从绝对 URI 转换为相对 URI。

如果提供源根,则使用绝对 URI 指定的项目的任何位置都必须使用相同 URI 方案。 如果源根的 URI 方案与一个或多个绝对 URI 不匹配,则上传会被拒绝。

例如,使用 file:///github/workspace 的源根上传 SARIF 文件。

# 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 方案。

如果结果的相对 URI 与使用符号链接定义的文件相匹配,则代码扫描将无法显示结果。 因此,你需要解析任何符号链接的文件,并使用解析的 URI 报告这些文件中的任何结果。

文件兼容性

可以通过根据code scanning引入规则对其进行测试来检查 SARIF 文件是否兼容GitHub。 有关详细信息,请访问 Microsoft SARIF 验证程序

对于每个 gzip 压缩 SARIF 文件,SARIF 上传支持的最大大小为 10 MB。 任何超过此限制的上传都将被拒绝。 如果 SARIF 文件由于包含太多结果而过大,则应更新配置,以将重点放在最重要的规则或查询的结果上。 有关详细信息,请参阅“SARIF 结果文件太大”。

Code scanning 支持上传下表中数据对象的最大条目数。 如果这些对象中的任何一个超过其最大值,则 SARIF 文件将遭到拒绝。 对于某些对象,将显示的值的数量还有额外限制。 尽可能显示最重要的值。 若要在分析中包含超出受支持限制的数据时充分利用分析,请尝试优化分析配置(例如,对于 CodeQL 工具,识别和禁用最干扰的查询)。 有关详细信息,请参阅“SARIF 结果超出一个或多个限制”。

SARIF 数据最大值数据截断限制
每个文件的运行次数20
每次运行的结果数25,000只包括前 5,000 条结果,并按严重性确定优先级。
每次运行的规则数25,000
每次运行的工具扩展数100
每个结果的线程流位置数10,000只包括前 1,000 个线程流位置,按优先级排序。
每个结果的位置数1,000只包括 100 个位置。
每个规则的标记数20只包括 10 个标记。
警报限制1,000,000

有关其他错误的信息,请参阅 排查 SARIF 上传问题

支持的属性

如果你使用的代码分析引擎不是 CodeQL,则可以查看受支持的 SARIF 属性,以优化分析结果在 GitHub 上的显示方式。

注意

对于标记为“required”的任何属性,你都必须提供明确的值。 必填属性不支持空字符串。

可以上传任何有效的 SARIF 2.1.0 输出文件, code scanning 但只会使用以下受支持的属性。

sarifLog 对象

Name必需Description
$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 文件包含一个或多个运行的数组。 每个运行代表分析工具的一次运行。 有关 run 的详细信息,请参阅 run 对象

run 对象

Code scanning 使用 run 对象按工具筛选结果,并提供有关结果源的信息。 run 对象包含 tool.driver 工具组件对象,该对象包含有关生成结果的工具的信息。 每个 run 只能获得一个分析工具的结果。

Name必需Description
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必需Description
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 对象

可在此处存储分析过程中运行的规则的详细信息。 这些对象中的信息应该很少更改,通常在更新工具时更改。 有关详细信息,请参阅上面的 规则和结果

Name必需Description
id规则的唯一标识符。
id被 SARIF 文件的其他部分引用,并且可被 code scanning 用于在 GitHub 上显示 URL。
name规则的名称。
Code scanning 显示名称,以便在 GitHub 上按规则筛选结果。 限制为 255 个字符。
shortDescription.text规则的简介。
Code scanning 在 GitHub 上显示相关结果旁边的简短说明。 限制为 1024 个字符。
fullDescription.text规则的描述。
Code scanning 在 GitHub 上显示相关结果旁边的完整描述。 限制为 1024 个字符。
defaultConfiguration.level规则的默认严重性级别。
Code scanning 使用严重性级别来帮助了解结果对给定规则的关键程度。 默认情况下,defaultConfiguration.level 设置为 warning。 但是,可以通过在与结果关联的对象 level 中设置 result 属性,替代默认的规则级别。 有关详细信息,请参阅 result 对象的相关文档。
defaultConfiguration.level 的有效值为:notewarningerror
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 的结果优先显示。 可以是以下选项之一:errorwarningrecommendation
properties.security-severity(建议仅用于安全规则)如果包含此字段的值,规则的结果将被视为安全结果。 一个表示分数的字符串,该分数指示安全查询的严重性级别,该值介于 0.0 到 10.0 之间(@tags 包括 security)。 此项与 properties.precision 属性一起决定结果是否默认在 GitHub 上显示,以便优先显示具有最高 security-severity 和最高 precision 的结果。
Code scanning将数值分数对应如下:9.0 以上为 critical,7.0 到 8.9 为 high,4.0 到 6.9 为 medium,0.1 到 3.9 为 low。 值 0.0 或给定范围之外的任何其他值被视为没有安全严重性。

result 对象

每个 result 对象都包含代码库中一个警报的详细信息。 在 results 对象中,可以引用检测到警报的规则。 有关详细信息,请参阅上面的 规则和结果

Name必需Description
ruleId规则的唯一标识符 (reportingDescriptor.id)。 有关详细信息,请参阅 reportingDescriptor 对象
Code scanning 使用规则标识符按规则依据 GitHub筛选结果。
ruleIndex工具组件 reportingDescriptor 数组中关联规则(rules 对象)的索引。 有关详细信息,请参阅 run 对象。 此属性的允许范围 0 到 2^63 - 1。
rule用于定位此结果的规则(报告描述符)的引用。 有关详细信息,请参阅 reportingDescriptor 对象
level结果的严重性。 此级别覆盖规则定义的默认严重程度。
Code scanning 使用级别在 GitHub 上按严重性筛选结果。
message.text描述结果的消息。
Code scanning 将消息文本显示为结果的标题。 当可见空间有限时,仅显示消息的第一句。
locations[]最多可以检测到 10 个结果的位置集。 应只包含一个位置,除非只能通过在每个指定位置进行更改来更正问题。
注意: 显示结果至少需要 code scanning 一个位置。
Code scanning 将使用此属性来决定把结果标注到哪个文件中。 仅使用此数组的第一个值。 将忽略所有其他值。
partialFingerprints一组字符串,用于跟踪结果的唯一标识。
Code scanning 使用 partialFingerprints 来准确识别哪些结果在不同提交和分支之间是相同的。
Code scanning 将尝试使用存在的 partialFingerprints。 如果使用 upload-action 上传第三方 SARIF 文件,当这些文件未包含在 SARIF 文件中时,该操作将为你创建 partialFingerprints。 有关详细信息,请参阅《在多次运行中提供用于跟踪代码扫描警报的数据》
**注意:**Code scanning 仅使用 primaryLocationLineHash.
codeFlows[].threadFlows[].locations[]
location 对象的 threadFlow 对象数组,通过执行线程描述程序进度。
codeFlow 对象描述用于检测结果的代码执行模式。 如果提供了代码流, code scanning 则会针对相关结果扩展代码流 GitHub 。 有关详细信息,请参阅 location 对象
relatedLocations[]与此结果相关的一组位置。 当结果消息中嵌入相关位置时,Code scanning 将链接到这些相关位置。 有关详细信息,请参阅 location 对象

location 对象

编程构件中的位置,例如仓库中的文件或在构建过程中生成的文件。

Name必需Description
location.id用于在单个结果对象中区分此位置与所有其他位置的唯一标识符。 此属性的允许范围 0 到 2^63 - 1。
location.physicalLocation标识构件和区域。 有关详细信息,请参阅 physicalLocation
location.message.text与位置相关的消息。

physicalLocation 对象

Name必需Description
artifactLocation.uri表示构件位置的 URI,通常是存储库中或在构建期间生成的文件。 为了获得最佳结果,我们建议这应该是正在分析的GitHub存储库根目录的相对路径。 例如,src/main.js。 有关构件 URI 的详细信息,请参阅《指定源文件的根目录》
region.startLine区域中第一个字符的行号。
region.startColumn区域中第一个字符的列号。
region.endLine区域中最后一个字符的行号。
region.endColumn区域末尾后面的字符的列号。

runAutomationDetails 对象

runAutomationDetails 对象包含指定运行标识的信息。

Name必需Description
id标识分析和运行 ID 类别的字符串。 如果您想要为同一工具上传多个 SARIF 文件,但在不同语言或代码的不同部分执行,请使用。

使用 runAutomationDetails 对象是可选的。

id 字段可以包含分析类别和运行 ID。 我们不使用 id 字段的运行 ID 部分,但会存储它。

使用类别来区分同一工具或提交的多次分析,但是在不同语言或代码的不同部分进行。 使用运行 ID 来识别分析的特定运行,例如分析的运行日期。

id 被解释为 category/run-id。 如果 id 不包含正斜杠 (/),则整个字符串为 run_id,而 category 为空。 否则,category 是字符串中直到最后一个正斜杠的所有内容,而 run_id 是之后的所有内容。

id分类run_id
my-analysis/tool1/2022-01-02my-analysis/tool12022-01-02
my-analysis/tool1/my-analysis/tool1None
工具 1 的我的分析None工具 1 的我的分析
  • id 为“my-analysis/tool1/2021-02-01”的运行属于类别“my-analysis/tool1”。
  • id 为“my-analysis/tool1/”的运行属于类别“my-analysis/tool1”,但未与该类别中的其他运行区分。
  • id 为“my-analysis for tool1”的运行具有唯一的标识符,但无法推断属于任何类别。

有关 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 生成器的相对 URI 指南

此 SARIF 输出文件提供了字段 originalUriBaseIds 的示例值,展示了在使用相对 URI 引用时,SARIF 生成器应包含的最低必需属性。

注意

虽然此属性不是正确显示结果所必需的GitHubcode scanning,但使用相对 URI 引用时,需要生成有效的 SARIF 输出。

{
  "$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",
               }
            }
          ]
        }
      },
      "originalUriBaseIds": {
        "PROJECTROOT": {
         "uri": "file:///C:/Users/Mary/code/TheProject/",
           "description": {
             "text": "The root directory for all project files."
           }
        },
         "%SRCROOT%": {
           "uri": "src/",
           "uriBaseId": "PROJECTROOT",
           "description": {
             "text": "The root of the source tree."
           }
         }
      },
      "results": [
        {
          "ruleId": "R01",
          "message": {
            "text": "Result text. This result does not have a rule associated."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "fileURI",
                  "uriBaseId": "%SRCROOT%"
                },
                "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"
    }
  ]
}