跳至主要内容

创建 CodeQL 查询套件

您可以为在 CodeQL 分析中经常使用的查询创建查询套件。

谁可以使用此功能?

CodeQL 可用于以下仓库类型

您可以为想要在 CodeQL 分析中频繁使用的查询创建查询套件。有关更多信息,请参阅 CodeQL 查询套件

注意

您希望添加到查询套件的任何自定义查询必须位于 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 包的兼容版本范围。如果未指定版本,则使用该包的最新版本。

注意

当查询套件定义中出现路径名时,必须始终使用正斜杠 / 作为目录分隔符。这可确保查询套件定义在所有操作系统上均能正常工作。

您必须在套件定义中至少添加一个 queryqueriesqlpack 指令,否则将不会选择任何查询。如果套件没有其他指令,则会选择从文件列表、给定目录或指定的 CodeQL 包中找到的所有查询。如果存在进一步的过滤指令,则仅会选择符合这些指令所施加约束的查询。

过滤查询套件中的查询

在通过指定 queryqueriesqlpack 指令定义了要添加到套件的初始查询集合后,您可以添加 includeexclude 指令。这些指令根据特定属性定义选择标准。

  • 执行 include 指令时,符合条件的查询将保留在选择中,不符合条件的查询将被剔除。
  • 执行 exclude 指令时,符合条件的查询将从选择中移除,不符合条件的查询将被保留。

过滤指令的顺序很重要。定位指令之后出现的第一个过滤指令决定查询默认是被包含还是被排除。如果第一个过滤指令是 include,则仅当最初定位的查询匹配显式的 include 过滤时才会成为套件的一部分。如果第一个过滤指令是 exclude,则最初定位的查询默认属于套件,除非被显式排除。

随后出现的指令按顺序执行,文件后面的指令优先于前面的指令。因此,include 指令可以被后续匹配相同查询的 exclude 指令覆盖。同理,exclude 也可以被后续的 include 覆盖。

对于两种指令,参数都是约束块——即表示约束的 YAML 映射。每个约束是一个映射条目,键通常是查询元数据属性,值可以是

  • 单个字符串。
  • / 包裹的正则表达式。
  • 包含字符串、正则表达式或两者的列表。

要匹配约束,元数据值必须匹配其中的一个字符串或正则表达式。当存在多个元数据键时,必须匹配每个键。可匹配的标准元数据键包括:descriptionidkindnametagsprecisionproblem.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 highvery-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 位置一样执行。来自应用套件的任何 includeexclude 指令同样作用于之前指令添加的查询。

    - 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 套件,并排除 lowmedium 精度的查询。

- 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 查询分析代码

延伸阅读

© . This site is unofficial and not affiliated with GitHub, Inc.