Skip to main content

Como preparar seu código para a análise do CodeQL

Você pode criar um banco de dados do CodeQL contendo os dados necessários para analisar o código.

Quem pode usar esse recurso?

Usuários com acesso de leitura a um repositório

O CodeQL está disponível para os seguintes tipos de repositórios:

Sobre como preparar seu código para análise

Antes de analisar o código usando o CodeQL, você precisa criar um banco de dados do CodeQL contendo todos os dados necessários para executar consultas no código. Você pode criar bancos de dados do CodeQL usando a CodeQL CLI.

A análise do CodeQL depende da extração de dados relacionais do código e do uso deles para criar um banco de dados do CodeQL. Os bancos de dados do CodeQL contêm todas as informações importantes sobre uma base de código, que podem ser analisadas executando consultas do CodeQL.

Antes de gerar um banco de dados do CodeQL, você precisa:

  1. Instalar e configurar a CodeQL CLI. Para obter mais informações, confira "Como configurar a CLI do CodeQL".
  2. Confira o código que você deseja analisar:
    • Para uma ramificação, confira o cabeçalho da ramificação que você deseja analisar.
    • Para uma solicitação de pull, faça check-out do commit principal da solicitação de pull ou confira um commit de mesclagem da solicitação de pull gerado pelo GitHub.
  3. Configure o ambiente para a base de código, verificando se todas as dependências estão disponíveis.
  4. Para melhores resultados com linguagens compiladas, encontre o comando de compilação (se houver) para a sua base de código. Normalmente, isso está disponível em um arquivo de configuração no sistema de CI.

Quando a base de código estiver pronta, execute codeql database create para criar o banco de dados. Para obter mais informações, confira "Como criar bancos de dados para linguagens não compiladas" e "Como criar bancos de dados para linguagens compiladas".

Em execuçãocodeql database create

Os bancos de dados do CodeQL são criados executando o seguinte comando na raiz de check-out do projeto:

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

É preciso especificar:

  • <database>: é um caminho para o novo banco de dados a ser criado. Esse diretório será criado quando você executar o comando. Não é possível especificar um diretório existente.

  • --language: o identificador da linguagem em que o banco de dados será criado. Quando usado com --db-cluster, a opção aceita uma lista separada por vírgulas ou pode ser especificada mais de uma vez. O CodeQL dá suporte à criação de bancos de dados para as seguintes linguagens:

    IdiomaIdentificadorIdentificadores alternativos opcionais (se houver)
    C/C++c-cppc ou cpp
    C#csharp
    Irgo
    Java/Kotlinjava-kotlinjava ou kotlin
    JavaScript/TypeScriptjavascript-typescriptjavascript ou typescript
    Pythonpython
    Rubyruby
    Swiftswift

    Nota: especificar um dos identificadores alternativos equivale a usar o identificador de idioma padrão. Por exemplo, especificar javascript em vez de javascript-typescript não excluirá a análise do código TypeScript. Você pode fazer isso em um fluxo de trabalho de configuração avançada com a opção --paths-ignore. Para obter mais informações, confira "Personalizando a configuração avançada para varredura de código".

Se a sua base de código tiver um comando ou script de compilação que invoque o processo de compilação, recomendamos que você o especifique também:

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

Opções para criar bancos de dados

Você poderá especificar opções adicionais dependendo do local do arquivo de origem se o código precisar ser compilado e se quiser criar bancos de dados do CodeQL para mais de uma linguagem.

