跳到主要内容

发布和使用 CodeQL 包

您可以发布您自己的 CodeQL 包,并使用其他人发布的包。

谁可以使用此功能?

CodeQL 可用于以下类型的代码库

对 GitHub 容器注册表进行身份验证

您可以通过对相应的 GitHub 容器注册表进行身份验证来发布包和下载私有包。

您可以通过两种方式对容器注册表进行身份验证

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

发布前配置qlpack.yml文件

您可以在发布前检查和修改 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 容器注册表后,您可以在包目录的根目录中运行以下命令

codeql pack publish

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

注意

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

运行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 个月。我们将尽最大努力保持新版本的兼容性超过 6 个月,但不作任何承诺。

还可以假设,由 CodeQL 最新公共版本发布的包可以被代码扫描和 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 上的容器注册表中发布查询包供其他人使用,我们建议您使用最新版本的 CodeQL 来运行codeql pack publish,并在您使用的版本超过 6 个月之前发布一个具有更新 CodeQL 版本的新版本包。这样,您可以确保使用您的包并保持 CodeQL 更新的用户将受益于您包中的预编译查询。

如果您发布查询包的目的在于在使用其捆绑的 CodeQL 二进制文件的 GitHub Enterprise Server 安装中使用它们,请使用相同的 CodeQL 版本运行codeql pack publish。较新版本可能会生成 GitHub Enterprise Server 无法识别的预编译查询。您的 GitHub Enterprise Server 管理员可能会定期选择升级到较新版本的 CodeQL。如果是这样,请遵循他们的指示。

关于qlpack.yml 文件

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

每个qlpack.yml文件中的元数据告诉 CodeQL 如何编译包中的任何查询,包依赖哪些库,以及在哪里可以找到查询套件定义。

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

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

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 测试的包来说是可选的。对于没有测试的包将被忽略。

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

    tests: .
    

extractor

  • 所有包含 CodeQL 测试的包都需要。

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

    extractor: javascript-typescript
    

authors

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 代码库中的每种语言都有四个主要的 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属性。这可以防止测试包被意外发布。