Skip to main content

在 CI 系统中配置 CodeQL CLI

您可以配置持续集成 系统以运行CodeQL CLI,执行 CodeQL 分析,并将结果上传到 GitHub Enterprise Cloud 以显示为 code scanning 警报。

Code scanning 可用于 GitHub.com 上的所有公共存储库。 若要在组织拥有的专用存储库中使用 code scanning,必须具有 GitHub Advanced Security 许可证。 有关详细信息,请参阅“关于 GitHub 高级安全性”。

关于使用 CodeQL CLI 生成代码扫描结果

一旦您在 CI 系统中提供了 CodeQL CLI 服务器, 并确保他们可以通过 GitHub Enterprise Cloud 进行身份验证,便可生成数据。

您使用三个不同的命令生成结果并将它们上传到 GitHub Enterprise Cloud:

  1. database create 以创建 CodeQL 数据库,用于表示存储库中每种支持的编程语言的层次结构。
  2. 使用 database analyze 运行查询以分析每个 CodeQL 数据库,并将结果汇总到 SARIF 文件中。
  3. github upload-results 将得到的 SARIF 文件上传到结果与分支或拉取请求匹配并显示为 code scanning 警报的 GitHub Enterprise Cloud。

可以使用 --help 选项显示任何命令的命令行帮助。

注意:上传 SARIF 数据以显示为 GitHub Enterprise Cloud 中的 code scanning 结果适用于启用了 GitHub Advanced Security 的组织拥有的数据库 和 GitHub.com 上的公共存储库。 有关详细信息,请参阅“管理存储库的安全和分析设置”。

创建 CodeQL 数据库进行分析

  1. 查看要分析的代码:

    • 对于分支,请查看要分析的分支的头。
    • 对于拉取请求,请签出拉取请求的头部提交,或签出 GitHub 生成的拉取请求的合并提交。
  2. 设置代码库的环境,确保所有依赖项都可用。 有关详细信息,请参阅“为 CodeQL 分析准备代码”中的“为未编译的语言创建数据库”和“为已编译的语言创建数据库”。

  3. 查找代码库的生成命令(如果有)。 通常可在 CI 系统的配置文件中找到。

  4. 从存储库的签出根目录运行 codeql database create,并生成代码库。

    # Single supported language - create one CodeQL database
    codeql database create <database> --command <build> \
          --language=<language-identifier>
    
    # Multiple supported languages - create one CodeQL database per language
    codeql database create <database> --command <build> \
          --db-cluster --language=<language-identifier>,<language-identifier>
    

    注意:如果使用容器化构建,需要在执行构建任务的容器内运行 CodeQL CLI。

选项必选使用情况
<database>指定要为 CodeQL 数据库创建的目录的名称和位置。 如果尝试覆盖现有目录,则该命令将失败。 如果还指定 --db-cluster,则这是父目录,并且会为分析的每种语言创建一个子目录。
--language指定要为其创建数据库的语言的标识符,请指定以下值之一:cppcsharpgojavajavascriptpythonrubyswift(使用 javascript 分析 TypeScript 代码 并使用 java 分析 Kotlin 代码)。 与 --db-cluster 一起使用时,该选项接受逗号分隔的列表,也可以多次指定。
--command(推荐)用于指定为代码库调用生成过程的生成命令或脚本。 命令从当前文件夹运行,或者从定义的位置 --source-root 运行。 Python 和 JavaScript/TypeScript 分析不需要。
--db-cluster在多语言代码库中使用,为 --language 指定的每种语言生成一个数据库。
--no-run-unnecessary-builds(推荐)用于抑制 CodeQL CLI 不需要监视生成的语言的生成命令(例如,Python 和 JavaScript/TypeScript)。
--source-root如果在存储库的检出根目录之外运行 CLI,请使用此选项。 默认情况下,database create 命令假定当前目录是源文件的根目录,使用此选项可指定其他位置。
--codescanning-config高级。 如果具有指定如何创建 CodeQL 数据库以及后续步骤中要运行的查询的配置文件,请进行使用。 有关详细信息,请参阅“自定义 代码扫描的高级设置”和“database create”。

