Skip to main content

Preparación del código para el análisis de CodeQL

Puedes crear una base de datos de CodeQL que contenga los datos necesarios para analizar el código.

¿Quién puede utilizar esta característica?

Las licencias de GitHub CodeQL se otorgan por usuario tras la instalación. Puedes usar CodeQL solo para determinadas tareas según las restricciones de las licencias. Para obtener más información, vea «Acerca de la CLI de CodeQL».

Si tienes una licencia de GitHub Advanced Security, puedes usar CodeQL para el análisis automatizado, la integración continua y la entrega continua. Para obtener más información, vea «Acerca de GitHub Advanced Security».

Acerca de la preparación del código para el análisis

Nota: En este artículo se describen las características disponibles con el paquete CodeQL CLI 2.15.5 que se incluye en la versión inicial de GitHub Enterprise Server 3.12.

Si el administrador del sitio ha actualizado tu versión de la CodeQL CLI a una versión más reciente, consulta la versión de GitHub Enterprise Cloud de este artículo para obtener información sobre las características más recientes.

Antes de analizar el código con CodeQL, debes crear una base de datos de CodeQL que contenga todos los datos necesarios para ejecutar consultas en el código. También puedes crear bases de datos de CodeQL por tu cuenta mediante la CodeQL CLI.

El análisis de CodeQL se basa en la extracción de datos relacionales del código y su uso para crear una base de datos de CodeQL. Las bases de datos de CodeQL contienen toda la información importante sobre un código base, que se puede analizar ejecutando consultas de CodeQL en él.

Antes de generar una base de datos de CodeQL, debes hacer lo siguiente:

  1. Instalar y configurar la CodeQL CLI. Para obtener más información, vea «Configuración de la CLI de CodeQL».
  2. Extraiga del repositorio el código que quiera analizar:
    • En el caso de una rama, extraiga del repositorio el inicio de la rama que quiera analizar.
    • Para una solicitud de incorporación de cambios, compruebe la confirmación del encabezado de la solicitud o una confirmación de combinación generada por GitHub de esa solicitud.
  3. Configure el entorno para el código base y asegúrese de que las dependencias estén disponibles.
  4. Para obtener los mejores resultados con lenguajes compilados, busque el comando build, si existe, para el código base. Normalmente está disponible en un archivo de configuración en el sistema de CI.

Una vez que el código base esté listo, puedes ejecutar codeql database create para crear la base de datos. Para obtener más información, consulta "Creación de bases de datos para lenguajes no compilados" y "Creación de bases de datos para lenguajes compilados".

En ejecución codeql database create

Las bases de datos de CodeQL se crean ejecutando el comando siguiente desde la raíz de restauración del proyecto:

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

Debe especificar:

  • <database>: una ruta de acceso a la base de datos nueva que se va a crear. Este directorio se creará al ejecutar el comando; no se puede especificar un directorio existente.

  • --language: el identificador del lenguaje para el que se va a crear una base de datos. Cuando se usa con --db-cluster, la opción acepta una lista separada por comas o se puede especificar más de una vez. CodeQL admite la creación de bases de datos para los lenguajes siguientes:

    LenguajeIdentificadorIdentificadores alternativos opcionales (si los hay)
    C/C++c-cppc o cpp
    C#csharp
    Gogo
    Java/Kotlinjava-kotlinjava o kotlin
    JavaScript/TypeScriptjavascript-typescriptjavascript o typescript
    Pythonpython
    Rubyruby
    Swiftswift

    Nota: Si especifica uno de los identificadores alternativos, esto equivale a usar el identificador de idioma estándar. Por ejemplo, especificar javascript en lugar de javascript-typescript no excluirá el análisis del código TypeScript. Puede hacerlo en un flujo de trabajo de configuración avanzada con la opción --paths-ignore. Para obtener más información, vea «Personalización de la configuración avanzada para el examen de código».

Si el código base tiene un comando de compilación o un script que invoca el proceso de compilación, se recomienda especificarlo también:

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

Opciones para crear bases de datos

Puedes especificar opciones adicionales en función de la ubicación del archivo de origen, si se tiene que compilar el código y si quieres crear bases de datos de CodeQL para más de un lenguaje.

