Skip to main content

发布及使用 CodeQL 包

你可发布自己的 CodeQL 包,也可使用其他人发布的包。

谁可以使用此功能?

CodeQL 可用于以下存储库类型:

在发布前配置 qlpack.yml 文件

注意:本文介绍了 GitHub Enterprise Server 3.14 的初始发行版中包含的 CodeQL CLI 2.17.6 捆绑包中可用的功能。

如果站点管理员已将 CodeQL CLI 版本更新为较新版本,请参阅本文的 GitHub Enterprise Cloud 版本,了解有关最新功能的信息。

可以在发布之前检查和修改 CodeQL 包的配置详细信息。 在你喜欢的文本编辑器中打开 qlpack.yml 文件。

library: # set to true if the pack is a library. Set to false or omit for a query pack
name: <scope>/<pack>
version: <x.x.x>
description: <Description to publish with the package>
defaultSuite: # optional, one or more queries in the pack to run by default
    - query: <relative-path>/query-file>.ql
defaultSuiteFile: default-queries.qls # optional, a pointer to a query-suite in this pack
license: # optional, the license under which the pack is published
dependencies: # map from CodeQL pack name to version range
  • name: 必须采用 <scope>/<pack> 格式,其中 <scope> 是将发布到的 GitHub 组织,<pack> 是包的名称。

  • 最多只能选择 defaultSuitedefaultSuiteFile 中的一个。 有两种不同的方法来定义要运行的默认查询套件,第一种是直接在 qlpack.yml 文件中指定查询,第二种是在包中指定查询套件。

正在运行 codeql pack publish

准备好将包发布到 GitHub Container registry 时,可在包目录的根目录中运行以下命令:

codeql pack publish

已发布的包将显示在 GitHub 组织的“包”部分中,该组织由 qlpack.yml 文件中的范围指定。

注意: 如果要将模型包发布到 GitHub Container registry,以便将覆盖范围扩展到组织中的所有存储库作为默认设置配置的一部分,则需要确保运行代码扫描的存储库可以访问这些模型包。 有关详细信息,请参阅“编辑默认设置配置”和“配置包的访问控制和可见性”。

正在运行 codeql pack download <scope>/<pack>

若要运行其他人创建的包,必须先运行以下命令来下载它:

codeql pack download <scope>/<pack>@x.x.x
  • <scope>:将从中下载的 GitHub 组织的名称。
  • <pack>:要下载的包的名称。
  • @x.x.x:可选版本号。 如果省略,将下载最新版本。

此命令接受多个包的参数。

如果编写脚本来指定要下载的查询包的特定版本号,请记住,在将 CodeQL 的版本更新为更新的版本时,可能还需要切换到更新的查询包版本。 与固定到非常旧的版本的查询包一起使用时,较新版本的 CodeQL 可能会导致性能降低。 有关详细信息,请参阅“关于 CodeQL 包兼容性”。

使用 CodeQL 包分析 CodeQL 数据库

若要使用 CodeQL 包分析 CodeQL 数据库,请运行以下命令:

codeql database analyze <database> <scope>/<pack>@x.x.x:<path>
  • <database>:要分析的 CodeQL 数据库。
  • <scope>:将包发布到的 GitHub 组织的名称。
  • <pack>:正在使用的包的名称。
  • @x.x.x:可选版本号。 如果省略,将使用最新版本。
  • :<path>:查询、目录或查询套件的可选路径。 如果省略,将使用包的默认查询套件。

analyze 命令将运行任何指定的 CodeQL 包的默认套件。 可以指定多个用于分析 CodeQL 数据库的 CodeQL 包。 例如:

codeql <database> analyze <scope>/<pack> <scope>/<other-pack>

注意:codeql pack download 命令将其下载的包存储在不用于本地修改的内部位置。 如果在下载后修改包,可能会导致意外(且很难进行排除故障)的行为。 有关自定义包的详细信息,请参阅“创建并使用 CodeQL 包”。

关于 CodeQL 包兼容性

发布查询包时,它包括其中所有查询的预编译表示形式。 与在分析期间从头开始编译 QL 源相比,这些预编译查询的执行速度通常要快得多。 但是,预编译的查询也依赖于 QL 计算器的某些内部信息,因此如果执行分析的 CodeQL 的版本与运行 codeql pack publish 的版本差异太大,则可能需要改为在分析期间从源编译查询。 重新编译会自动进行,不会影响分析的结果,但会使分析速度明显变慢。