有关详细信息,请参阅“为 CodeQL 分析准备代码”。

单语言示例

此示例在 /checkouts/example-repo 为签出的存储库创建 CodeQL 数据库。 它使用 JavaScript 提取器在存储库中创建 JavaScript 和 TypeScript 代码的分层表示形式。 生成的数据库存储在 /codeql-dbs/example-repo 中。

$ codeql database create /codeql-dbs/example-repo --language=javascript \
    --source-root /checkouts/example-repo

> Initializing database at /codeql-dbs/example-repo.
> Running command [/codeql-home/codeql/javascript/tools/autobuild.cmd]
    in /checkouts/example-repo.
> [build-stdout] Single-threaded extraction.
> [build-stdout] Extracting
...
> Finalizing database at /codeql-dbs/example-repo.
> Successfully created database at /codeql-dbs/example-repo.

多语言示例

此示例在 /checkouts/example-repo-multi 为签出的存储库创建两个 CodeQL 数据库。 它使用:

  • --db-cluster 用于请求分析多种语言。
  • --language 用于指定要为其创建数据库的语言。
  • --command 用于告知工具代码库的生成命令,此处为 make
  • --no-run-unnecessary-builds 用于告知工具跳过不需要的语言(如 Python)的生成命令。

生成的数据库存储在 /codeql-dbs/example-repo-multipythoncpp 子目录中。

$ codeql database create /codeql-dbs/example-repo-multi \
    --db-cluster --language python,cpp \
    --command make --no-run-unnecessary-builds \
    --source-root /checkouts/example-repo-multi
Initializing databases at /codeql-dbs/example-repo-multi.
Running build command: [make]
[build-stdout] Calling python3 /codeql-bundle/codeql/python/tools/get_venv_lib.py
[build-stdout] Calling python3 -S /codeql-bundle/codeql/python/tools/python_tracer.py -v -z all -c /codeql-dbs/example-repo-multi/python/working/trap_cache -p ERROR: 'pip' not installed.
[build-stdout] /usr/local/lib/python3.6/dist-packages -R /checkouts/example-repo-multi
[build-stdout] [INFO] Python version 3.6.9
[build-stdout] [INFO] Python extractor version 5.16
[build-stdout] [INFO] [2] Extracted file /checkouts/example-repo-multi/hello.py in 5ms
[build-stdout] [INFO] Processed 1 modules in 0.15s
[build-stdout] <output from calling 'make' to build the C/C++ code>
Finalizing databases at /codeql-dbs/example-repo-multi.
Successfully created databases at /codeql-dbs/example-repo-multi.
$

分析 CodeQL 数据库

  1. 创建 CodeQL 数据库(见上文)。

  2. 对数据库运行 codeql database analyze,并指定要使用的包和/或查询。

    codeql database analyze <database> --format=<format> \
        --output=<output>  --download <packs,queries>
    

注意:如果你针对某个提交分析了一个以上的 CodeQL 数据库,需要为此命令生成的每组结果指定 SARIF 类别。 当您上传结果到 GitHub Enterprise Cloud 时,code scanning 使用此类别来分别存储每种语言的结果。 如果忘记执行此操作,则每次上传都会覆盖之前的结果。

codeql database analyze <database> --format=<format> \
    --sarif-category=<language-specifier> --output=<output> \
    <packs,queries>
选项必选使用情况
<database>指定包含要分析的 CodeQL 数据库的目录路径。
<packs,queries>指定要运行 CodeQL 包或查询。 要运行用于 code scanning 的标准查询,请省略此参数。 要查看 CodeQL CLI 捆绑包中包含的其他查询套件,请查看 /<extraction-root>/qlpacks/codeql/<language>-queries/codeql-suites。 有关创建你自己的查询套件的信息,请参阅 CodeQL CLI 文档中的“创建 CodeQL 查询套件”。
--format指定命令生成的结果文件的格式。 要上传到 GitHub,这应该是:sarif-latest。 有关详细信息,请参阅“对代码扫描的 SARIF 支持”。
--output指定保存 SARIF 结果文件的位置。
--sarif-category对于单一数据库分析是可选的。 对于在为存储库中的单个提交分析多个数据库时定义语言是必需的。