OpçãoObrigatórioUso
<database>Especifique o nome e local de um diretório a ser criado para o banco de dados de CodeQL. O comando falhará se você tentar substituir um diretório. Se você também especificar --db-cluster, esse será o diretório pai e um subdiretório será criado para cada linguagem analisada.
--languageEspecifique o identificador do idioma para o qual criar um banco de dados, um dos seguintes: c-cpp, csharp, go, java-kotlin, javascript-typescript, python, ruby e swift. Quando usado com --db-cluster, a opção aceita uma lista separada por vírgulas ou pode ser especificada mais de uma vez.
--commandRecomendado. Use para especificar o comando ou o script de build que invoca o processo de build para a base de código. Os comandos são executados da pasta atual ou, quando definidos, de --source-root. Não é necessário para a análise de Python e JavaScript/TypeScript.
--build-modeRecomendado. Use para C# e Java quando não fornecer um --command a fim de especificar se um banco de dados do CodeQL deve ser criado sem compilação (none) ou se deve haver uma tentativa de detecção automática do comando de compilação (autobuild). Por padrão, a detecção de compilação automática é usada. Para uma comparação dos modos de compilação, consulte "Modos de compilação do CodeQL".
--db-clusterUse bases de código de linguagem múltipla para gerar um banco de dados para cada linguagem especificada por --language.
--no-run-unnecessary-buildsRecomendado. Use para suprimir o comando de compilação para linguagens em que CodeQL CLI não precisa monitorar a criação (por exemplo, Python e JavaScript/TypeScript).
--source-rootUse se você executa a CLI fora da raiz de check-out do repositório. Por padrão, o comando database create pressupõe que o diretório atual seja o diretório raiz dos arquivos de origem. Use essa opção para especificar outro local.
--codescanning-configAvançado. Use se você tiver um arquivo de configuração que especifica como criar os bancos de dados CodeQL e quais consultas serão executadas em etapas posteriores. Para obter mais informações, confira "Personalizando a configuração avançada para varredura de código" e "database create."

Você pode especificar opções de extrator para personalizar o comportamento de extratores que criam bancos de dados do CodeQL. Para obter mais informações, confira "Opções do extrator".

Para obter detalhes completos de todas as opções que você pode usar ao criar bancos de dados, confira "database create".

Exemplo de linguagem única

Este exemplo cria um único banco de dados do CodeQL para o repositório com check-out em /checkouts/example-repo. Ele usa o extrator de JavaScript para criar uma representação hierárquica do código JavaScript e TypeScript no repositório. O banco de dados resultante é armazenado no /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.

Exemplo de linguagem múltipla

Este exemplo cria dois bancos de dados do CodeQL para o repositório com check-out em /checkouts/example-repo-multi. Ele usa:

  • --db-cluster para solicitar a análise de mais de uma linguagem.
  • --language para especificar para quais linguagens os bancos de dados são criados.
  • --command para indicar o comando de build para a base de código à ferramenta, acesse aqui make.
  • --no-run-unnecessary-builds para informar a ferramenta para ignorar o comando de build para linguagens em que ele não é necessário (como Python).

Os bancos de dados resultantes são armazenados em subdiretórios python e cpp do /codeql-dbs/example-repo-multi.

$ 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.
$

Progresso e resultados

Erros serão relatados se houver problemas com as opções especificadas. Para linguagens interpretadas e quando você especifica --build-mode none para C# e Java, o progresso da extração é exibido no console. Para cada arquivo de origem, o console mostra se a extração foi bem-sucedida ou se falhou. Quando uma linguagem é compilada, o console exibirá a saída do sistema de build.

Quando o banco de dados for criado com êxito, haverá um novo diretório no caminho especificado no comando. Se você usou a opção --db-cluster para criar mais de um banco de dados, um subdiretório será criado para cada linguagem. Cada diretório de banco de dados do CodeQL contém vários subdiretórios, incluindo os dados relacionais (necessários para análise) e um arquivo de origem. Uma cópia dos arquivos de origem feita durante a criação do banco de dados, que é usado para exibir resultados de análise.

Como criar bancos de dados para linguagens não compiladas

A CodeQL CLI inclui extratores para criar bancos de dados para as linguagens não compiladas JavaScript (e TypeScript), Python e Ruby. Esses extratores são invocados automaticamente quando você especifica JavaScript, Python ou Ruby como a opção --language ao executar database create. Ao criar bancos de dados para essas linguagens, você precisa garantir que todas as dependências adicionais estejam disponíveis.

Observação: ao executar database create para JavaScript, TypeScript, Python e Ruby, você não deve especificar uma opção --command. Caso contrário, isso substituirá a invocação normal do extrator, que criará um banco de dados vazio. Se você criar bancos de dados para várias linguagens e uma delas for uma linguagem compilada, use a opção --no-run-unnecessary-builds para ignorar o comando em linguagens que não precisam ser compiladas.

JavaScript e TypeScript

A criação de bancos de dados para JavaScript não requer dependências adicionais, mas se o projeto incluir arquivos TypeScript, o Node.js 14 ou superior precisará ser instalado e estar disponível no PATH como node. Na linha de comando, você pode especificar --language=javascript-typescript para extrair arquivos JavaScript e TypeScript:

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

Aqui, especificamos um caminho --source-root, que é o local em que a criação do banco de dados é executada, mas não é necessariamente a raiz de check-out da base de código.