通常可以假设,如果包发布时包含 CodeQL 的一个版本,则 CodeQL 的更高版本可直接使用其中的预编译查询,只要发布日期之间的间隔不超过 6 个月即可。 我们将做出合理的努力,使新版本的兼容性保持更长时间,但不做出任何承诺。

还可以假设由 CodeQL 的最新公开版本发布的包可供 code scanning 和 GitHub Actions 使用的 CodeQL 版本使用,即使该版本通常略微更旧也是如此。

作为已发布的查询包的用户,你可通过检查使用查询包的分析运行中的终端输出来检查 CodeQL 是否利用了其中预编译的查询。 如果它包含如下所示的行,则已成功使用预编译的查询:

[42/108] Loaded /long/path/to/query/Filename.qlx.

但是,如果它们如下所示,则未能使用预编译的查询:

Compiling query plan for /long/path/to/query/Filename.ql.
[42/108 comp 25s] Compiled /long/path/to/query/Filename.ql.

在这种情况下,分析结果仍然不错,但为了获得最佳性能,可能需要升级到 CodeQL CLI 和/或查询包的更新版本。

如果你在 GitHub.com 上的 Container registry 上发布查询包供其他人使用,建议使用最新版本的 CodeQL 来运行 codeql pack publish,并在使用的版本已过 6 个月之前发布包含 CodeQL 更新版本的包的新版本。 这样,你可确保将 CodeQL 保持最新状态的包用户将受益于包中预编译的查询。

如果发布查询包的目的是在使用其捆绑的 CodeQL 二进制文件的 GitHub Enterprise Server 安装上使用查询包,请使用相同的 CodeQL 版本来运行 codeql pack publish。 较新版本可能会生成预编译的查询,而 GitHub Enterprise Server 中的查询可能无法识别。 GitHub Enterprise Server 管理员可选择定期升级到更新版本的 CodeQL。 如果是,请按照其指示操作。

在 GitHub Enterprise Server 上使用 CodeQL 包

默认情况下,CodeQL CLI 预期从 GitHub.com 上的 Container registry 下载 CodeQL 包,并将这些包发布到此位置。 不过,也可通过创建 qlconfig.yml 文件来告知 CLI 每个包使用哪个 Container registry,使用 GitHub Enterprise Server 上的 Container registry 中的 CodeQL 包。

使用首选文本编辑器创建 ~/.codeql/qlconfig.yml 文件,并添加条目来指定要用于一个或多个包名称模式的注册表。 例如,以下 qlconfig.yml 文件将所有包与位于 GHE_HOSTNAME 的 GitHub Enterprise Server 的 Container registry 进行关联,但与 codeql/\* 匹配的包除外,它们与 GitHub.com 上的 Container registry 关联:

registries:
- packages:
  - 'codeql/*'
  - 'other-org/*'
  url: https://ghcr.io/v2/
- packages: '*'
  url: https://containers.GHE_HOSTNAME/v2/

CodeQL CLI 将通过查找 registries 列表中具有与该包名称匹配的 packages 属性的第一项来确定要用于给定包名称的注册表。 这意味着,通常需要先定义最具体的包名称模式。 packages 属性可以是单个包名称、glob 模式,也可以是包名称和 glob 模式的 YAML 列表。

registries 列表也可以放在 codeql-workspace.yml 文件中。 这样,便可定义要在特定工作区中使用的注册表,以便可在工作区的其他 CodeQL 用户之间共享该注册表。 codeql-workspace.yml 中的 registries 列表将与全局 qlconfig.yml 中的列表合并,并优先于后者。 有关 codeql-workspace.yml 的详细信息,请参阅“关于 CodeQL 工作区”。

现在可以使用 codeql pack publishcodeql pack downloadcodeql database analyze 来管理 GitHub Enterprise Server 上的包。

对 GitHub Container registries 进行身份验证

可通过向相应的 GitHub Container registry 进行身份验证来发布包和下载专用包。

