Skip to main content

为 CodeQL 分析准备代码

可以生成 CodeQL 数据库,其中包含分析代码所需的数据。

谁可以使用此功能?

GitHub CodeQL 在安装后按用户授权。 根据许可证限制,只能将 CodeQL 用于某些任务。 有关详细信息,请参阅“关于 CodeQL CLI”。

如果你有 GitHub Advanced Security 许可证,则可以使用 CodeQL 进行自动分析、持续集成和持续交付。 有关详细信息,请参阅“关于 GitHub 高级安全性”。

关于为分析准备代码

在使用 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 支持为以下语言创建数据库:

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

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

    注意:用于 Kotlin 和 Swift 的 CodeQL 分析目前为 beta 版。 在 Beta 版中,Kotlin 和 Swift 代码的分析以及随附文档不会像其他语言那样全面。 此外,尚不支持 Swift 5.9。

如果你的代码库中有调用构建过程的构建命令或脚本,我们建议你也指定该命令或脚本:

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

用于创建数据库的选项

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

选项必选使用情况
<database>指定要为 CodeQL 数据库创建的目录的名称和位置。 如果尝试覆盖现有目录,则该命令将失败。 如果还指定 --db-cluster,则这是父目录,并且会为分析的每种语言创建一个子目录。
--language指定要为其创建数据库的语言的标识符,以下之一:c-cppcsharpgojava-kotlinjavascript-typescriptpythonruby、和 swift。 与 --db-cluster 一起使用时,该选项接受逗号分隔的列表,也可以多次指定。
--command推荐。 用于指定为代码库调用生成过程的生成命令或脚本。 命令从当前文件夹运行,或者从定义的位置 --source-root 运行。 Python 和 JavaScript/TypeScript 分析不需要。
--build-modebeta 版本。 当未提供 --command 指定是否在没有生成 (none) 的情况下创建 CodeQL 数据库,或尝试检测生成命令 (autobuild) 时,供 Java 使用。 默认情况下,使用自动生成检测。 有关生成模式的比较,请参阅“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.
$

进度和结果

如果指定的选项存在任何问题,将报告错误。 对于解释语言以及为 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 或更高版本并在 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_modulesbower_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 路径,该路径是执行数据库创建的位置,但不一定是代码库的签出根。

为已编译语言创建数据库

对于t最多已编译语言,CodeQL 需要调用所需的生成系统来生成数据库,因此生成方法必须可用于 CLI。 此方法会创建包含生成的代码的数据库。 CodeQL 有两种方法来生成代码库:

此外,对于 Java,可以选择生成数据库而不生成代码。 如果要为多个存储库启用 code scanning,此选项尤其有用。 有关详细信息,请参阅“CodeQL 生成模式”。

自动检测生成系统

CodeQL CLI 包括 C/C++、C#、 Go、 Java 以及 Swift 代码的自动生成程序。 CodeQL 自动生成程序允许为编译语言生成项目,而无需指定任何生成命令。 调用自动生成程序时,CodeQL 检查源以获取生成系统的证据,并尝试运行提取数据库所需的最佳命令集。 有关详细信息,请参阅“对编译语言进行 CodeQL 代码扫描”。

如果不包含 --command 选项 或设置 --build-mode none,则为已编译语言执行 codeql database create 时自动调用自动生成程序。 例如,对于 C# 代码库,只需运行:

codeql database create --language=csharp <output-folder>/csharp-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
    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` ...

后续步骤