关于创建 CodeQL 查询套件
CodeQL 查询套件提供了一种根据查询的文件名、磁盘或 CodeQL 包中的位置或元数据属性来选择查询的方法。为要在 CodeQL 分析中经常使用的查询创建查询套件。
查询套件允许您将多个查询传递给 CodeQL,而无需单独指定每个查询文件的路径。查询套件定义存储在扩展名为 .qls
的 YAML 文件中。套件定义是一系列指令,其中每个指令都是一个 YAML 映射(通常)只有一个键。这些指令按其在查询套件定义中出现的顺序执行。在执行完套件定义中的所有指令后,结果将是一组选定的查询。
注意
要添加到查询套件的任何自定义查询都必须位于“CodeQL 包”中,并且包含正确的查询元数据。有关更多信息,请参阅“使用 CodeQL CLI 的自定义查询”。
查找要添加到查询套件的查询
创建查询套件时,首先需要指定要选择的查询的位置。您可以使用以下方法定义一个或多个查询的位置
-
query
指令 - 指示 CodeQL 查找一个或多个指定的.ql
文件- query: <path-to-query>
该参数必须是相对于包含套件定义的 CodeQL 包的一个或多个文件路径。
-
queries
指令 - 指示 CodeQL 递归扫描目录以查找.ql
文件- queries: <path-to-subdirectory>
目录的路径必须相对于包含套件定义文件的 CodeQL 包的根目录。若要查找相对于不同 CodeQL 包的查询,请添加
from
字段- queries: <path-to-subdirectory> from: <ql-pack-name> version: ^x.y.z
version
字段是可选的,并指定此 CodeQL 包的兼容版本的范围。如果您未指定版本,则使用包的最新版本。 -
qlpack
指令 - 指示 CodeQL 解析命名 CodeQL 包的默认套件中的查询- qlpack: <qlpack-name> version: ^x.y.z
查询包的默认套件包括该查询包内的一组推荐查询。并非所有查询包都具有默认套件。如果给定的查询包未定义默认套件,则 qlpack 指令将解析为包中的所有查询。
version
字段是可选的,并指定此 CodeQL 包的兼容版本的范围。如果您未指定版本,则使用包的最新版本。
注意
当路径名出现在查询套件定义中时,必须始终使用正斜杠 /
作为目录分隔符。这可确保查询套件定义在所有操作系统上都能正常工作。
您必须至少向套件定义添加一个 query
、queries
或 qlpack
指令,否则将不会选择任何查询。如果套件不包含其他指令,则将从文件列表、给定目录或命名 CodeQL 包中找到的所有查询都选中。如果有其他筛选指令,则仅选择与这些指令施加的约束匹配的查询。
筛选查询套件中的查询
通过指定 query
、queries
或 qlpack
指令定义要添加到套件的初始查询集后,您可以添加 include
和 exclude
指令。这些指令根据特定属性定义选择条件
- 当您对一组查询执行
include
指令时,与您的条件匹配的任何查询都将保留在选择中,而不匹配的查询将被删除。 - 当您对一组查询执行
exclude
指令时,与您的条件匹配的任何查询都将从选择中删除,而不匹配的查询将被保留。
筛选指令的顺序很重要。出现在定位指令后的第一个筛选指令决定默认情况下查询是包含还是排除。如果第一个筛选器是 include
,则仅当初始定位的查询与显式 include
筛选器匹配时,它们才会成为套件的一部分。如果第一个筛选器是 exclude
,则初始定位的查询将成为套件的一部分,除非它们被明确排除。
后续指令按顺序执行,并且文件中出现的较晚的指令优先于较早的指令。因此,include
指令可以被与相同查询匹配的稍后的 exclude
指令覆盖。类似地,exclude
可以被稍后的 include
覆盖。
对于这两个指令,参数都是一个约束块 - 即表示约束的 YAML 映射。每个约束都是一个映射条目,其中键通常是查询元数据属性。该值可以是
- 单个字符串。
- 一个
/
括起来的 正则表达式。 - 包含字符串、正则表达式或两者的列表。
若要匹配约束,元数据值必须与其中一个字符串或正则表达式匹配。当存在多个元数据键时,必须匹配每个键。可用于匹配的标准元数据键为:description
、id
、kind
、name
、tags
、precision
和 problem.severity
。有关查询元数据属性的更多信息,请参阅“CodeQL 查询的元数据”。
除了元数据标签外,约束块中的键还可以是
query filename
—匹配查询文件名最后一个路径组件。query path
—匹配查询文件相对于其封闭 CodeQL 包的路径。tags contain
—给定的匹配字符串之一必须与@tags
元数据属性的值的空格分隔组件之一匹配。tags contain all
—给定的每个匹配字符串都必须与@tags
元数据属性的组件之一匹配。
运行哪些查询的过滤示例
一个常见的用例是创建一个查询套件,该套件运行 CodeQL 包中的所有查询,除了用户不想运行的一些特定查询。通常,我们建议根据查询id
进行过滤,它是一个查询的唯一且稳定的标识符。以下三个查询套件定义在语义上是相同的,并按查询id
进行过滤
此过滤器匹配codeql/cpp-queries
默认套件中的所有查询,除了两个具有排除标识符的查询
- qlpack: codeql/cpp-queries
- exclude:
id:
- cpp/cleartext-transmission
- cpp/cleartext-storage-file
在此示例中,每个查询都使用单独的exclude
指令。
- qlpack: codeql/cpp-queries
- exclude:
id: cpp/cleartext-transmission
- exclude:
id: cpp/cleartext-storage-file
在此示例中,正则表达式排除了相同的两个查询。它还将排除将来添加到套件中以以下标识符开头的任何查询:cpp/cleartext-
- qlpack: codeql/cpp-queries
- exclude:
id:
- /^cpp\/cleartext-.*/
要定义一个套件,该套件选择codeql/cpp-queries
CodeQL 包的默认套件中的所有查询,然后将其细化为仅包含安全查询,请使用
- qlpack: codeql/cpp-queries
- include:
tags contain: security
要定义一个套件,该套件从my-custom-queries
目录中选择所有具有@kind problem
和@precision high
的查询,请使用
- queries: my-custom-queries
- include:
kind: problem
precision: very-high
请注意,以下查询套件定义的行为与上述定义不同。此定义选择@kind problem
或@precision very-high
的查询
- queries: my-custom-queries
- include:
kind: problem
- include:
precision: very-high
要创建一个套件,该套件选择my-custom-queries
目录中所有具有@kind problem
的查询,但那些具有@problem.severity recommendation
的查询除外,请使用
- queries: my-custom-queries
- include:
kind: problem
- exclude:
problem.severity: recommendation
要创建一个套件,该套件从codeql/cpp-queries
CodeQL 包中选择所有具有@tag security
和@precision high
或very-high
的查询,请使用
- queries: .
from: codeql/cpp-queries
- include:
tags contain: security
precision:
- high
- very-high
注意
您可以使用codeql resolve queries /path/to/suite.qls
命令查看查询套件定义选择了哪些查询。有关更多信息,请参阅“解析查询”。
重用现有的查询套件定义
可以通过指定以下内容来重用现有的查询套件定义
-
import
指令—将先前定义的.qls
文件选择的查询添加到当前套件- import: <path-to-query-suite>
导入套件的路径必须相对于包含当前套件定义的 CodeQL 包。如果导入的查询套件在不同的 QL 包中,则可以使用
- import: <path-to-query-suite> from: <ql-pack> version: ^x.y.z
version
字段是可选的,并指定此 CodeQL 包的兼容版本的范围。如果您未指定版本,则使用包的最新版本。使用
import
指令添加的查询可以使用后续的exclude
指令进行过滤。 -
apply
指令—将先前定义的.qls
文件中的所有指令添加到当前套件。应用的.qls
文件中的指令将被执行,就像它们出现在apply
的位置一样。应用套件中的任何include
和exclude
指令也对任何早期指令添加的查询起作用- apply: <path-to-query-suite>
apply
指令也可用于将保存在.yml
文件中的可重用条件集应用于多个查询定义。有关更多信息,请参阅下面的示例。
可重用性示例
要在多个查询套件定义中使用相同的条件,请创建一个包含指令的单独.yml
文件。例如,将以下内容保存在名为reusable-instructions.yml
的文件中
- include:
kind:
- problem
- path-problem
tags contain: security
precision:
- high
- very-high
将reusable-instructions.yml
添加到与当前查询套件相同的 CodeQL 包中。然后,在一个或多个查询套件中,使用apply
指令将可重用指令应用于当前套件。例如
- queries: queries/cpp/custom
- apply: reusable-instructions.yml
这将过滤queries/cpp/custom
中的查询,以仅包含与可重用条件匹配的查询。
您还可以使用reusable-instructions.yml
在不同 CodeQL 包中的查询上创建套件定义。如果.qls
文件与查询位于同一 CodeQL 包中,则可以在apply
指令后立即添加from
字段
# load queries from the default suite of my-org/my-other-custom-queries
- qlpack: my-org/my-other-custom-queries
# apply the reusable instructions from the my-org/my-custom-instructions CodeQL pack
- apply: reusable-instructions.yml
from: my-org/my-custom-instructions
version: ^1.2.3 # optional
import
指令的一个常见用例是对来自另一个查询套件的查询应用进一步的过滤器。例如,此套件将进一步过滤cpp-security-and-quality
套件并排除low
和medium
精度的查询
- import: codeql-suites/cpp-security-and-quality.qls
from: codeql/cpp-queries
- exclude:
precision:
- low
- medium
如果要include
从另一个套件导入的查询,语法会略有不同
- import: codeql-suites/cpp-security-and-quality.qls
from: codeql/cpp-queries
- exclude: {}
- include:
precision:
- very-high
- high
请注意空的exclude
指令。这是必需的,以确保后续的include
指令能够过滤导入套件中的查询。
命名查询套件
您可以通过指定description
指令来为查询套件提供名称
- description: <name-of-query-suite>
保存查询套件
将您的查询套件保存在扩展名为.qls
的文件中,并将其添加到 CodeQL 包中。有关更多信息,请参阅“使用 CodeQL 包自定义分析”。
将查询套件与 CodeQL 结合使用
您可以为任何接受.qls
文件的命令在命令行上指定查询套件。例如,您可以使用query compile
编译套件定义选择的查询,或在分析中使用database analyze
使用这些查询。有关分析 CodeQL 数据库的更多信息,请参阅“使用 CodeQL 查询分析您的代码”。