OpciónObligatorioUso
<database>Especifica el nombre y ubicación de un directorio a crear para la base de datos de CodeQL. Se producirá un error en el comando si intenta sobrescribir un directorio existente. Si también especifica --db-cluster, este es el directorio primario y se crea un subdirectorio para cada lenguaje analizado.
--languageEspecifique el identificador del idioma para el que se va a crear una base de datos; una de: c-cpp, csharp, go, java-kotlin, javascript-typescript, python, ruby y swift. Cuando se usa con --db-cluster, la opción acepta una lista separada por comas o se puede especificar más de una vez.
--commandOpción recomendada. Se usa para especificar el comando de compilación o el script que invoca el proceso de compilación para el código base. Los comandos se ejecutan desde la carpeta actual o, donde se define, desde --source-root. No es necesario para el análisis de Python y JavaScript o TypeScript.
--db-clusterSe usa en códigos base de varios lenguajes para generar una base de datos para cada lenguaje especificado por --language.
--no-run-unnecessary-buildsOpción recomendada. Utilízalo para suprimir el comando de compilación para los lenguajes en donde el CodeQL CLI no necesite monitorear la compilación (por ejemplo, Python y JavaScript/TypeScript).
--source-rootSe usa si ejecuta la CLI fuera de la raíz de extracción del repositorio. De manera predeterminada, el comando database create supone que el directorio actual es el directorio raíz de los archivos de origen. Use esta opción para especificar otra ubicación.
--codescanning-configAvanzado. Úsalo si tienes un archivo de configuración que especifica cómo crear las bases de datos CodeQL y qué consultas ejecutar en pasos posteriores. Para obtener más información, vea «Personalización de la configuración avanzada para el examen de código» y «database create».

Puedes especificar opciones de extractor para personalizar el comportamiento de los extractores que crean bases de datos de CodeQL. Para obtener más información, vea «Opciones de extractor».

Para obtener información detallada sobre todas las opciones que se pueden usar al crear bases de datos, consulta "database create".

Ejemplo de un solo lenguaje

En este ejemplo se crea una única base de datos de CodeQL para el repositorio extraído en /checkouts/example-repo. Usa el extractor de JavaScript para crear una representación jerárquica del código JavaScript y TypeScript en el repositorio. La base de datos resultante se almacena en /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.

Ejemplo de lenguaje múltiple

En este ejemplo se crean dos base de datos de CodeQL para el repositorio extraído en /checkouts/example-repo-multi. Usa:

  • --db-cluster para solicitar el análisis de más de un lenguaje.
  • --language para especificar los lenguajes para los que se crearán las bases de datos.
  • --command para indicarle a la herramienta el comando de compilación para el código base, en este caso make.
  • --no-run-unnecessary-builds para indicarle a la herramienta que omita el comando de compilación para los lenguajes en los que no es necesario (como Python).

Las bases de datos resultantes se almacenan en los subdirectorios python y cpp de /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.
$

Progreso y resultados

Los errores se notifican si hay algún problema con las opciones especificadas. En el caso de los lenguajes interpretados y al especificar --build-mode none para Java, el progreso de la extracción se muestra en la consola. Para cada archivo de origen, la consola muestra si la extracción se realizó correctamente o si se produjo un error. En el caso de los lenguajes compilados, la consola mostrará la salida del sistema de compilación.

Cuando la base de datos se crea correctamente, encontrarás un directorio nuevo en la ruta de acceso especificada en el comando. Si usaste la opción --db-cluster para crear más de una base de datos, se crea un subdirectorio para cada lenguaje. Cada directorio de base de datos de CodeQL contiene varios subdirectorios, incluidos los datos relacionales (necesarios para el análisis) y un archivo de origen (una copia de los archivos de origen realizada en el momento en que se creó la base de datos), que se usa para mostrar los resultados del análisis.

Creación de bases de datos para lenguajes no compilados

La CodeQL CLI incluye extractores a fin de crear bases de datos para lenguajes no compilados, en concreto JavaScript (y TypeScript), Python y Ruby. Estos extractores se invocan automáticamente al especificar JavaScript, Python o Ruby como la opción --language al ejecutar database create. Al crear bases de datos para estos lenguajes, debes asegurarte de que todas las dependencias adicionales están disponibles.

Nota: Al ejecutar database create para JavaScript, TypeScript, Python y Ruby, no debes especificar una opción --command. De lo contrario, invalidará la invocación de extractor normal, que creará una base de datos vacía. Si creas bases de datos para varios lenguajes y uno de ellos es un lenguaje compilado, usa la opción --no-run-unnecessary-builds a fin de omitir el comando de los lenguajes que no sea necesario compilar.

JavaScript y TypeScript