为此分析指定要包含在 SARIF 结果文件中的类别。 类别用于区分针对同一工具和提交的多个分析,但在不同的语言或代码的不同部分执行。
--sarif-add-baseline-file-info(推荐)用于将文件覆盖率信息提交到工具状态页。 有关详细信息,请参阅“关于代码扫描的工具状态页”。
--sarif-add-query-help如果想为分析中使用的自定义查询包含任何可用的 Markdown 呈现查询帮助,请使用此选项。 如果相关查询生成警报,则包含在 SARIF 输出中的自定义查询的任何查询帮助都将显示在代码扫描 UI 中。 有关详细信息,请参阅“使用 CodeQL 查询分析代码”。
<packs>如果要在分析中包含 CodeQL 查询包,请使用此选项。 有关详细信息,请参阅“下载和使用 CodeQL 包”。
--download如果某些 CodeQL 查询包尚未在磁盘上,并且需要在运行查询之前下载,请使用此选项。
--threads如果想使用多个线程来运行查询,请使用此选项。 默认值是 1。 可以指定更多线程来加快查询执行速度。 要将线程数设置为逻辑处理器数,请指定 0
--verbose用于从数据库创建过程中获取有关分析过程和诊断数据的更多详细信息。

有关详细信息,请参阅“使用 CodeQL 查询分析代码”。

分析 CodeQL 数据库的基本示例

此示例分析存储在 /codeql-dbs/example-repo 的 CodeQL 数据库并将结果保存为 SARIF 文件:/temp/example-repo-js.sarif。 它使用 --sarif-category 在 SARIF 文件中包含将结果标识为 JavaScript 的额外信息。 当你有多个 CodeQL 数据库来分析存储库中的单个提交时,这一点至关重要。

$ codeql database analyze /codeql-dbs/example-repo \
    javascript-code-scanning.qls --sarif-category=javascript \
    --format=sarif-latest --output=/temp/example-repo-js.sarif

> Running queries.
> Compiling query plan for /codeql-home/codeql/qlpacks/codeql-javascript/AngularJS/DisablingSce.ql.
...
> Shutting down query evaluator.
> Interpreting results.

将文件覆盖率信息添加到结果以供监视

可以选择将文件覆盖率信息提交到 GitHub Enterprise Cloud,以供显示在 code scanning 的工具状态页上。 有关文件覆盖率信息的详细信息,请参阅“关于代码扫描的工具状态页”。

若要在 code scanning 结果中包含文件覆盖率信息,请将 --sarif-add-baseline-file-info 标志添加到 CI 系统中的 codeql database analyze 调用,例如:

$ codeql database analyze /codeql-dbs/example-repo \
    javascript-code-scanning.qls --sarif-category=javascript \
    --sarif-add-baseline-file-info \ --format=sarif-latest \
    --output=/temp/example-repo-js.sarif

上传结果到 GitHub Enterprise Cloud

可以检查 SARIF 属性是否具有支持上传的大小,以及该文件是否与代码扫描兼容。 有关详细信息,请参阅“对代码扫描的 SARIF 支持”。

在将结果上传到 GitHub Enterprise Cloud 之前,必须确定将 GitHub App 或之前创建的 personal access token 传递给 CodeQL CLI 的最佳方式(请参阅在 CI 系统中安装 CodeQL CLI)。 建议查看 CI 系统有关安全使用机密存储的指南。 CodeQL CLI 支持:

  • 使用 --github-auth-stdin 选项(建议)与机密存储库进行交互。
  • 将机密保存在环境变量 GITHUB_TOKEN 中,并在不包含 --github-auth-stdin 选项的情况下运行 CLI。
  • 出于测试目的,可以传递 --github-auth-stdin 命令行选项,并通过标准输入提供临时令牌。

为 CI 服务器确定最安全可靠的方法后,请在每个 SARIF 结果文件上运行 codeql github upload-results 并包含 --github-auth-stdin,除非该令牌在环境变量 GITHUB_TOKEN 中可用。

# GitHub App or personal access token available from a secret store
<call-to-retrieve-secret> | codeql github upload-results \
    --repository=<repository-name> \
    --ref=<ref> --commit=<commit> \
    --sarif=<file> --github-auth-stdin