Por padrão, os arquivos nos diretórios node_modules e bower_components não são extraídos.

Python

Ao criar bancos de dados para Python, você precisa:

  • Ter o Python 3 instalado e disponível para o extrator do CodeQL.
  • Ter a versão do Python usada pelo código instalada.

Na linha de comando, você precisa especificar --language=python. Por exemplo:

codeql database create --language=python <output-folder>/python-database

Isso executa o subcomando database create da raiz de check-out do código, gerando um novo banco de dados Python em <output-folder>/python-database.

Ruby

A criação de bancos de dados para Ruby não requer dependências adicionais. Na linha de comando, você precisa especificar --language=ruby. Por exemplo:

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

Aqui, especificamos um caminho --source-root, que é o local em que a criação do banco de dados é executada, mas não é necessariamente a raiz de check-out da base de código.

Como criar bancos de dados para linguagens compiladas

Para a maioria das linguagens compiladas, o CodeQL precisa invocar o sistema de build necessário para gerar um banco de dados, portanto, o método de build precisa estar disponível para a CLI. Essa abordagem cria bancos de dados que incluem código gerado. CodeQL tem dois métodos para compilar bases de código:

Além disso, para C# e Java, existe a opção de gerar um banco de dados sem compilar o código. Isso é particularmente útil quando você deseja habilitar o code scanning para muitos repositórios. Para mais informações, consulte "Modos de compilação do CodeQL".

Detectando o sistema de compilação automaticamente

A CodeQL CLI inclui construtores automáticos para códigos em C/C++, C#, Go, Java, Kotlin, e Swift. Os construtores automáticos do CodeQL permitem que você crie projetos para linguagens compiladas sem especificar comandos de build. Quando um construtor automático é invocado, o CodeQL examina a origem para obter evidências de um sistema de build e tenta executar o conjunto ideal de comandos necessários para extrair um banco de dados. Para obter mais informações, confira "Verificação de código do CodeQL para linguagens compiladas".

Um compilador automático ("autobuilder") é invocado automaticamente quando você executa codeql database create para uma linguagem compilada caso você não inclua uma opção --command ou defina --build-mode none . Por exemplo, para uma base de código C/C++, você poderia simplesmente executar:

codeql database create --language=cpp <output-folder>/cpp-database

Se uma base de código usa um sistema de build padrão, a dependência de um construtor automático geralmente é a maneira mais simples de criar um banco de dados. Para fontes que exigem etapas de build não padrão, talvez seja necessário definir explicitamente cada etapa na linha de comando.

Observações:

  • Se você estiver criando um banco de dados Go, instale a cadeia de ferramentas Go (versão 1.11 ou posterior) e, se houver dependências, o gerenciador de dependências apropriado (como o dep).
  • O construtor automático Go tenta detectar automaticamente o código escrito em Go em um repositório e executa apenas scripts de build na tentativa de buscar dependências. Para forçar o CodeQL a limitar a extração aos arquivos compilados pelo script de build, defina a variável de ambiente CODEQL_EXTRACTOR_GO_BUILD_TRACING=on ou use a opção --command para especificar um comando de build.

Como especificar comandos de build

Os exemplos a seguir foram projetados para dar uma ideia de alguns dos comandos de build que você pode especificar para linguagens compiladas.

