跳到主要内容

准备您的代码以进行 CodeQL 分析

您可以构建一个 CodeQL 数据库,其中包含分析代码所需的数据。

谁可以使用此功能?

具有仓库**读取**访问权限的用户

CodeQL 可用于以下类型的仓库

关于准备您的代码进行分析

在使用 CodeQL 分析代码之前,您需要创建一个 CodeQL 数据库,其中包含运行代码查询所需的所有数据。您可以使用 CodeQL CLI 自己创建 CodeQL 数据库。

CodeQL 分析依赖于从代码中提取关系数据,并使用它来构建CodeQL 数据库。CodeQL 数据库包含关于代码库的所有重要信息,可以通过对它执行 CodeQL 查询来进行分析。

在生成 CodeQL 数据库之前,您需要

  1. 安装并设置 CodeQL CLI。有关更多信息,请参阅“设置 CodeQL CLI”。
  2. 检出要分析的代码
    • 对于分支,检出要分析的分支的头部。
    • 对于拉取请求,检出拉取请求的头部提交,或检出 GitHub 生成的拉取请求合并提交。
  3. 为代码库设置环境,确保所有依赖项都可用。
  4. 为了获得编译语言的最佳结果,请查找代码库的构建命令(如果有)。这通常在 CI 系统的配置文件中可用。

代码库准备就绪后,您可以运行codeql database create来创建数据库。有关更多信息,请参阅“为非编译语言创建数据库”和“为编译语言创建数据库”。

运行codeql database create

CodeQL 数据库是通过在项目的检出根目录中运行以下命令创建的

codeql database create <database> --language=<language-identifier>

您必须指定

  • <database>:要创建的新数据库的路径。执行命令时将创建此目录,您不能指定现有目录。

  • --language:要为其创建数据库的语言的标识符。与--db-cluster一起使用时,该选项接受逗号分隔的列表,或者可以多次指定。CodeQL 支持为以下语言创建数据库

    语言标识符可选的替代标识符(如果有)
    C/C++c-cppccpp
    C#csharp
    Gogo
    Java/Kotlinjava-kotlinjavakotlin
    JavaScript/TypeScriptjavascript-typescriptjavascripttypescript
    Pythonpython
    Rubyruby
    Swiftswift

    注意

    如果您指定其中一个替代标识符,则这等效于使用标准语言标识符。例如,指定javascript而不是javascript-typescript不会排除对 TypeScript 代码的分析。您可以在高级设置工作流程中使用--paths-ignore选项执行此操作。有关更多信息,请参阅“自定义代码扫描的高级设置”。

如果您的代码库具有调用构建过程的构建命令或脚本,我们建议您也指定它

   codeql database create <database> --command <build> \
         --language=<language-identifier>

创建数据库的选项

您可以根据源文件的位置、代码是否需要编译以及是否要为多种语言创建 CodeQL 数据库来指定其他选项。

选项必需用法
<database>指定要为 CodeQL 数据库创建的目录的名称和位置。如果您尝试覆盖现有目录,则命令将失败。如果您还指定--db-cluster,则这是父目录,并且为分析的每种语言创建一个子目录。
--language指定要为其创建数据库的语言的标识符,其中之一:c-cppcsharpgojava-kotlinjavascript-typescriptpythonrubyswift。与--db-cluster一起使用时,该选项接受逗号分隔的列表,或者可以多次指定。
--command**推荐。** 用于指定调用代码库构建过程的构建命令或脚本。命令从当前文件夹运行,或在定义的情况下从--source-root运行。Python 和 JavaScript/TypeScript 分析不需要。
--build-mode**推荐。** 在不提供--command的情况下,用于 C# 和 Java 指定是否在没有构建的情况下创建 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-multipythoncpp 子目录中。

$ 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# 和 Java 指定--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 或更高版本,并将其作为node 可用于PATH。在命令行中,您可以指定--language=javascript-typescript 来提取 JavaScript 和 TypeScript 文件。

codeql database create --language=javascript-typescript --source-root <folder-to-extract> <output-folder>/javascript-database

这里,我们指定了一个--source-root 路径,这是执行数据库创建的位置,但不一定是代码库的检出根目录。

默认情况下,不会提取node_modulesbower_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# 和 Java,可以选择在不构建代码的情况下生成数据库。当您想要为许多存储库启用代码扫描时,这尤其有用。更多信息,请参见“CodeQL 构建模式”。

自动检测构建系统

CodeQL CLI 包含用于 C/C++、C#、Go、Java、Kotlin 和 Swift 代码的自动构建器。CodeQL 自动构建器允许您在不指定任何构建命令的情况下为编译型语言构建项目。当调用自动构建器时,CodeQL 会检查源代码中是否存在构建系统的证据,并尝试运行提取数据库所需的最优命令集。更多信息,请参见“CodeQL 编译语言代码扫描”。

如果您不包含--command 选项或设置--build-mode none,则在为编译型语言执行codeql database create 时会自动调用自动构建器。例如,对于 C/C++ 代码库,您可以简单地运行

codeql database create --language=cpp <output-folder>/cpp-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.
    # 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'
    
  • 使用 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
    

    您可以将archivetest 选项传递给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
    # `--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
    
  • 使用自定义构建脚本构建的项目

    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 数据库最简单的方法是使用适用于 Azure DevOps 的 GitHub 高级安全功能。有关文档,请参阅 Microsoft Learn 中的配置适用于 Azure DevOps 的 GitHub 高级安全功能

以下示例显示了如何在 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` ...

后续步骤