可通过两种方式向 GitHub.com 上的 Container registry 进行身份验证:

  1. --github-auth-stdin 选项传递给 CodeQL CLI,然后通过标准输入提供 GitHub Apps 令牌或 personal access token。
  2. GITHUB_TOKEN 环境变量设置为 GitHub Apps 令牌或 personal access token。

同样,可以向 GitHub Enterprise Server Container registry 进行身份验证,或者通过两种方式同时向多个注册表进行身份验证(例如,从多个注册表下载或运行专用包):

  1. --registries-auth-stdin 选项传递给 CodeQL CLI,然后通过标准输入提供注册表身份验证字符串。
  2. CODEQL_REGISTRIES_AUTH 环境变量设置为注册表身份验证字符串。

注册表身份验证字符串是一个逗号分隔的 <registry-url>=<token> 对列表,其中 registry-url 是 Container registry URL(例如 https://containers.GHE_HOSTNAME/v2/),token 是 GitHub Apps 令牌或该 GitHub Container registry 的 personal access token。 这可确保每个令牌仅传递到指定的 Container registry。 例如,以下注册表身份验证字符串指定 CodeQL CLI 应使用 <token1> 令牌向 GitHub.com 上的 Container registry 进行身份验证,使用 GHE_HOSTNAME 令牌向位于 <token2> 的 GHES 实例的 Container registry 进行身份验证:

https://ghcr.io/v2/=<token1>,https://containers.GHE_HOSTNAME/v2/=<token2>

关于 qlpack.yml 文件

执行与查询相关的命令时,CodeQL 首先在安装目录(及其子目录)的同级中查找 qlpack.yml 文件。 然后,它会检查包缓存中是否有已下载的 CodeQL 包。 这意味着,在本地开发查询时,安装目录中的本地包会覆盖包缓存中同名的包,以便可测试本地更改。

每个 qlpack.yml 文件中的元数据显示了 CodeQL 如何编译包中的任何查询、包依赖于哪些库以及在何处查找查询套件定义。

CodeQL 包(CodeQL 分析中使用的查询或库)的内容与 qlpack.yml 或其子目录包含在同一目录中。

包含 qlpack.yml 文件的目录用作 CodeQL 包内容的根目录。 也就是说,对于包中的所有 .ql.qll 文件,CodeQL 将解析与包根目录中包含 qlpack.yml 文件的目录相关的所有 import 语句。

qlpack.yml 属性

qlpack.yml 文件中支持以下属性。

name

  • 这是所有包所必需的。

  • 定义包的范围、发布 CodeQL 包的位置,以及使用字母数字字符和连字符定义的包名称。 它必须是唯一的,因为 CodeQL 无法区分具有相同名称的 CodeQL 包。 使用包名称指定要使用 database analyze 运行的查询,并定义 CodeQL 包之间的依赖项(请参阅下面的示例)。 例如:

    name: octo-org/security-queries
    

version

  • 对于已发布的所有包,这是必需的。

  • 为此 CodeQL 包定义一个语义版本,该版本必须符合 SemVer v2.0.0 规范。 例如:

    version: 0.0.0
    

dataExtensions

  • 这是所有模型包所必需的。
  • 获取 glob 模式列表,该模式指定数据扩展插件文件相对于查询包或库包的根目录的位置。

dependencies

  • 对于定义 CodeQL 包对其他包的依赖项的查询包和库包而言,这是必需的。 模型包无法定义任何依赖项,并且使用的是 extensionTargets

  • 定义从包引用到与此包兼容的语义版本范围的映射。 支持用于 CodeQL CLI v2.6.0 及更高版本。 例如:

    dependencies:
      codeql/cpp-all: ^0.0.2
    

    如果不确定或应使用哪个版本不重要,则可以使用 "*",这表示此依赖项的任何版本都与此包兼容。 在实践中,这通常会解析为依赖项的最高已发布版本。

    有一个特殊的版本占位符 ${workspace},其指示此 CodeQL 包依赖于同一工作区中的依赖项版本。 有关详细信息,请参阅“关于 CodeQL 工作区”。

defaultSuiteFile

  • 对于导出要运行的一组默认查询的包,这是必需的。

  • 定义相对于程序包根目录的查询套件文件的路径,其中包含将此包传递给 codeql database analyze 命令时默认运行的所有查询。 从 CLI v2.6.0 及更高版本开始支持。 只能定义 defaultSuiteFiledefaultSuite 之一。 例如:

    defaultSuiteFile: cpp-code-scanning.qls
    

defaultSuite

  • 对于导出要运行的一组默认查询的包,这是必需的。

  • 定义一个内联查询套件,其中包含将此包传递至 codeql database analyze 命令时默认运行的所有查询。 从 CLI v2.6.0 及更高版本开始支持。 只能定义 defaultSuiteFiledefaultSuite 之一。 例如:

    defaultSuite:
      queries: .
      exclude:
        precision: medium
    

extensionTargets

  • 这是所有模型包所必需的。
  • 声明模型包中的扩展适用的查询包。 如果扩展包位于指定的版本范围内,并且在评估中使用,则扩展包会将其数据扩展注入 extensionTargets 字典中命名的每个包中。

groups

  • 可选。

  • 定义 CodeQL 工作区中包的逻辑分组。 使用组是将包操作应用于工作区中的包子集的一种方法。 例如,以下包定义为 javaexperimental 组的一部分:

    groups:
      - java
      - experimental
    

    运行 codeql pack publish --groups java,-experimental 将发布 java 组中的所有包(experimental 包除外)。__ 可以运行 codeql pack ls --groups [-]<group>[,[-]<group>...] 命令,列出工作区中与指定组集匹配的包。

    如果满足以下条件,给定工作区中的 CodeQL 包将包含在列表中:

    • 它至少在一个不带减号的所列组中(如果没有不带减号的所列组,则自动满足此条件),并且
    • 它不在任何带减号的组中。

library

  • 这是库包所必需的。

  • 定义一个布尔值,该值指示此包是否为库包。 库包不包含查询,也不会进行编译。 查询包可忽略此字段或将其显式设置为 false。 例如:

    library: true
    

suites

  • 对于定义查询套件的包,这是可选项。 这使用户能够通过指定包名称来运行存储在指定目录中的查询套件,而无需提供完整路径。
  • 目前仅对于 CodeQL CLI 捆绑中包含的标准查询包提供支持。
  • 从 GitHub 容器注册表下载的 CodeQL 包不支持此选项。

tests

  • 对于具有 CodeQL 测试的包,这是可选的。 针对没有测试的包已忽略。

  • 定义包中具有测试的目录的路径,此路径相对于包目录进行定义。 使用 . 指定整个包。 当 test run 使用 --strict-test-discovery 选项运行时,此目录中的任何查询都作为测试运行。 使用 queriesqlpack 指令请求特定包中的所有查询的查询套件定义会忽略这些查询。 如果缺少此属性,则假定 .。 例如:

    tests: .
    

extractor

  • 对于具有 CodeQL 测试的所有包,这是必需的。

  • 定义在包中运行 CodeQL 测试时要使用的 CodeQL 语言提取程序。 有关测试查询的详细信息,请参阅“测试自定义查询”。 例如:

    extractor: javascript-typescript
    

authors

  • 可选。

  • 定义将在 CodeQL 包发布到的帐户的“包”部分的“打包搜索”页面上显示的元数据。 例如:

    authors: author1@github.com,author2@github.com
    

license

  • 可选。

  • 定义将在 CodeQL 包发布到的帐户的“包”部分的“打包搜索”页面上显示的元数据。 有关允许的许可证列表,请参阅 SPDX 规范中的 SPDX 许可证列表。 例如:

    license: MIT
    

description

  • 可选。

  • 定义将在 CodeQL 包发布到的帐户的“包”部分的“打包搜索”页面上显示的元数据。 例如:

    description: Human-readable description of the contents of the CodeQL pack.
    

libraryPathDependencies

  • 可选,已弃用。 改用 dependencies 属性。

  • 以前用于将此 CodeQL 包所依赖的任何 CodeQL 包的名称定义为数组。 这使得包能够访问依赖项中定义的任何库、数据库架构和查询套件。 例如:

    libraryPathDependencies: codeql/javascript-all
    

dbscheme

  • 只有对于核心语言包来说是必需的。

  • 对于为此 CodeQL 语言编写的所有库和查询,定义数据库架构的路径(请参阅下面的示例)。 例如:

    dbscheme: semmlecode.python.dbscheme
    

upgrades

  • 只有对于核心语言包来说是必需的。

  • 定义包中包含数据库升级脚本的目录的路径,该路径相对于包目录进行定义。 数据库升级在内部使用,以确保使用其他版本的 CodeQL CLI 创建的数据库与当前版本的 CLI 兼容。 例如:

    upgrades: .
    

warnOnImplicitThis

  • 可选。 如果未定义 warnOnImplicitThis 属性,则默认为 false

  • 定义一个布尔值,指定编译器是否应发出有关带有隐式 this 调用接收器(即没有显式接收器)的成员谓词调用的警告。 自 CodeQL CLI v2.13.2 起可用。 例如:

    warnOnImplicitThis: true
    

关于 codeql-pack.lock.yml 文件

codeql-pack.lock.yml 文件会存储 CodeQL 包已解析的可传递依赖项的版本。 如果此文件尚不存在,则由 codeql pack install 命令创建,并且应将其添加到版本控制系统中。 qlpack.yml 文件的 dependencies 部分包含与包兼容的版本范围。 codeql-pack.lock.yml 文件将版本锁定到精确的依赖项。 这可确保在此包上运行 codeql pack install 将始终检索相同版本的依赖项,即使存在较新的兼容版本也是如此。

例如,如果 qlpack.yml 文件包含以下依赖项:

dependencies:
  codeql/cpp-all: ^0.1.2
  my-user/my-lib: ^0.2.3
  other-dependency/from-source: "*"

codeql-pack.lock.yml 文件将包含如下内容:

dependencies:
  codeql/cpp-all:
    version: 0.1.4
  my-user/my-lib:
    version: 0.2.4
  my-user/transitive-dependency:
    version: 1.2.4

codeql/cpp-all 依赖项锁定到版本 0.1.4。 my-user/my-lib 依赖项锁定到版本 0.2.4。 my-user/transitive-dependency 是可传递依赖项,未在 qlpack.yml 文件中指定,并且已锁定到版本 1.2.4。 锁定文件中没有 other-dependency/from-source,因为它是从源解析的。 此依赖项必须在与包相同的 CodeQL 工作区中可用。 若要详细了解 CodeQL 工作区以及如何从源解析依赖项,请参阅“关于 CodeQL 工作区”。

在大多数情况下,codeql-pack.lock.yml 文件仅与查询包相关,因为库包不可执行,通常不需要修复其可传递依赖项。 对于包含测试的库包,这种情况除外。 在这种情况下,codeql-pack.lock.yml 文件用于确保始终使用相同的依赖项版本运行测试,以避免在依赖项不匹配时出现虚假故障。

自定义 CodeQL 包的示例

编写自定义查询或测试时,应将它们保存在自定义 CodeQL 包中。 为了简单起见,请尝试按逻辑整理每个包。 有关详细信息,请参阅“创建并使用 CodeQL 包”。 将用于查询和测试的文件保存在单独的包中,并尽可能地将自定义包整理到每种目标语言的特定文件夹中。 如果打算发布 CodeQL 包,以便可与他人共享或在代码扫描中使用它们,这将特别有用。 有关详细信息,请参阅“关于使用 CodeQL 进行代码扫描”。

自定义库的 CodeQL 包

包含自定义 C++ 库的自定义 CodeQL 包(没有查询或测试)可能具有包含以下内容的 qlpack.yml 文件:

name: my-github-user/my-custom-libraries
version: 1.2.3
library: true
dependencies:
  codeql/cpp-all: ^0.1.2

其中,codeql/cpp-all 是 CodeQL 存储库中包含的用于 C/C++ 分析的 CodeQL 包的名称。 版本范围 ^0.1.2 表示此包与大于等于 0.1.2 且小于 0.2.0 的所有 codeql/cpp-all 版本兼容。 此包中定义的任何 CodeQL 库文件(扩展名为 .qll 的文件)都可用于在其依赖项块中包含此包的任何查询包中定义的查询。

library 属性指示此包是库包,不包含任何查询。

自定义查询的 CodeQL 包

包含自定义 C++ 查询和库的自定义 CodeQL 包可能具有包含以下内容的 qlpack.yml 文件:

name: my-github-user/my-custom-queries
version: 1.2.3
dependencies:
  codeql/cpp-all: ^0.1.2
  my-github-user/my-custom-libraries: ^1.2.3

其中,codeql/cpp-all 是 CodeQL 存储库中包含的用于 C/C++ 分析的 CodeQL 包的名称。 版本范围 ^0.1.2 表示此包与大于等于 0.1.2 且小于 0.2.0 的所有 codeql/cpp-all 版本兼容。 my-github-user/my-custom-libraries 是包含用于 C++ 的自定义 CodeQL 库的 CodeQL 包的名称。 此包中定义的任何 CodeQL 库文件(扩展名为 .qll 的文件)都可用于 my-github-user/my-custom-queries 包中的查询。

自定义测试的 CodeQL 包

对于包含测试文件的自定义 CodeQL 包,还需要包含 extractor 属性,以便 test run 命令知道如何创建测试数据库。 你可能还希望指定 tests 属性。

以下 qlpack.yml 文件说明 my-github-user/my-query-tests 取决于版本高于或等于 1.2.3 且低于 2.0.0 的 my-github-user/my-custom-queries。 同时还声明 CLI 在创建测试数据库时应使用 Java extractortests: . 行声明在使用 --strict-test-discovery 选项运行 codeql test run 时,包中的所有 .ql 文件都应作为测试运行。 通常,测试包不包含 version 属性。 这样可以防止意外发布它们。

name: my-github-user/my-query-tests
dependencies:
  my-github-user/my-custom-queries: ^1.2.3
extractor: java-kotlin
tests: .

有关运行测试的详细信息,请参阅“测试自定义查询”。

CodeQL 存储库中的 CodeQL 包示例

CodeQL 存储库中的每种语言都有 4 个主要的 CodeQL 包:

  • 语言的核心库包,其中包含该语言使用的数据库架构、CodeQL 库和 <language>/ql/lib 处的查询

  • 语言的核心查询包,其中包含该语言的默认查询及其在 <language>/ql/src 处的查询套件

  • <language>/ql/test 处用于核心语言库和查询的测试

  • <language>/ql/examples 处的语言示例查询

核心库包

下面是 C/C++ 分析库核心语言包的示例 qlpack.yml 文件:

name: codeql/cpp-all
version: x.y.z-dev
dbscheme: semmlecode.cpp.dbscheme
library: true
upgrades: upgrades

有关以下属性的一些额外说明:

  • library:指示这是没有可执行查询的库包。 它只能用作其他包的依赖项。

  • dbschemeupgrades:这些属性是 CodeQL CLI 的内部属性,应仅在语言的核心 CodeQL 查询包中定义。

核心查询包

下面是 C/C++ 分析查询核心查询包的示例 qlpack.yml 文件:

name: codeql/cpp-queries
version: x.y.z-dev
dependencies:
    codeql/cpp-all: "*"
    codeql/suite-helpers: "*"
suites: codeql-suites
defaultSuiteFile: codeql-suites/cpp-code-scanning.qls

有关以下属性的一些额外说明:

  • dependencies:此查询包依赖于 codeql/cpp-allcodeql/suite-helpers。 由于这些依赖项是从源解析的,因此它们与 CodeQL 包的哪个版本兼容并不重要。 若要详细了解如何从源解析依赖项,请参阅“源依赖项”。

  • suites:指示包含“已知”查询套件的目录。

  • defaultSuiteFile:未指定查询套件时使用的默认查询套件文件的名称。

核心 CodeQL 包的测试

下面是 C/C++ 分析测试核心测试包的示例 qlpack.yml 文件:

name: codeql/cpp-tests
dependencies:
  codeql/cpp-all: "*"
  codeql/cpp-queries: "*"
extractor: cpp
tests: .

有关以下属性的一些额外说明:

  • dependencies:此包依赖于用于C++ 的核心 CodeQL 查询和库包。

  • extractor:这指定所有测试将使用相同的 C++ 提取程序为测试创建数据库。

  • tests:这指定测试的位置。 在这种情况下,测试位于包的根文件夹(和所有子文件夹)中。

  • version:测试包没有 version 属性。 这可防止意外发布测试包。