Nota: a opção --command aceita um só argumento. Se você precisar usar mais de um comando, especifique --command várias vezes. Se você precisar passar subcomandos e opções, todo o argumento precisará ser colocado entre aspas para ser interpretado corretamente.

  • Projeto C/C++ criado usando make:

    codeql database create cpp-database --language=c-cpp --command=make
    
  • Projeto C# criado usando dotnet build:

    É bom adicionar /t:rebuild para garantir que todo o código seja criado ou fazer um dotnet clean anterior (o código que não foi criado não será incluído no banco de dados do CodeQL):

    codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild'
    
  • Projeto Go criado usando a variável de ambiente CODEQL_EXTRACTOR_GO_BUILD_TRACING=on:

    CODEQL_EXTRACTOR_GO_BUILD_TRACING=on codeql database create go-database --language=go
    
  • Projeto Go criado usando um script de build personalizado:

    codeql database create go-database --language=go --command='./scripts/build.sh'
    
  • Projeto Java criado usando o 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'
    
  • Projeto Java criado usando o Maven:

    codeql database create java-database --language=java-kotlin --command='mvn clean install'
    
  • Projeto Java criado usando o Ant:

    codeql database create java-database --language=java-kotlin --command='ant -f build.xml'
    
  • Projeto Swift criado a partir de um projeto ou workspace do Xcode. Por padrão, o maior destino Swift é criado:

    É uma boa ideia garantir que o projeto esteja em um estado limpo e que não haja artefatos de compilação disponíveis.

    xcodebuild clean -all
    codeql database create -l swift swift-database
    
  • Projeto Swift criado com swift build:

    codeql database create -l swift -c "swift build" swift-database
    
  • Projeto Swift criado com xcodebuild:

    codeql database create -l swift -c "xcodebuild build -target your-target" swift-database
    

    Você pode passar as opções archive e test para xcodebuild. No entanto, o comando xcodebuild padrão é recomendado, pois deve ser o mais rápido e deve ser tudo o que o CodeQL exige para uma verificação bem-sucedida.

  • Projeto Swift criado usando um script de build personalizado:

    codeql database create -l swift -c "./scripts/build.sh" swift-database
    
  • Projeto criado usando o 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
    
  • Projeto criado usando um script de build personalizado:

    codeql database create new-database --language=<language> --command='./scripts/build.sh'
    

Esse comando executa um script personalizado que contém todos os comandos necessários para compilar o projeto.

Como usar o rastreamento de build indireto

Se os construtores automáticos da CodeQL CLI para linguagens compiladas não funcionarem com seu fluxo de trabalho de CI e você não puder encapsular invocações de comandos de build com codeql database trace-command, use o rastreamento de build indireto para criar um banco de dados do CodeQL. Para usar o rastreamento de build indireto, o sistema de CI precisa ser capaz de definir variáveis de ambiente personalizadas para cada ação de build.

Para criar um banco de dados do CodeQL com rastreamento de build indireto, execute o seguinte comando na raiz de check-out do projeto:

codeql database init ... --begin-tracing <database>

É preciso especificar:

  • <database>: é um caminho para o novo banco de dados a ser criado. Esse diretório será criado quando você executar o comando. Não é possível especificar um diretório existente.
  • --begin-tracing: cria scripts que podem ser usados para configurar um ambiente no qual os comandos de build serão rastreados.

Você pode especificar outras opções para o comando codeql database init como de costume.

Observação: se o build for executado no Windows, você precisará definir --trace-process-level <number> ou --trace-process-name <parent process name> para que a opção aponte a um processo de CI pai que observará todas as etapas de build do código que está sendo analisado.

O comando codeql database init vai gerar uma mensagem:

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: ...

O comando codeql database init cria <database>/temp/tracingEnvironment com arquivos que contêm variáveis de ambiente e valores que permitirão que o CodeQL rastreie uma sequência de etapas de build. Esses arquivos são chamados de start-tracing.{json,sh,bat,ps1}. Use um desses arquivos com o mecanismo do sistema de CI para definir variáveis de ambiente de etapas futuras. Você pode:

  • Ler o arquivo JSON, processá-lo e imprimir variáveis de ambiente no formato esperado pelo sistema de CI. Por exemplo, o Azure DevOps espera echo "##vso[task.setvariable variable=NAME]VALUE".
  • Ou, se o sistema de CI persistir o ambiente, crie o script start-tracing apropriado para definir as variáveis do CodeQL no ambiente de shell do sistema de CI.

Crie o código. Opcionalmente, remova a definição das variáveis de ambiente usando um script end-tracing.{json,sh,bat,ps1} do diretório em que os scripts start-tracing são armazenados e depois execute o comando codeql database finalize <database>.

Depois de criar um banco de dados do CodeQL usando o rastreamento de build indireto, você pode trabalhar com ele como qualquer outro banco de dados do CodeQL. Por exemplo, analise o banco de dados e carregue os resultados no GitHub ao usar a verificação de código.

Exemplo de criação de um banco de dados do CodeQL usando o rastreamento de build indireto

Observação: se você usar pipelines do Azure DevOps, a maneira mais simples de criar um banco de dados do CodeQL será usar GitHub Advanced Security for Azure DevOps. Para obter a documentação, veja Configurar o GitHub Advanced Security for Azure DevOps no Microsoft Learn.

O exemplo a seguir mostra como você pode usar o rastreamento de build indireto em um pipeline do Azure DevOps para criar um banco de dados do 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` ...

Próximas etapas