# GitHub App or personal access token available in GITHUB_TOKEN
codeql github upload-results \
    --repository=<repository-name> \
    --ref=<ref> --commit=<commit> \
    --sarif=<file> 
选项必选使用情况
--repository指定要将数据上传到的存储库的所有者/名称。 所有者必须是拥有 GitHub Advanced Security 许可证的企业内的组织,而必须为存储库启用 GitHub Advanced Security,除非存储库是公共的。 有关详细信息,请参阅“管理存储库的安全和分析设置”。
--ref指定你签出和分析的 ref 的名称,以便使结果与正确的代码匹配。 用于分支:refs/heads/BRANCH-NAME,用于拉取请求的头提交:refs/pull/NUMBER/head,或者用于拉取请求的 GitHub 生成的合并提交:refs/pull/NUMBER/merge
--commit指定分析的提交的完整 SHA。
--sarif指定要加载的 SARIF 文件。
--github-auth-stdin通过标准输入,将为对 GitHub 的 REST API 进行身份验证而创建的 GitHub App 或 personal access token 从机密存储库传递给 CLI。 如果命令有权访问使用此令牌设置的 GITHUB_TOKEN 环境变量,则不需要执行此操作。

有关详细信息,请参阅“github upload-results”。

将结果上传到 GitHub Enterprise Cloud 的基本示例

下面的示例将结果从 SARIF 文件 temp/example-repo-js.sarif 上传到存储库 my-org/example-repo。 它告诉 code scanning API,结果用于 main 分支上的提交 deb275d2d5fe9a522a0b7bd8b6b6a1c939552718。 该示例假设为对 GitHub 的 REST API 进行身份验证而创建的 GitHub App 或 personal access token 使用 GITHUB_TOKEN 环境变量。

codeql github upload-results \
    --repository=my-org/example-repo \
    --ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
    --sarif=/temp/example-repo-js.sarif 

除非上传未成功,否则此命令不会输出。 上传完成并开始数据处理时,命令提示返回。 在较小的代码库中,您应该能够在稍后的 GitHub Enterprise Cloud 中探索 code scanning 警告。 可以直接在拉取请求或分支的“安全性”选项卡中查看警报,具体取决于检出的代码。有关详细信息,请参阅“鉴定拉取请求中的代码扫描警报”和“管理存储库的代码扫描警报”。

如果分析失败,请将诊断信息上传到 GitHub Enterprise Cloud

CodeQL CLI 成功完成数据库分析后,它会收集诊断信息(例如文件覆盖率、警告和错误),并将这些信息以及结果包含在 SARIF 文件中。 将 SARIF 文件上传到 GitHub 时,诊断信息将显示在存储库的 code scanning 工具状态页上,以便轻松查看 CodeQL 的性能如何并调试任何问题。 有关详细信息,请参阅“关于代码扫描的工具状态页”。

但是,如果 codeql database analyze 因任何原因失败,则没有 SARIF 文件可上传到 GitHub,也没有诊断信息可显示在存储库的 code scanning 工具状态页上。 这使得用户难以对分析进行故障排除,除非他们有权访问你的 CI 系统中的日志文件。

建议将 CI 工作流配置为在分析失败时导出诊断信息并将其上传到 GitHub Enterprise Cloud。 可以使用以下简单命令来导出诊断信息并将其上传到 GitHub。

如果分析失败,则导出诊断信息

可以使用“database export-diagnostics”为失败的分析创建 SARIF 文件,例如:

$ codeql database export-diagnostics codeql-dbs/example-repo \
    --sarif-category=javascript --format=sarif-latest \
    --output=/temp/example-repo-js.sarif

此 SARIF 文件将包含失败分析的诊断信息,其中包括分析期间生成的任何文件覆盖率信息、警告和错误。

如果分析失败,则上传诊断信息

可以通过使用“github upload-results”将 SARIF 文件上传到 GitHub Enterprise Cloud,在工具状态页上提供此诊断信息,例如:

codeql github upload-results \
    --repository=my-org/example-repo \
    --ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
    --sarif=/temp/example-repo-js.sarif 

