关于为分析准备代码
在使用 CodeQL 分析代码之前,需要创建一个 CodeQL 数据库,其中包含对代码运行查询所需的所有数据。 可以使用 CodeQL CLI 自行创建 CodeQL 数据库。
CodeQL 分析依赖于从代码中提取关系数据,并使用它来生成 CodeQL 数据库。 CodeQL 数据库包含有关代码库的所有重要信息,可通过执行 CodeQL 查询对其进行分析。
在生成 CodeQL 数据库之前,需要:
- 安装并设置 CodeQL CLI。 有关详细信息,请参阅“设置 CodeQL CLI”。
- 查看要分析的代码:
- 对于分支,请查看要分析的分支的头。
- 对于拉取请求,请签出拉取请求的头部提交,或签出 GitHub 生成的拉取请求的合并提交。
- 设置代码库的环境,确保所有依赖项都可用。 有关详细信息,请参阅“为非编译语言创建数据库”和“为编译语言创建数据库”。
- 查找代码库的生成命令(如果有)。 通常可在 CI 系统的配置文件中找到。
代码库准备就绪后,可以运行 codeql database create
以创建数据库。
正在运行 codeql database create
CodeQL 数据库是通过从项目的签出根目录运行以下命令创建的:
codeql database create <database> --language=<language-identifier>
必须指定以下内容:
<database>
:要创建的新数据库的路径。 执行命令时将创建此目录,无法指定现有目录。--language
:要为其创建数据库的语言的标识符。 与--db-cluster
一起使用时,该选项接受逗号分隔的列表,也可以多次指定。 CodeQL 支持为以下语言创建数据库:
语言 | 标识符 | 可选替代标识符(如果有) |
---|---|---|
C/C++ | c-cpp | c 或 cpp |
C# | csharp | |
Go | go | |
Java/Kotlin | java-kotlin | java 或 kotlin |
JavaScript/TypeScript | javascript-typescript | javascript 或 typescript |
Python | python | |
Ruby | ruby | |
Swift | swift |
注意:**** 如果指定替代标识符之一,则等效于使用标准语言标识符。 例如,指定 javascript
而不是 javascript-typescript
不排除对 TypeScript 代码的分析。 可以使用 --paths-ignore
选项在高级设置工作流中执行此操作。 有关详细信息,请参阅“自定义 代码扫描的高级设置”。
注意:用于 Kotlin 和 Swift 的 CodeQL 分析目前为 beta 版。 在 Beta 版中,Kotlin 和 Swift 代码的分析以及随附文档不会像其他语言那样全面。 此外,尚不支持 Swift 5.8。
如果你的代码库中有调用构建过程的构建命令或脚本,我们建议你也指定该命令或脚本:
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 、和 swift 。 与 --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 数据库的提取程序的行为。 有关详细信息,请参阅“提取程序选项”。
有关创建数据库时可以使用的所有选项的完整详细信息,请参阅“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.
$
进度和结果
如果指定的选项存在任何问题,将报告错误。 对于解释的语言,提取进度显示在控制台中。 对于每个源文件,控制台显示提取是成功还是失败。 对于已编译的语言,控制台将显示生成系统的输出。
成功创建数据库后,会在命令中指定的路径处找到一个新目录。 如果使用 --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 6.x 或更高版本。 在命令行中,可以指定 --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 版本。
- 你有权访问 pip 打包管理系统,并且可以安装代码库所依赖的任何包。
- 已安装 virtualenv pip 模块。
在命令行中,必须指定 --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 CLI 包括 C/C++、C#、 Go、 Java 以及 Swift 代码的自动生成程序。 CodeQL 自动生成程序允许为编译语言生成项目,而无需指定任何生成命令。 调用自动生成程序时,CodeQL 检查源以获取生成系统的证据,并尝试运行提取数据库所需的最佳命令集。 有关详细信息,请参阅“对编译语言进行 CodeQL 代码扫描”。
如果不包含 --command
选项,则为已编译的 --language
执行 codeql database create
时自动调用自动生成程序。 例如,对于 Java 代码库,只需运行:
codeql database create --language=java-kotlin <output-folder>/java-database
如果代码库使用标准生成系统,则依赖于自动生成程序通常是创建数据库的最简单方法。 对于需要非标准生成步骤的源,可能需要在命令行中显式定义每个步骤。
注意:
- 如果要生成 Go 数据库,请安装 Go 工具链(版本 1.11 或更高版本),如果有依赖项,则相应的依赖项管理器(如 dep)。
- Go 自动生成程序尝试自动检测在存储库中用 Go 编写的代码,并且仅在尝试提取依赖项时运行生成脚本。 若要强制 CodeQL 将提取限制为由生成脚本编译的文件,请设置环境变量
CODEQL_EXTRACTOR_GO_BUILD_TRACING=on
或使用--command
选项指定生成命令。
指定生成命令
以下示例旨在让你了解可为编译语言指定的一些生成命令。
注意:--command
选项接受单个参数,如果需要使用多个命令,请多次指定 --command
。 如果需要传递子命令和选项,则需要引用整个参数才能正确解释。
-
使用
make
生成的 C/C++ 项目:codeql database create cpp-database --language=c-cpp --command=make
-
使用
dotnet build
生成的 C# 项目:最好添加
/t:rebuild
以确保生成所有代码,或者先执行dotnet clean
(未生成的代码不会包含在 CodeQL 数据库中):codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild'
-
使用
CODEQL_EXTRACTOR_GO_BUILD_TRACING=on
环境变量生成的 Go 项目: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'
-
使用 Gradle 生成的 Java 项目:
# Use `--no-daemon` because a build delegated to an existing daemon cannot be detected by CodeQL: codeql database create java-database --language=java-kotlin --command='gradle --no-daemon clean test'
-
使用 Maven 生成的 Java 项目:
codeql database create java-database --language=java-kotlin --command='mvn clean install'
-
使用 Ant 生成的 Java 项目:
codeql database create java-database --language=java-kotlin --command='ant -f build.xml'
-
从 Xcode 项目或工作区生成的 Swift 项目。 默认情况下,将生成最大的 Swift 目标:
最好确保项目处于干净状态,并且没有可用的生成项目。
xcodebuild clean -all codeql database create -l swift swift-database
-
使用
swift build
生成的 Swift 项目:codeql database create -l swift -c "swift build" swift-database
-
使用
xcodebuild
生成的 Swift 项目:codeql database create -l swift -c "xcodebuild build -target your-target" swift-database
可以将
archive
和test
选项传递给xcodebuild
。 但是,建议使用标准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 codeql database create new-database --language=<language> \ --command='bazel build --spawn_strategy=local --nouse_action_cache --noremote_accept_cached --noremote_upload_local_results //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
-
使用自定义生成脚本生成的项目:
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 系统保留该环境,请获取适当的
start-tracing
脚本以在 CI 系统的 shell 环境中设置 CodeQL 变量。
生成代码;(可选)使用存储 start-tracing
脚本的目录中的 end-tracing.{json,sh,bat,ps1}
脚本取消设置环境变量;然后运行命令 codeql database finalize <database>
。
使用间接生成跟踪创建 CodeQL 数据库后,可以像使用任何其他 CodeQL 数据库一样使用该数据库。 例如,如果使用的是代码扫描,请分析数据库并将结果上传到 GitHub。
使用间接生成跟踪创建 CodeQL 数据库的示例
注意:如果使用 Azure DevOps 管道,则创建 CodeQL 数据库最简单的方法是使用 GitHub Advanced Security for Azure DevOps。 有关文档,请参阅 Microsoft Learn 中的配置 GitHub Advanced Security for Azure DevOps。
以下示例演示如何在 Azure DevOps 管道中使用间接生成跟踪来创建 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 查询分析代码”。