La creación de bases de datos para JavaScript no requiere dependencias adicionales, pero si el proyecto incluye archivos TypeScript, debes instalar Node.js 14 o una versión posterior que debe estar disponible en PATH como node. En la línea de comandos, puedes especificar --language=javascript-typescript para extraer archivos JavaScript y TypeScript:

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

Aquí hemos especificado una ruta de acceso --source-root, que es la ubicación donde se ejecuta la creación de la base de datos, pero no es necesariamente la raíz de restauración del código base.

De manera predeterminada, los archivos de los directorios node_modules y bower_components no se extraen.

Python

Al crear bases de datos para Python, debes asegurarte de lo siguiente:

  • Tener Python 3 instalado y disponible para el extractor de CodeQL.
  • Tener instalada la versión de Python que usa el código.

En la línea de comandos, debes especificar --language=python. Por ejemplo:

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

Esto ejecuta el subcomando database create desde la raíz de restauración del código, lo que genera una base de datos de Python nueva en <output-folder>/python-database.

Ruby

La creación de bases de datos para Ruby no requiere dependencias adicionales. En la línea de comandos, debes especificar --language=ruby. Por ejemplo:

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

Aquí hemos especificado una ruta de acceso --source-root, que es la ubicación donde se ejecuta la creación de la base de datos, pero no es necesariamente la raíz de restauración del código base.

Creación de bases de datos para lenguajes compilados

En el caso de los lenguajes compilados, CodeQL debe invocar el sistema de compilación necesario a fin de generar una base de datos, por lo que el método de compilación debe estar disponible para la CLI. Este enfoque crea bases de datos que incluyen código generado. CodeQL tiene dos métodos para compilar código base:

Detección automática del sistema de compilación

El CodeQL CLI incluye los constructores automáticos para el código C/C++, C#, Go, Java y Swift. Los generadores automáticos de CodeQL permiten compilar proyectos para lenguajes compilados sin especificar ningún comando de compilación. Cuando se invoca un generador automático, CodeQL examina el origen en busca de evidencias de un sistema de compilación e intenta ejecutar un conjunto óptimo de comandos necesarios para extraer una base de datos. Para obtener más información, vea «Análisis de código de CodeQL para lenguajes compilados».

Un generador automático se invoca automáticamente cuando se ejecuta codeql database create para un lenguaje compilado si no incluye una opción --command . Por ejemplo, para un código base en C/C++, puede ejecutar simplemente:

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

Si un código base usa un sistema de compilación estándar, basarse en un generador automático suele ser la manera más sencilla de crear una base de datos. En el caso de los orígenes que requieren pasos de compilación que no son estándar, es posible que tengas que definir de forma explícita cada paso en la línea de comandos.

Notas:

  • Si vas a compilar una base de datos de Go, instala la cadena de herramientas de Go (versión 1.11 o una posterior) y, si hay dependencias, el administrador de dependencias adecuado (por ejemplo, dep).
  • El generador automático de Go intenta detectar automáticamente el código escrito en Go en un repositorio y solo ejecuta scripts de compilación en un intento de capturar dependencias. Para forzar que CodeQL limite la extracción a los archivos que ha compilado el script de compilación, establece la variable de entorno CODEQL_EXTRACTOR_GO_BUILD_TRACING=on o usa la opción --command a fin de especificar un comando de compilación.

Especificación de comandos de compilación

Los ejemplos siguientes están pensados para darte una idea de algunos de los comandos de compilación que puedes especificar para los lenguajes compilados.

