关于 SARIF 支持
SARIF(静态分析结果交换格式)是OASIS 标准,它定义了一种输出文件格式。SARIF 标准用于简化静态分析工具共享其结果的方式。代码扫描支持 SARIF 2.1.0 JSON 模式的子集。
要上传来自第三方静态代码分析引擎的 SARIF 文件,您需要确保上传的文件使用 SARIF 2.1.0 版本。GitHub 将解析 SARIF 文件,并在您的代码库中显示使用结果的警报,作为代码扫描体验的一部分。有关更多信息,请参阅“将 SARIF 文件上传到 GitHub”。有关 SARIF 2.1.0 JSON 模式的更多信息,请参阅sarif-schema-2.1.0.json。
如果您使用带有 CodeQL 分析工作流的 GitHub Actions 或使用 CodeQL CLI,则代码扫描结果将自动使用 SARIF 2.1.0 的支持子集。有关更多信息,请参阅“配置代码扫描的高级设置”或“将代码扫描与您现有的 CI 系统一起使用”。
GitHub 使用 SARIF 文件中的属性来显示警报。例如,shortDescription 和 fullDescription 出现在代码扫描警报的顶部。location 允许 GitHub 在您的代码文件中显示注释。有关更多信息,请参阅“关于代码扫描警报”。
如果您是 SARIF 新手并希望了解更多信息,请参阅 Microsoft 的 SARIF 教程 代码库。
提供数据以跟踪跨运行的代码扫描警报
每次上传新的代码扫描结果时,都会处理这些结果并将警报添加到代码库。为了防止针对同一问题出现重复警报,代码扫描使用指纹来匹配不同运行中的结果,以便它们仅在所选分支的最新运行中显示一次。这使得在编辑文件时可以将警报与正确的代码行匹配。结果的ruleID在分析中必须相同。
报告一致的文件路径
为了能够计算稳定的指纹,文件路径在各个运行中必须一致。如果同一结果的文件路径不同,则每次进行新的分析时都会创建新的警报,而旧的警报将被关闭。这将导致对同一结果出现多个警报。
包含用于指纹生成的数据
GitHub 使用 OASIS 标准中的partialFingerprints属性来检测两个结果在逻辑上是否相同。更多信息,请参见 OASIS 文档中的“partialFingerprints 属性”条目。
由 CodeQL 分析工作流或使用 CodeQL CLI 创建的 SARIF 文件包含指纹数据。如果使用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对象的数组。在这里,您可以存储在分析过程中运行的规则的详细信息。这些对象中的信息应该很少更改,通常是在更新工具时。 -
结果存储为
run对象中results下的result对象序列。每个result对象都包含代码库中一个警报的详细信息。在results对象中,您可以引用检测到警报的规则。
当您使用相同的工具和规则比较通过分析不同的代码库生成的 SARIF 文件时,您应该看到分析结果的差异,而不是规则的差异。
指定源文件的位置
指定源文件位置和代码行可确保代码扫描警报在包含已识别问题的文件中准确显示,从而实现有针对性的问题解决。
这种精度提高了代码审查和解决过程的效率,通过使开发人员能够直接在其代码库的上下文中解决问题,从而简化了开发工作流程。
当警报标识的所有代码行都存在于拉取请求差异中时,代码扫描还将在拉取请求检查结果中显示警报。
要在拉取请求检查中显示,警报必须满足以下所有条件:
- 警报标识的所有代码行都存在于拉取请求差异中,包括警报的第一行。
- 警报必须存在于拉取请求中添加或编辑的代码行中,而不是已删除的行中。
提交的 SARIF 文件中的physicalLocation对象标识警报的代码行。更多信息,请参见“physicalLocation 对象”。
指定源文件的根目录
代码扫描将使用相对路径报告的结果解释为相对于所分析存储库的根目录。如果结果包含绝对 URI,则该 URI 将转换为相对 URI。然后可以将相对 URI 与提交到存储库的文件匹配。
您可以通过以下方式之一提供用于从绝对 URI 转换为相对 URI 的源根目录。
github/codeql-action/analyze操作的checkout_path输入- SARIF 上传 API 端点的
checkout_uri参数。更多信息,请参见“代码扫描的 REST API 端点”。 - SARIF 文件中
run对象中的invocations[0].workingDirectory.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 方案。
生成 SARIF 结果之前解析符号链接
如果将结果的相对 URI 与使用符号链接定义的文件匹配,则代码扫描将无法显示结果。因此,您需要解析任何符号链接文件,并使用已解析的 URI 报告这些文件中的任何结果。
验证您的 SARIF 文件
您可以通过针对 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 上传疑难解答”
为提交上传多个 SARIF 文件
您可以为同一个提交上传多个 SARIF 文件,并将每个文件中的数据显示为代码扫描结果。为提交上传多个 SARIF 文件时,必须为每个分析指定一个“类别”。指定类别的方式因分析方法而异。
- 直接使用 CodeQL CLI 时,在生成 SARIF 文件时将
--sarif-category参数传递给codeql database analyze命令。更多信息,请参见“关于 CodeQL CLI”。 - 使用带有
codeql-action/analyze的 GitHub Actions 时,类别会根据工作流名称和任何矩阵变量(通常为language)自动设置。您可以通过为操作指定category输入来覆盖此设置,这在您在一个工作流中分析单体库的不同部分时非常有用。 - 使用 GitHub Actions 上传来自其他静态分析工具的结果时,如果在一个工作流中上传同一工具的多个结果文件,则必须指定
category输入。更多信息,请参见“将 SARIF 文件上传到 GitHub”。 - 如果您没有使用这些方法中的任何一种,则必须在每个要上传的 SARIF 文件中指定唯一的
runAutomationDetails.id。有关此属性的更多信息,请参见“runAutomationDetails对象”。
如果您为具有相同类别和来自同一工具的提交上传第二个 SARIF 文件,则较早的结果将被覆盖。但是,如果您尝试在单个 GitHub Actions 工作流运行中为同一工具和类别上传多个 SARIF 文件,则会检测到错误配置,并且运行将失败。
支持的 SARIF 输出文件属性
如果您使用的是 CodeQL 以外的代码分析引擎,您可以查看支持的 SARIF 属性以优化您的分析结果在 GitHub 上的显示方式。
注意
您必须为任何标记为“必需”的属性提供显式值。空字符串不支持必需属性。
可以上传任何有效的 SARIF 2.1.0 输出文件,但是,代码扫描只会使用以下支持的属性。
sarifLog 对象
| 名称 | 必需 | 描述 |
|---|---|---|
$schema | 2.1.0 版 SARIF JSON 架构的 URI。例如,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。更多信息,请参见语义版本控制文档中的“语义版本控制 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 | (仅推荐用于安全规则) 如果您为此字段包含一个值,则该规则的结果将被视为安全结果。一个字符串,表示一个分数,该分数指示严重性级别,对于安全查询(@tags 包含security),其值为大于 0.0 至多 10.0。这与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 对象中,您可以引用检测到警报的规则。更多信息,请参见上文的“理解规则和结果”。
您可以检查 SARIF 属性是否具有支持的上传大小,以及该文件是否与代码扫描兼容。更多信息,请参见“代码扫描的 SARIF 支持”。
| 名称 | 必需 | 描述 |
|---|---|---|
ruleId | 规则的唯一标识符 (reportingDescriptor.id)。更多信息,请参见reportingDescriptor 对象。代码扫描使用规则标识符在 GitHub 上按规则筛选结果。 | |
ruleIndex | 工具组件rules 数组中关联规则 (reportingDescriptor 对象) 的索引。更多信息,请参见run 对象。此属性的允许范围为 0 到 2^63 - 1。 | |
rule | 用于查找此结果的规则(报告描述符)的引用。更多信息,请参见reportingDescriptor 对象。 | |
level | 结果的严重性。此级别将覆盖规则定义的默认严重性。代码扫描使用级别在 GitHub 上按严重性筛选结果。 | |
message.text | 描述结果的消息。代码扫描将消息文本显示为结果的标题。当可见空间有限时,只会显示消息的第一句话。 | |
locations[] | 检测到结果的位置集,最多 10 个。除非只能通过对每个指定位置进行更改来纠正问题,否则应只包含一个位置。**注意:**代码扫描至少需要一个位置才能显示结果。代码扫描将使用此属性来决定用结果注释哪个文件。仅使用此数组的第一个值。所有其他值都将被忽略。 | |
partialFingerprints | 一组用于跟踪结果唯一标识的字符串。代码扫描使用partialFingerprints 来准确识别跨提交和分支相同的哪些结果。如果存在,代码扫描将尝试使用partialFingerprints。如果您正在使用upload-action 上传包含partialFingerprints的第三方 SARIF 文件,则该操作将在 SARIF 文件中不包含它们时为您创建partialFingerprints。更多信息,请参见“提供数据以跟踪跨运行的代码扫描警报”。**注意:**代码扫描仅使用primaryLocationLineHash。 | |
codeFlows[].threadFlows[].locations[] | 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字段的值示例,显示SARIF生成器在使用相对URI引用时应包含的最小必需属性。
注意:虽然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"
}
]
}