这与从成功分析上传 SARIF 文件的过程相同。

下载和使用 CodeQL 查询包

注意:CodeQL 包管理功能(包括 CodeQL 包)当前为 beta 版本,可能会发生更改。

CodeQL CLI 捆绑包中包括由 GitHub 专家、安全研究人员和社区贡献者维护的查询。 如果要运行其他组织开发的查询,CodeQL 查询包提供了一种高效可靠的下载和运行查询的方法。 有关详细信息,请参阅“关于使用 CodeQL 进行代码扫描”。

在使用 CodeQL 包分析数据库之前,必须从 GitHub Container registry 下载所需的任何包。 这可以通过使用 --download 标志作为 codeql database analyze 命令的一部分或运行 codeql pack download 来完成。 如果包不是公开可用,需要使用 GitHub App 或 personal access token 进行身份验证。 有关详细信息和示例,请参阅“将结果上传到 GitHub Enterprise Cloud”。

选项必选使用情况
<scope/name@version:path>使用以逗号分隔的列表指定要下载的一个或多个 CodeQL 查询包的作用域和名称。 (可选)包括要下载和解压缩的版本。 默认情况下,将下载此包的最新版本。 (可选)包括要运行的查询、目录或查询套件的路径。 如果未包括路径,则运行此包的默认查询。
--github-auth-stdin通过标准输入,将为对 GitHub 的 REST API 进行身份验证而创建的 GitHub App 或 personal access token 从机密存储库传递给 CLI。 如果命令有权访问使用此令牌设置的 GITHUB_TOKEN 环境变量,则不需要执行此操作。

注意:如果指定要使用的查询包的特定版本,需注意你指定的版本最终可能会变得太旧,使得无法有效使用最新版本的 CodeQL。 为了确保最佳性能,如果需要指定确切的查询包版本,应重新评估每次升级所使用的 CodeQL CLI 时要固定到的版本。

有关包兼容性的详细信息,请参阅“发布及使用 CodeQL 包”。

下载并使用查询包的基本示例

此示例运行包含 --download 选项的 codeql database analyze 命令来执行以下操作:

  1. 下载最新版本的 octo-org/security-queries 包。
  2. 下载与版本 1.0.1 兼容的 octo-org/optional-security-queries 包版本(在本例中为版本 1.0.2)。 有关 SemVer 兼容性的详细信息,请参阅 npm 的语义化版本范围文档
  3. octo-org/security-queries 中运行所有默认查询。
  4. octo-org/optional-security-queries 中仅运行查询 queries/csrf.ql
$ echo $OCTO-ORG_ACCESS_TOKEN | codeql database analyze --download /codeql-dbs/example-repo \
    octo-org/security-queries \
    octo-org/optional-security-queries@~1.0.1:queries/csrf.ql \
    --format=sarif-latest --output=/temp/example-repo-js.sarif

> Download location: /Users/mona/.codeql/packages
> Installed fresh octo-org/security-queries@1.0.0
> Installed fresh octo-org/optional-security-queries@1.0.2
> Running queries.
> Compiling query plan for /Users/mona/.codeql/packages/octo-org/security-queries/1.0.0/potential-sql-injection.ql.
> [1/2] Found in cache: /Users/mona/.codeql/packages/octo-org/security-queries/1.0.0/potential-sql-injection.ql.
> Starting evaluation of octo-org/security-queries/query1.ql.
> Compiling query plan for /Users/mona/.codeql/packages/octo-org/optional-security-queries/1.0.2/queries/csrf.ql.
> [2/2] Found in cache: /Users/mona/.codeql/packages/octo-org/optional-security-queries/1.0.2/queries/csrf.ql.
> Starting evaluation of octo-org/optional-security-queries/queries/csrf.ql.
> [2/2 eval 694ms] Evaluation done; writing results to octo-org/security-queries/query1.bqrs.
> Shutting down query evaluator.
> Interpreting results.

直接下载 CodeQL 包

如果要在不立即运行 CodeQL 包的情况下进行下载,则可以使用 codeql pack download 命令。 如果要避免在运行 CodeQL 查询时访问 Internet,此选项非常有用。 运行 CodeQL 分析时,可以采用与上一示例相同的方式指定包、版本和路径:

echo $OCTO-ORG_ACCESS_TOKEN | codeql pack download <scope/name@version:path> <scope/name@version:path> ...

从多 GitHub 容器注册表下载 CodeQL 包

如果 CodeQL 包存在于多个容器注册表上,就必须指示 CodeQL CLI 在何处查找每个包。 有关详细信息,请参阅“自定义 代码扫描的高级设置”。

用于 CodeQL 分析的示例 CI 配置

这是一系列命令的示例,您可以使用两种支持的语言分析代码库,然后上传结果到 GitHub Enterprise Cloud。

# Create CodeQL databases for Java and Python in the 'codeql-dbs' directory
# Call the normal build script for the codebase: 'myBuildScript'

codeql database create codeql-dbs --source-root=src \
    --db-cluster --language=java,python --command=./myBuildScript

# Analyze the CodeQL database for Java, 'codeql-dbs/java'
# Tag the data as 'java' results and store in: 'java-results.sarif'

codeql database analyze codeql-dbs/java java-code-scanning.qls \
    --format=sarif-latest --sarif-category=java --output=java-results.sarif

# Analyze the CodeQL database for Python, 'codeql-dbs/python'
# Tag the data as 'python' results and store in: 'python-results.sarif'

codeql database analyze codeql-dbs/python python-code-scanning.qls \
    --format=sarif-latest --sarif-category=python --output=python-results.sarif

# Upload the SARIF file with the Java results: 'java-results.sarif'
# The GitHub App or personal access token created for authentication
# with GitHub's REST API is available in the `GITHUB_TOKEN` environment variable.

codeql github upload-results \
    --repository=my-org/example-repo \
    --ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
    --sarif=java-results.sarif

# Upload the SARIF file with the Python results: 'python-results.sarif'

codeql github upload-results \
    --repository=my-org/example-repo \
    --ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
    --sarif=python-results.sarif

使用模型包来分析对自定义依赖项的调用

可以使用 --model-packs 选项,将已发布的模型包包含在 code scanning 分析中。 例如:

$ codeql database analyze /codeql-dbs/my-company --format=sarif-latest \
  --model-packs my-repo/my-java-model-pack \
  --output=/temp/my-company.sarif codeql/java-queries

在此示例中,标准查询包 codeql/java-queries 中的相关查询将使用模型包 my-repo/my-java-model-pack 中的依赖项信息,来检查调用这些依赖项的代码中的漏洞。

可以在分析中指定多个已发布的模型包。

有关编写自己的模型包的详细信息,请参阅“创建并使用 CodeQL 包”。

CI 系统中的 CodeQL CLI 疑难解答

查看日志和诊断信息

当您使用 code scanning 查询套件分析 CodeQL 数据库时,除了生成有关警报的详细信息外,CLI 还报告数据库生成步骤和汇总指标的诊断数据。 对于警报很少的存储库,您可能会发现此信息可用于确定代码中是否真的存在很少的问题,或者生成 CodeQL 数据库时是否出错。 要获取 codeql database analyze 更详细的输出,请使用 --verbose 选项。

有关可用诊断信息类型的详细信息,请参阅“查看代码扫描日志”。

Code scanning 只显示被分析语言之一的分析结果

默认情况下, code scanning 预计每个仓库需要一个SARIF 结果文件。 因此,当您上传第二个 SARIF 结果文件进行提交时,将被视为原始数据集的替换。

如果您想将多组结果上传到 code scanning API 以在存储库中提交,则必须将每组结果识别为唯一的一组结果。 对于需要创建多个 CodeQL 数据库来分析每个提交的存储库,使用 --sarif-category 为每个为该存储库生成的 SARIF 文件指定一个语言或其他独特的类别。

Python 提取的问题

我们将弃用对 CodeQL CLI 的 Python 2 支持,更具体地说,是对 CodeQL 数据库生成阶段(代码提取)的支持。

如果使用 CodeQL CLI 在用 Python 编写的代码上运行 CodeQL code scanning,请必须确保 CI 系统已安装 Python 3。

延伸阅读