Nota: La opción --command acepta un único argumento; si necesitas usar más de un comando, especifica --command varias veces. Si necesitas pasar subcomandos y opciones, el argumento entero debe ir entre comillas para que se interprete correctamente.

  • Proyecto de C/C++ compilado con make:

    codeql database create cpp-database --language=c-cpp --command=make
    
  • Proyecto de C# compilado con dotnet build:

    Es recomendable agregar /t:rebuild para asegurarse de que se compilará todo el código, o bien realizar un elemento dotnet clean anterior (el código que no esté compilado no se incluirá en la base de datos de CodeQL):

    codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild'
    
  • Ve al proyecto compilado con la variable de entorno CODEQL_EXTRACTOR_GO_BUILD_TRACING=on:

    CODEQL_EXTRACTOR_GO_BUILD_TRACING=on codeql database create go-database --language=go
    
  • Ve al proyecto compilado con un script de compilación personalizado:

    codeql database create go-database --language=go --command='./scripts/build.sh'
    
  • Proyecto de Java compilado con 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'
    
  • Proyecto de Java compilado con Maven:

    codeql database create java-database --language=java-kotlin --command='mvn clean install'
    
  • Proyecto de Java compilado con Ant:

    codeql database create java-database --language=java-kotlin --command='ant -f build.xml'
    
  • Proyecto de Swift compilado con un proyecto o área de trabajo de Xcode. De forma predeterminada, se compila el destino de Swift más grande:

    Es una buena idea asegurarse de que el proyecto está en un estado limpio y de que no hay artefactos de compilación disponibles.

    xcodebuild clean -all
    codeql database create -l swift swift-database
    
  • Proyecto de Swift compilado con swift build:

    codeql database create -l swift -c "swift build" swift-database
    
  • Proyecto de Swift compilado con xcodebuild:

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

    Puedes pasar las opciones archive y test a xcodebuild. Sin embargo, se recomienda el comando estándar xcodebuild, ya que es el más rápido y es todo lo que CodeQL necesita para un examen correcto.

  • Proyecto de Swift compilado con un script de compilación personalizado:

    codeql database create -l swift -c "./scripts/build.sh" swift-database
    
  • Proyecto compilado con 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
    
  • Proyecto compilado con un script de compilación personalizado:

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

Este comando ejecuta un script personalizado que contiene todos los comandos necesarios para compilar el proyecto.

Uso del seguimiento indirecto de la compilación

Si los generadores automáticos de la CodeQL CLI para lenguajes compilados no funcionan con el flujo de trabajo de CI y no puedes encapsular invocaciones de comandos de compilación con codeql database trace-command, puedes usar el seguimiento indirecto de la compilación para crear una base de datos de CodeQL. A fin de usar el seguimiento indirecto de la compilación, el sistema de CI debe poder establecer variables de entorno personalizadas para cada acción de compilación.

Para crear una base de datos de CodeQL con seguimiento indirecto de la compilación, ejecuta el comando siguiente desde la raíz de desprotección del proyecto:

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

Debe especificar:

  • <database>: una ruta de acceso a la base de datos nueva que se va a crear. Este directorio se creará al ejecutar el comando; no se puede especificar un directorio existente.
  • --begin-tracing: crea scripts que se pueden usar para configurar un entorno en el que se realizará un seguimiento de los comandos de compilación.

Puedes especificar otras opciones para el comando codeql database init con normalidad.

Nota: Si la compilación se ejecuta en Windows, debes establecer --trace-process-level <number> o --trace-process-name <parent process name> a fin de que la opción apunte a un proceso de CI primario que observará todos los pasos de compilación para el código que se va a analizar.

El comando codeql database init dará generará un mensaje:

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

El comando codeql database init crea <database>/temp/tracingEnvironment con archivos que contienen variables de entorno y valores que permitirán que CodeQL realice un seguimiento de una secuencia de pasos de compilación. Estos archivos se denominan start-tracing.{json,sh,bat,ps1}. Usa uno de estos archivos con el mecanismo del sistema de CI a fin de establecer variables de entorno para pasos futuros. Puede:

  • Leer el archivo JSON, procesarlo e imprimir variables de entorno en el formato que espera el sistema de CI. Por ejemplo, Azure DevOps espera echo "##vso[task.setvariable variable=NAME]VALUE".
  • O bien, si el sistema de CI conserva el entorno, obtén el script de start-tracing adecuado para establecer las variables de CodeQL en el entorno de shell del sistema de CI.

Compila el código; opcionalmente, anula las variables de entorno mediante un script de end-tracing.{json,sh,bat,ps1} del directorio donde se almacenan los scripts de start-tracing; y, después, ejecuta el comando codeql database finalize <database>.

Una vez que hayas creado una base de datos de CodeQL mediante el seguimiento indirecto de la compilación, puedes trabajar con ella como con cualquier otra base de datos de CodeQL. Por ejemplo, analiza la base de datos y carga los resultados en GitHub si usas el examen de código.

Ejemplo de creación de una base de datos de CodeQL mediante el seguimiento indirecto de la compilación

Nota: Si usas canalizaciones de Azure DevOps, la manera más sencilla de crear una base de datos de CodeQL es usar GitHub Advanced Security for Azure DevOps. Para obtener documentación, consulta Configuración de GitHub Advanced Security for Azure DevOps en Microsoft Learn.

En el ejemplo siguiente se muestra cómo puedes usar el seguimiento indirecto de la compilación en una canalización de Azure DevOps para crear una base de datos de 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` ...

Pasos siguientes