跳至主要内容

创建 CodeQL 查询套件

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

谁可以使用此功能?

CodeQL 可用于以下存储库类型

关于创建 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 包的兼容版本的范围。如果您未指定版本,则使用包的最新版本。

注意

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

您必须至少向套件定义添加一个 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中的查询,以仅包含与可重用条件匹配的查询。

您还可以使用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套件并排除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 查询分析您的代码”。

进一步阅读