关于创建 CodeQL 查询套件
CodeQL 查询套件提供了一种基于其文件名、磁盘上或 CodeQL 包中的位置或者元数据属性选择查询的方法。 可以为要经常在 CodeQL 分析中使用的查询创建查询套件。
使用查询套件,可将多个查询传递给 CodeQL,而无需单独指定每个查询文件的路径。 查询套件定义存储在扩展名为 .qls
的 YAML 文件中。 套件定义是一系列指令,其中每条指令都是带有(通常)单个键的 YAML 映射。 指令按它们在查询套件定义中的显示顺序执行。 执行套件定义中所有指令后,结果为一组选定的查询。
Note
要添加到查询套件的任何自定义查询都必须位于 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 包的兼容版本范围。 如果未指定版本,则使用最新版本的包。
Note
当路径名出现在查询套件定义中时,路径名必须始终使用正斜杠 (/
) 作为目录分隔符。 这可确保查询套件定义适用于所有操作系统。
必须向套件定义添加至少一条 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
Note
可使用 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 包的兼容版本范围。 如果未指定版本,则使用最新版本的包。可以使用后续
exclude
指令筛选使用import
指令添加的查询。 -
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
中的查询,以仅包含与可重用条件匹配的查询。
还可以在不同的 CodeQL 包中的查询上使用 reusable-instructions.yml
创建套件定义。 如果 .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 查询分析代码。