GitHub 可以解析第三方工具生成的 SARIF 文件,以在仓库中显示代码扫描警报。欲了解更多信息,请参阅 关于代码扫描的 SARIF 文件。
本文重点介绍 SARIF 文件的关键属性,帮助您上传符合 GitHub 要求的 SARIF 文件,并将其转换为有用的警报。
如果您在 GitHub Actions 中使用 CodeQL 分析工作流或使用 CodeQL CLI,则代码扫描结果会自动使用 SARIF 2.1.0 的受支持子集。
用于防止重复警报的数据
每次上传新的代码扫描结果时,系统会处理这些结果并在仓库中添加警报。为防止同一问题产生重复警报,代码扫描使用指纹在不同运行之间匹配结果,使其仅在所选分支的最新运行中出现一次。这使得在文件编辑时能够将警报匹配到正确的代码行。结果的 ruleId 必须在各次分析中保持一致。
一致的文件路径
文件路径必须在各次运行中保持一致,以便计算稳定的指纹。如果同一结果的文件路径不同,每次进行新分析时都会创建新的警报,而旧的警报会被关闭。这将导致同一结果出现多个警报。
指纹生成
GitHub 使用 OASIS 标准中的 partialFingerprints 属性来检测两个结果在逻辑上是否相同。欲了解更多信息,请参阅 OASIS 文档中的 partialFingerprints 属性 条目。
SARIF 文件由 CodeQL 分析工作流或使用 CodeQL CLI 创建时包含指纹数据。如果您使用 upload-sarif 操作上传 SARIF 文件且缺少此数据,GitHub 会尝试从源文件中填充 partialFingerprints 字段。有关上传结果的更多信息,请参阅 将 SARIF 文件上传到 GitHub。
如果您使用 /code-scanning/sarifs API 端点上传缺少指纹数据的 SARIF 文件,代码扫描警报仍会被处理并显示,但用户可能会看到重复警报。为避免出现重复警报,您应在上传 SARIF 文件之前计算指纹数据并填充 partialFingerprints 属性。您可能会发现 upload-sarif 操作使用的脚本是一个有用的起点:https://github.com/github/codeql-action/blob/main/src/fingerprints.ts。有关 API 的更多信息,请参阅 代码扫描的 REST API 端点。
规则与结果
SARIF 文件同时支持规则和结果。这些元素中存储的信息相似,但用途不同。
- 规则是包含在
toolComponent对象中的reportingDescriptor对象数组。您在此存储在分析期间运行的规则的详细信息。这些对象中的信息应很少更改,通常仅在您更新工具时更改。 - 结果作为一系列
result对象存放在run对象的results中。每个result对象包含代码库中一个警报的详细信息。在results对象中,您可以引用检测到警报的规则。
当您比较使用相同工具和规则对不同代码库进行分析所生成的 SARIF 文件时,您应看到分析结果的差异,而规则应保持不变。
源文件位置
指定源文件位置和代码行可确保代码扫描警报在包含已识别问题的文件中准确显示,从而实现有针对性的问题解决。
这种精确性提升了代码审查和解决流程的效率,通过让开发者直接在代码库的上下文中处理问题,简化了开发工作流。
当警报标识的所有代码行都出现在拉取请求的差异中时,代码扫描还会在拉取请求检查结果中显示警报。
要在拉取请求检查中显示,警报必须满足以下所有条件
- 警报标识的所有代码行(包括警报的第一行)都存在于拉取请求的差异中。
- 警报必须出现在拉取请求中新增或编辑的代码行,而不是已删除的行。
提交的 SARIF 文件中的 physicalLocation 对象标识警报对应的代码行。欲了解更多信息,请参阅 physicalLocation 对象。
源文件根位置
代码扫描将使用相对路径报告的结果解释为相对于被分析仓库根目录的路径。如果结果包含绝对 URI,则会将该 URI 转换为相对 URI。随后可以将相对 URI 与仓库中提交的文件匹配。
您可以通过以下任一方式提供用于将绝对 URI 转换为相对 URI 的源根。
checkout_path输入到github/codeql-action/analyze操作checkout_uri参数用于 SARIF 上传 API 端点。欲了解更多信息,请参阅 代码扫描的 REST API 端点。invocations[0].workingDirectory.uri在 SARIF 文件的run对象中的属性
如果您提供了源根,则使用绝对 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 报告这些文件中的结果。
文件兼容性
您可以通过针对 GitHub 收集规则进行测试,检查 SARIF 文件是否与代码扫描兼容。欲了解更多信息,请访问 Microsoft SARIF 验证器。
对于每个 gzip 压缩的 SARIF 文件,SARIF 上传支持的最大大小为 10 MB。超过此限制的上传将被拒绝。如果您的 SARIF 文件因包含过多结果而过大,您应调整配置,仅关注最重要的规则或查询的结果。欲了解更多信息,请参阅 SARIF 结果文件太大。
代码扫描支持上传以下表格中数据对象的最大条目数。如果任何对象超过其最大值,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 上的显示方式。
注意
对于标记为“必需”的任何属性,必须提供明确的值。空字符串不适用于必需属性。
可以上传任何有效的 SARIF 2.1.0 输出文件,但代码扫描仅使用以下受支持的属性。
sarifLog 对象
| 名称 | 是否必填 | 描述 |
|---|---|---|
$schema | SARIF JSON 架构的 URI(版本 2.1.0),例如 https://json.schemastore.org/sarif-2.1.0.json。 | |
version | 代码扫描仅支持 SARIF 版本 2.1.0。 | |
runs[] | SARIF 文件包含一个或多个运行的数组。每个运行代表一次分析工具的执行。有关 run 的更多信息,请参阅 run 对象。 |
run 对象
代码扫描使用 run 对象按工具筛选结果并提供结果来源信息。run 对象包含 tool.driver 工具组件对象,其中包含生成结果的工具信息。每个 run 只能包含一种分析工具的结果。
| 名称 | 是否必填 | 描述 |
|---|---|---|
tool.driver | 描述分析工具的 toolComponent 对象。欲了解更多信息,请参阅 toolComponent 对象。 | |
tool.extensions[] | 一个 toolComponent 对象数组,表示工具在分析期间使用的任何插件或扩展。欲了解更多信息,请参阅 toolComponent 对象。 | |
invocation.workingDirectory.uri | 仅在未提供 checkout_uri(仅 SARIF 上传 API)或 checkout_path(仅 GitHub Actions)的情况下使用此字段。该值用于将 physicalLocation 对象 中使用的绝对 URI 转换为相对 URI。欲了解更多信息,请参阅 指定源文件根位置。 | |
results[] | 分析工具的结果。代码扫描将在 GitHub 上显示这些结果。欲了解更多信息,请参阅 result 对象。 |
toolComponent 对象
| 名称 | 是否必填 | 描述 |
|---|---|---|
name | 分析工具的名称。代码扫描在 GitHub 上显示该名称,以便您按工具筛选结果。 | |
version | 分析工具的版本。代码扫描使用版本号来追踪结果是否因工具版本更改而改变,而非因被分析的代码更改。如果 SARIF 文件包含 semanticVersion 字段,则代码扫描不使用 version。 | |
semanticVersion | 使用语义化版本 2.0 格式指定的分析工具版本。代码扫描使用该版本号来追踪结果是否因工具版本更改而改变,而非因被分析的代码更改。如果 SARIF 文件包含 semanticVersion 字段,则代码扫描不使用 version。欲了解更多信息,请参阅语义化版本文档中的 Semantic Versioning 2.0.0。 | |
rules[] | 一个 reportingDescriptor 对象数组,代表规则。分析工具使用规则来查找被分析代码中的问题。欲了解更多信息,请参阅 reportingDescriptor 对象。 |
reportingDescriptor 对象
这里存储在分析期间运行的规则的详细信息。这些对象中的信息应很少更改,通常在您更新工具时更改。欲了解更多信息,请参阅上面的 规则与结果。
| 名称 | 是否必填 | 描述 |
|---|---|---|
id | 规则的唯一标识符。id 在 SARIF 文件的其他部分被引用,代码扫描可能会使用它在 GitHub 上显示 URL。 | |
name | 规则的名称。代码扫描显示该名称,以便在 GitHub 上按规则筛选结果。最长 255 个字符。 | |
shortDescription.text | 规则的简要描述。代码扫描在 GitHub 上的相应结果旁显示此短描述。最长 1024 个字符。 | |
fullDescription.text | 规则的完整描述。代码扫描在 GitHub 上的相应结果旁显示此完整描述。最长 1024 个字符。 | |
defaultConfiguration.level | 规则的默认严重性级别。代码扫描使用严重性级别帮助您了解给定规则的结果有多关键。默认情况下,defaultConfiguration.level 设置为 warning。您可以通过在与结果关联的 result 对象中设置 level 属性来覆盖规则的默认级别。欲了解更多信息,请参阅 result 对象 的文档。defaultConfiguration.level 的有效值为:note、warning 和 error。 | |
help.text | 使用文本格式的规则文档。代码扫描在相应结果旁显示此帮助文档。 | |
help.markdown | (推荐)使用 Markdown 格式的规则文档。代码扫描在相应结果旁显示此帮助文档。当 help.markdown 可用时,将显示它而不是 help.text。 | |
properties.tags[] | 字符串数组。代码扫描使用 tags 让您在 GitHub 上筛选结果。例如,可以筛选出所有带有 security 标签的结果。 | |
properties.precision | (推荐)表示该规则产生的结果真实程度的字符串。例如,如果某规则已知误报率高,则精度应为 low。代码扫描在 GitHub 上按精度对结果进行排序,使 level 最高且 precision 最高的结果优先显示。可取值为:very-high、high、medium 或 low。 | |
properties.problem.severity | (推荐)表示非安全查询生成的任何警报的严重程度的字符串。结合 properties.precision 属性,此字段决定结果是否默认在 GitHub 上显示,以便 problem.severity 最高且 precision 最高的结果优先展示。可取值为:error、warning 或 recommendation。 | |
properties.security-severity | (仅针对安全规则推荐)如果您为此字段提供值,则该规则的结果将被视为安全结果。该字段为字符串,表示评分,范围为大于 0.0 且不超过 10.0,适用于安全查询(@tags 包含 security)。结合 properties.precision 属性,此字段决定结果是否默认在 GitHub 上显示,以便 security-severity 最高且 precision 最高的结果优先展示。代码扫描将数值分数解释为:大于 9.0 为 critical,7.0‑8.9 为 high,4.0‑6.9 为 medium,0.1‑3.9 为 low。0.0 或超出该范围的其他值视为没有安全严重性。 |
result 对象
每个 result 对象包含代码库中一个警报的详细信息。在 results 对象中,您可以引用检测到警报的规则。欲了解更多信息,请参阅上面的 规则与结果。
| 名称 | 是否必填 | 描述 |
|---|---|---|
ruleId | 规则的唯一标识符(reportingDescriptor.id)。欲了解更多信息,请参阅 reportingDescriptor 对象。代码扫描使用规则标识符在 GitHub 上按规则筛选结果。 | |
ruleIndex | 关联规则(reportingDescriptor 对象)在工具组件 rules 数组中的索引。欲了解更多信息,请参阅 run 对象。此属性的允许范围为 0 到 2^63 - 1。 | |
rule | 用于定位此结果对应规则(报告描述符)的引用。欲了解更多信息,请参阅 reportingDescriptor 对象。 | |
level | 结果的严重性。此级别会覆盖规则定义的默认严重性。代码扫描使用该级别在 GitHub 上按严重性筛选结果。 | |
message.text | 描述结果的消息。代码扫描将消息文本显示为结果的标题。当可见空间受限时,仅显示消息的第一句。 | |
locations[] | 检测到结果的位置集合,最多可包含 10 项。除非问题只能通过在每个指定位置进行更改来纠正,否则仅应包含一个位置。注意:代码扫描显示结果至少需要一个位置。代码扫描将使用此属性决定在何文件上注释结果。仅使用该数组的第一个值,其他值将被忽略。 | |
partialFingerprints | 用于跟踪结果唯一身份的一组字符串。代码扫描使用 partialFingerprints 准确识别跨提交和分支的相同结果。如果存在,代码扫描将尝试使用 partialFingerprints。如果您使用 upload-action 上传第三方 SARIF 文件,且文件中未包含 partialFingerprints,该操作将为您创建它们。欲了解更多信息,请参阅 提供数据以跨运行跟踪代码扫描警报。注意:代码扫描仅使用 primaryLocationLineHash。 | |
codeFlows[].threadFlows[].locations[] | 一个 location 对象数组,属于 threadFlow 对象,用于描述程序在执行线程中的进程。codeFlow 对象描述用于检测结果的代码执行模式。如果提供了代码流,代码扫描将在 GitHub 上展开相应结果的代码流。欲了解更多信息,请参阅 location 对象。 | |
relatedLocations[] | 与此结果相关的一组位置。当这些位置嵌入结果消息时,代码扫描将链接到它们。欲了解更多信息,请参阅 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 | 一个字符串,用于标识分析的类别和运行 ID。如果您希望为同一工具和提交上传多个 SARIF 文件,但在不同语言或代码的不同部分进行分析,请使用此字段。 |
使用 runAutomationDetails 对象为可选。
id 字段可以包含分析类别和运行 ID。我们不使用 id 字段中的运行 ID 部分,但会保存它。
使用类别区分同一工具或提交的多个分析,但在不同语言或代码的不同部分进行。使用运行 ID 标识特定的分析运行,例如分析执行的日期。
id 被解释为 category/run-id。如果 id 中不包含斜杠(/),则整个字符串即为 run_id,category 为空。否则,category 为最后一个斜杠之前的所有字符,run_id 为其后的所有字符。
id | category (类别) | run_id |
|---|---|---|
| my-analysis/tool1/2022-01-02 | my-analysis/tool1 | 2022-01-02 |
| my-analysis/tool1/ | my-analysis/tool1 | 无 |
| my-analysis for tool1 | 无 | my-analysis for tool1 |
- 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 输出文件提供示例值,以展示代码扫描结果正常工作所需的最低必需属性。如果删除任何属性、省略值或使用空字符串,此数据将无法在 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 生成者应包含的最低必需属性。
注意
虽然 GitHub 对代码扫描结果的正确显示并不要求此属性,但在使用相对 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 输出文件提供示例值,以展示代码扫描所支持的所有 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"
}
]
}