关于准备代码进行分析
在使用 CodeQL 分析代码之前,您需要创建一个包含运行查询所需全部数据的 CodeQL 数据库。您可以使用 CodeQL CLI 自行创建 CodeQL 数据库。
CodeQL 分析依赖于从代码中提取关系数据,并使用这些数据构建CodeQL 数据库。CodeQL 数据库包含代码库的所有重要信息,可通过对其执行 CodeQL 查询进行分析。
在生成 CodeQL 数据库之前,您需要
- 安装并设置 CodeQL CLI。有关详细信息,请参阅设置 CodeQL CLI。
- 检出您想要分析的代码
- 对于分支,请检出您想要分析的分支的 HEAD。
- 对于拉取请求,请检出拉取请求的 HEAD 提交,或检出 GitHub 生成的拉取请求合并提交。
- 为代码库设置环境,确保所有依赖项可用。
- 为了在编译语言上获得最佳效果,请查找代码库的构建命令(如果有)。通常该命令在 CI 系统的配置文件中可找到。
代码库准备就绪后,您可以运行 codeql database create 来创建数据库。有关更多信息,请参阅为非编译语言创建数据库和为编译语言创建数据库。
运行 codeql database create
CodeQL 数据库通过在项目检出根目录运行以下命令创建
codeql database create <database> --language=<language-identifier>
您必须指定
-
<database>:要创建的新数据库的路径。执行命令时会创建此目录——您不能指定已存在的目录。 -
--language:要为其创建数据库的语言标识符。当与--db-cluster一起使用时,该选项接受以逗号分隔的列表,或可以多次指定。CodeQL 支持为以下语言创建数据库语言 标识符 可选的替代标识符(如有) C/C++ c-cppc或cppC# csharpGitHub Actions 工作流 actionsGo goJava/Kotlin java-kotlinjava或kotlinJavaScript/TypeScript javascript-typescriptjavascript或typescriptPython pythonRuby rubyRust rustSwift swift注意
如果指定了替代标识符,其效果等同于使用标准语言标识符。例如,指定
javascript而不是javascript-typescript并不会排除对 TypeScript 代码的分析。相反,您可以使用--codescanning-configCLI 选项加载一个配置文件,在该文件中使用paths-ignore键指定要排除的文件。请参阅代码扫描的工作流配置选项。另外,对于支持此功能的语言,您也可以使用仅构建想要扫描文件的自定义构建命令。参阅为编译语言创建数据库。
如果您的代码库有调用构建过程的构建命令或脚本,建议您一并指定它。
codeql database create <database> --command <build> \
--language=<language-identifier>
创建数据库的选项
您可以根据源文件的位置、代码是否需要编译以及是否希望为多种语言创建 CodeQL 数据库来指定其他选项。
| 选项 | 是否必填 | 用途 |
|---|---|---|
<database> | 指定要为 CodeQL 数据库创建的目录名称和位置。如果尝试覆盖已存在的目录,命令将失败。如果您还指定了 --db-cluster,则此目录为父目录,并为每种分析语言创建子目录。 | |
--language | 指定要为其创建数据库的语言标识符,可选值包括:c-cpp、csharp、go、java-kotlin、javascript-typescript、python、ruby、rust 和 swift。当与 --db-cluster 一起使用时,该选项接受以逗号分隔的列表,或可以多次指定。 | |
--command | 推荐。 用于指定调用代码库构建过程的构建命令或脚本。命令从当前文件夹运行,或在定义的情况下从 --source-root 运行。Python 和 JavaScript/TypeScript 分析不需要此选项。 | |
--build-mode | 推荐。 在未提供 --command 时,用于 C/C++、C#、Java 和 Rust,指示是创建一个不进行构建的 CodeQL 数据库(none)还是尝试自动检测构建命令(autobuild)。默认使用自动检测构建。有关构建模式的比较,请参阅CodeQL 构建模式。 | |
--db-cluster | 在多语言代码库中使用,以根据 --language 指定的每种语言生成一个数据库。 | |
--no-run-unnecessary-builds | 推荐。 用于抑制那些 CodeQL CLI 不需要监视构建过程的语言的构建命令(例如 Python 和 JavaScript/TypeScript)。 | |
--source-root | 当您在仓库检出根之外运行 CLI 时使用。默认情况下,database create 命令假定当前目录是源文件的根目录,使用此选项可指定其他位置。 | |
--codescanning-config | 高级。用于当您有一个配置文件来指定如何创建 CodeQL 数据库以及后续步骤要运行的查询时。有关详细信息,请参阅代码扫描的工作流配置选项和database create。 |
您可以指定提取器选项来自定义创建 CodeQL 数据库的提取器行为。更多信息请参阅提取器选项。
有关创建数据库时可以使用的所有选项的完整详情,请参阅database create。
单语言示例
此示例在 /checkouts/example-repo 检出的位置为仓库创建一个单一的 CodeQL 数据库。它使用 JavaScript 提取器为仓库中的 JavaScript 与 TypeScript 代码创建层级表示。生成的数据库存放在 /codeql-dbs/example-repo 中。
$ codeql database create /codeql-dbs/example-repo --language=javascript-typescript \
--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-multi 下的 python 和 cpp 子目录中。
$ codeql database create /codeql-dbs/example-repo-multi \
--db-cluster --language python,c-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.
$
进度与结果
如果您指定的选项存在问题,系统会报告错误。对于解释型语言以及在 C/C++、C#、Java 和 Rust 中指定 --build-mode none 时,提取进度会显示在控制台。对于每个源文件,控制台会显示提取是成功还是失败。当编译语言被构建时,控制台会显示构建系统的输出。
当数据库成功创建后,您将在命令中指定的路径看到一个新目录。如果使用了 --db-cluster 选项创建了多个数据库,则会为每种语言创建一个子目录。每个 CodeQL 数据库目录包含多个子目录,包括用于分析的关系数据以及源代码存档——在数据库创建时复制的源文件,用于在显示分析结果时使用。
为非编译语言创建数据库
CodeQL CLI 包含用于为非编译语言(具体而言为 JavaScript(及 TypeScript)、Python 和 Ruby)创建数据库的提取器。当您在执行 database create 时将 JavaScript、Python 或 Ruby 作为 --language 选项指定时,这些提取器会自动被调用。为这些语言创建数据库时,必须确保所有额外的依赖项均可用。
注意
在为 JavaScript、TypeScript、Python 和 Ruby 运行 database create 时,您不应指定 --command 选项。否则会覆盖正常的提取器调用,导致创建空数据库。如果为多种语言创建数据库且其中有编译语言,请使用 --no-run-unnecessary-builds 选项跳过那些不需要编译的语言的构建命令。
JavaScript 和 TypeScript
为 JavaScript 创建数据库不需要额外的依赖项,但如果项目包含 TypeScript 文件,则必须安装 Node.js 14 或更高版本,并确保其在 PATH 中以 node 可用。在命令行中可以使用 --language=javascript-typescript 来同时提取 JavaScript 与 TypeScript 文件。
codeql database create --language=javascript-typescript --source-root <folder-to-extract> <output-folder>/javascript-database
这里我们指定了一个 --source-root 路径,它是执行数据库创建的所在位置,但不一定是代码库的检出根目录。
默认情况下,node_modules 和 bower_components 目录中的文件不会被提取。
Python
为 Python 创建数据库时,您必须确保
- 已安装 Python 3,并且 CodeQL 提取器可以访问它。
- 已安装代码所使用的 Python 版本。
在命令行中必须指定 --language=python。例如
codeql database create --language=python <output-folder>/python-database
这将在代码的检出根目录执行 database create 子命令,在 <output-folder>/python-database 生成一个新的 Python 数据库。
Ruby
为 Ruby 创建数据库不需要额外的依赖项。在命令行中必须指定 --language=ruby。例如
codeql database create --language=ruby --source-root <folder-to-extract> <output-folder>/ruby-database
这里我们指定了一个 --source-root 路径,它是执行数据库创建的所在位置,但不一定是代码库的检出根目录。
为编译语言创建数据库
对于大多数编译语言,CodeQL 需要调用相应的构建系统来生成数据库,因此构建方法必须对 CLI 可用。这种方式会创建包含生成代码的数据库。CodeQL 提供了两种构建代码库的方法
此外,对于 C/C++、C#、Java 和 Rust,还可以选择在不构建代码的情况下生成数据库。当您希望为大量仓库启用代码扫描时,这特别有用。更多信息请参阅CodeQL 构建模式。
自动检测构建系统
CodeQL CLI 为 C/C++、C#、Go、Java、Kotlin 和 Swift 代码包含自动构建器。CodeQL 自动构建器允许您在不指定任何构建命令的情况下为编译语言构建项目。当调用自动构建器时,CodeQL 会检查源码中是否有构建系统的痕迹,并尝试运行一套最优的命令以提取数据库。更多信息请参阅编译语言的 CodeQL 代码扫描。
如果您在为编译语言执行 codeql database create 时未包含 --command 选项或将 --build-mode 设为 none,则会自动调用自动构建器。例如,对 Swift 代码库,只需运行
codeql database create --language=swift <output-folder>/swift-database
如果代码库使用的是标准构建系统,依赖自动构建器往往是创建数据库的最简单方式。对于需要非标准构建步骤的源码,您可能需要在命令行中显式定义每一步。
注意
- 如果您正在构建 Go 数据库,请安装 Go 工具链(版本 1.11 或更高),并在有依赖的情况下安装相应的依赖管理器(如 dep)。
- Go 自动构建器会尝试自动检测仓库中的 Go 代码,并仅在尝试获取依赖时运行构建脚本。若要强制 CodeQL 将提取限制为您构建脚本编译的文件,请设置环境变量
CODEQL_EXTRACTOR_GO_BUILD_TRACING=on,或使用--command选项指定构建命令。
指定构建命令
以下示例旨在帮助您了解可为编译语言指定的部分构建命令。
注意
--command 选项接受单个参数——如果需要使用多个命令,请多次指定 --command。如果需要传递子命令和选项,整个参数必须加引号以确保正确解析。
-
C/C++ 项目使用
make构建# Disable parallel execution via `-j1` or other techniques: https://gnu.net.cn/software/make/manual/make.html#Parallel-Execution codeql database create cpp-database --language=c-cpp --command=make -
C# 项目使用
dotnet build构建建议添加
/t:rebuild以确保所有代码均被构建,或在此之前执行dotnet clean(未构建的代码不会包含在 CodeQL 数据库中)codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild' -
Go 项目使用
CODEQL_EXTRACTOR_GO_BUILD_TRACING=on环境变量构建CODEQL_EXTRACTOR_GO_BUILD_TRACING=on codeql database create go-database --language=go -
Go 项目使用自定义构建脚本构建
codeql database create go-database --language=go --command='./scripts/build.sh' -
Java 项目使用 Gradle 构建
# Use `--no-daemon` because a build delegated to an existing daemon cannot be detected by CodeQL. # To ensure isolated builds without caching, add `--no-build-cache` on persistent machines. codeql database create java-database --language=java-kotlin --command='gradle --no-daemon clean test' -
Java 项目使用 Maven 构建
codeql database create java-database --language=java-kotlin --command='mvn clean install' -
Java 项目使用 Ant 构建
codeql database create java-database --language=java-kotlin --command='ant -f build.xml' -
Rust 项目使用 Cargo 构建
codeql database create rust-database --language=rust -
Swift 项目从 Xcode 项目或工作区构建。默认情况下,会构建最大的 Swift 目标
建议确保项目处于干净状态,并且没有可用的构建产物。
xcodebuild clean -all codeql database create -l swift swift-database -
Swift 项目使用
swift build构建codeql database create -l swift -c "swift build" swift-database -
Swift 项目使用
xcodebuild构建codeql database create -l swift -c "xcodebuild build -target your-target" swift-database您可以向
xcodebuild传递archive和test选项。不过,推荐使用标准的xcodebuild命令,因为它通常是最快的,并且已满足 CodeQL 成功扫描所需的全部条件。 -
Swift 项目使用自定义构建脚本构建
codeql database create -l swift -c "./scripts/build.sh" swift-database -
项目使用 Bazel 构建
# Navigate to the Bazel workspace. # Before building, remove cached objects # and stop all running Bazel server processes. bazel clean --expunge # Build using the following Bazel flags, to help CodeQL detect the build: # `--spawn_strategy=local`: build locally, instead of using a distributed build # `--nouse_action_cache`: turn off build caching, which might prevent recompilation of source code # `--noremote_accept_cached`, `--noremote_upload_local_results`: avoid using a remote cache # `--disk_cache=`: avoid using a disk cache. Note that a disk cache is no longer considered a remote cache as of Bazel 6. codeql database create new-database --language=<language> \ --command='bazel build --spawn_strategy=local --nouse_action_cache --noremote_accept_cached --noremote_upload_local_results --disk_cache= //path/to/package:target' # After building, stop all running Bazel server processes. # This ensures future build commands start in a clean Bazel server process # without CodeQL attached. bazel shutdown
注意
当前不支持使用 Bazel 构建 Go 项目。
-
项目使用自定义构建脚本构建
codeql database create new-database --language=<language> --command='./scripts/build.sh'
此命令运行包含构建项目所需全部命令的自定义脚本。
使用间接构建跟踪
如果 CodeQL CLI 的编译语言自动构建器在您的 CI 工作流中无法使用,且您无法使用 codeql database trace-command 包装构建命令的调用,则可以使用间接构建跟踪来创建 CodeQL 数据库。要使用间接构建跟踪,您的 CI 系统必须能够为每个构建动作设置自定义环境变量。
要使用间接构建跟踪创建 CodeQL 数据库,请在项目的检出根目录运行以下命令
codeql database init ... --begin-tracing <database>
您必须指定
<database>:要创建的新数据库的路径。执行命令时会创建此目录——您不能指定已存在的目录。--begin-tracing:创建可用于设置构建命令被跟踪的环境的脚本。
您可以像往常一样为 codeql database init 命令指定其他选项。
注意
如果构建在 Windows 上运行,必须设置 --trace-process-level <number> 或 --trace-process-name <parent process name>,使该选项指向将观察所有代码分析构建步骤的父 CI 进程。
codeql database init 命令将输出一条信息
Created skeleton <database>. This in-progress database is ready to be populated by an extractor. In order to initialise tracing, some environment variables need to be set in the shell your build will run in. A number of scripts to do this have been created in <database>/temp/tracingEnvironment. Please run one of these scripts before invoking your build command.
Based on your operating system, we recommend you run: ...
codeql database init 命令会在 <database>/temp/tracingEnvironment 下创建包含环境变量及其值的文件,这些文件将使 CodeQL 能够跟踪一系列构建步骤。这些文件命名为 start-tracing.{json,sh,bat,ps1}。请使用这些文件之一通过您的 CI 系统的机制为后续步骤设置环境变量。您可以
- 读取 JSON 文件,处理后按 CI 系统期望的格式输出环境变量。例如,Azure DevOps 需要
echo "##vso[task.setvariable variable=NAME]VALUE"。 - 或者,如果您的 CI 系统会持久化环境,则在 CI 系统的 shell 环境中 source 相应的
start-tracing脚本,以设置 CodeQL 变量。
构建代码;可选地,使用位于存放 start-tracing 脚本的目录中的 end-tracing.{json,sh,bat,ps1} 脚本取消环境变量;随后运行 codeql database finalize <database> 命令。
使用间接构建跟踪创建 CodeQL 数据库后,您可以像使用其他任何 CodeQL 数据库一样使用它。例如,分析该数据库,并在使用代码扫描时将结果上传到 GitHub。
使用间接构建跟踪创建 CodeQL 数据库的示例
注意
如果您使用 Azure DevOps Pipelines,创建 CodeQL 数据库的最简单方式是使用 GitHub Advanced Security for Azure DevOps。有关文档,请参阅 Microsoft Learn 中的为 Azure DevOps 配置 GitHub Advanced Security。
以下示例展示了如何在 Azure DevOps pipeline 中使用间接构建跟踪来创建 CodeQL 数据库
steps:
# Download the CodeQL CLI and query packs...
# Check out the repository ...
# Run any pre-build tasks, for example, restore NuGet dependencies...
# Initialize the CodeQL database.
# In this example, the CodeQL CLI has been downloaded and placed on the PATH.
- task: CmdLine@1
displayName: Initialize CodeQL database
inputs:
# Assumes the source code is checked out to the current working directory.
# Creates a database at `<current working directory>/db`.
# Running on Windows, so specifies a trace process level.
script: "codeql database init --language csharp --trace-process-name Agent.Worker.exe --source-root . --begin-tracing db"
# Read the generated environment variables and values,
# and set them so they are available for subsequent commands
# in the build pipeline. This is done in PowerShell in this example.
- task: PowerShell@1
displayName: Set CodeQL environment variables
inputs:
targetType: inline
script: >
$json = Get-Content $(System.DefaultWorkingDirectory)/db/temp/tracingEnvironment/start-tracing.json | ConvertFrom-Json
$json.PSObject.Properties | ForEach-Object {
$template = "##vso[task.setvariable variable="
$template += $_.Name
$template += "]"
$template += $_.Value
echo "$template"
}
# Execute the pre-defined build step. Note the `msbuildArgs` variable.
- task: VSBuild@1
inputs:
solution: '**/*.sln'
msbuildArgs: /p:OutDir=$(Build.ArtifactStagingDirectory)
platform: Any CPU
configuration: Release
# Execute a clean build, in order to remove any existing build artifacts prior to the build.
clean: True
displayName: Visual Studio Build
# Read and set the generated environment variables to end build tracing. This is done in PowerShell in this example.
- task: PowerShell@1
displayName: Clear CodeQL environment variables
inputs:
targetType: inline
script: >
$json = Get-Content $(System.DefaultWorkingDirectory)/db/temp/tracingEnvironment/end-tracing.json | ConvertFrom-Json
$json.PSObject.Properties | ForEach-Object {
$template = "##vso[task.setvariable variable="
$template += $_.Name
$template += "]"
$template += $_.Value
echo "$template"
}
- task: CmdLine@2
displayName: Finalize CodeQL database
inputs:
script: 'codeql database finalize db'
# Other tasks go here, for example:
# `codeql database analyze`
# then `codeql github upload-results` ...
后续步骤
- 要了解如何使用 CodeQL CLI 分析您从代码创建的数据库,请参阅使用 CodeQL 查询分析代码。