Skip to main content

Como criar conjuntos de consultas do CodeQL

Você pode criar conjuntos de consultas para consultas usadas com frequência nas análises do CodeQL.

Quem pode usar esse recurso?

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

Sobre a criação de conjuntos de consultas do CodeQL

Os conjuntos de consultas do CodeQL oferecem uma forma de selecionar consultas, com base no nome de arquivo, no local no disco, em um pacote CodeQL ou em propriedades de metadados. Crie conjuntos com as consultas que você deseja usar mais nas análises do CodeQL.

Os conjuntos de consultas permitem que você passe várias consultas ao CodeQL sem precisar especificar o caminho para cada arquivo de consulta individualmente. As definições do pacote de consultas são armazenadas em arquivos YAML com a extensão .qls. Uma definição de pacote é uma sequência de instruções, em que cada instrução é um mapeamento YAML com (geralmente) uma única chave. As instruções são executadas na ordem em que aparecem na definição do pacote de consultas. Depois que todas as instruções na definição do conjunto tiverem sido executadas, o resultado será um pacote de consultas selecionadas.

Note

As consultas personalizadas que você deseja adicionar a um pacote de consultas precisam estar em um "pacote do CodeQL" e conter os metadados de consulta corretos. Para obter mais informações, confira "Como usar consultas personalizadas com a CodeQL CLI".

Como localizar as consultas a serem adicionadas a um conjunto de consultas

Ao criar um conjunto de consultas, primeiro você precisa especificar os locais das consultas que deseja selecionar. Você pode definir o local de uma ou mais consultas usando:

  • Uma instrução query: instrui o CodeQL a procurar um ou mais arquivos especificados .ql:

    - query: <path-to-query>
    

    O argumento precisa ser um ou mais caminhos de arquivo, em relação ao pacote do CodeQL que contém a definição do conjunto.

  • Uma instrução queries: solicita que o CodeQL verifique recursivamente um diretório em busca de arquivos .ql:

    - queries: <path-to-subdirectory>
    

    O caminho do diretório precisa ser relativo à raiz do pacote do CodeQL que contém o arquivo de definição do conjunto. Para localizar as consultas relativas a um pacote do CodeQL diferente, adicione um campo from:

    - queries: <path-to-subdirectory>
      from: <ql-pack-name>
      version: ^x.y.z
    

    O campo version é opcional e especifica um intervalo de versões compatíveis deste pacote do CodeQL. Se você não especificar uma versão, será usada a mais recente do pacote.

  • Uma instrução qlpack: solicita que o CodeQL resolva consultas no conjunto padrão do pacote do CodeQL nomeado:

    - qlpack: <qlpack-name>
      version: ^x.y.z
    

    O conjunto padrão de um pacote de consultas inclui um conjunto recomendado de consultas dentro desse pacote de consultas. Nem todos os pacotes de consultas têm um conjunto padrão. Se o pacote de consultas especificado não definir um conjunto padrão, a instrução qlpack será resolvida para todas as consultas dentro do pacote.

    O campo version é opcional e especifica um intervalo de versões compatíveis deste pacote do CodeQL. Se você não especificar uma versão, será usada a mais recente do pacote.

Note

Quando os nomes de caminho aparecem nas definições do conjunto de consultas, eles sempre precisam conter uma barra / como separador de diretório. Isso garante que as definições do conjunto de consultas funcionem em todos os sistemas operacionais.

Você precisa adicionar pelo menos uma instrução query, queries ou qlpack à definição do conjunto. Caso contrário, nenhuma consulta será selecionada. Se o conjunto não contiver mais instruções, todas as consultas encontradas na lista de arquivos, no diretório especificado ou no pacote do CodeQL nomeado serão selecionadas. Se houver mais instruções de filtragem, somente as consultas que correspondem às restrições impostas por essas instruções serão selecionadas.

Como filtrar as consultas em um conjunto de consultas

Depois de definir o grupo inicial de consultas a serem adicionadas ao conjunto especificando as instruções query, queriesou qlpack, você pode adicionar as instruções include e exclude. Estas instruções definem os critérios de seleção com base em propriedades específicas:

  • Quando você executa uma instrução include em um conjunto de consultas, todas as consultas que correspondem às condições são mantidas na seleção e as que não correspondem são removidas.
  • Quando você executa uma instrução exclude em um conjunto de consultas, todas as consultas que correspondem às condições são removidas da seleção e as que não correspondem são mantidas.

A ordem das instruções de filtro é importante. A primeira instrução de filtro exibida após as instruções de localização determina se as consultas são incluídas ou excluídas por padrão. Se o primeiro filtro for um include, as consultas localizadas inicialmente só farão parte do conjunto se corresponderem a um filtro explícito include. Se o primeiro filtro for um exclude, as consultas localizadas inicialmente farão parte do conjunto, a menos que sejam excluídas explicitamente.

As instruções subsequentes são executadas em ordem e as instruções que aparecem posteriormente no arquivo têm precedência sobre as instruções anteriores. Portanto, as instruções include poderão ser substituídas por instruções exclude posteriores que correspondam à mesma consulta. Da mesma forma, excludes podem ser substituídas por uma include posterior.

Para as duas instruções, o argumento é um bloco de restrição, ou seja, um mapa YAML que representa as restrições. Cada restrição é uma entrada de mapa, em que a chave normalmente é uma propriedade de metadados de consulta. O valor pode ser:

  • Uma só cadeia de caracteres.
  • Uma expressão regular entre /.
  • Uma lista que contém cadeias de caracteres e/ou expressões regulares.

Para corresponder a uma restrição, um valor de metadados precisa corresponder a uma das cadeias de caracteres ou expressões regulares. Quando há mais de uma chave de metadados, cada chave precisa ser correspondida. As chaves de metadados padrão disponíveis para correspondência são: description, id, kind, name, tags, precision e problem.severity. Para obter mais informações sobre as propriedades de metadados de consulta, confira "Metadados para consultas do CodeQL".

Além das marcas de metadados, as chaves no bloco de restrição também podem ser:

  • query filename: corresponde ao último componente de caminho do nome do arquivo de consulta.
  • query path: corresponde ao caminho para o arquivo de consulta em relação ao pacote do CodeQL que ele contém.
  • tags contain: uma das cadeias de caracteres de correspondência fornecidas precisa corresponder a um dos componentes separados por espaço do valor da propriedade de metadados @tags.
  • tags contain all: cada uma das cadeias de caracteres de correspondência fornecidas precisa corresponder a um dos componentes da propriedade de metadados @tags.

Exemplos de filtragem das consultas que serão executadas

Um caso de uso comum é criar um conjunto de consultas que execute todas as consultas em um pacote do CodeQL, exceto algumas consultas específicas que o usuário não deseja executar. Em geral, recomendamos a filtragem na id da consulta, que é um identificador exclusivo e estável de cada consulta. As três definições de conjunto de consultas a seguir são semanticamente idênticas e filtram pela consulta id:

Esse filtro corresponde a todas as consultas no conjunto padrão de codeql/cpp-queries, exceto às duas consultas com os identificadores excluídos:

- qlpack: codeql/cpp-queries
- exclude:
    id:
      - cpp/cleartext-transmission
      - cpp/cleartext-storage-file

Neste exemplo, uma instrução exclude separada é usada para cada consulta:

- qlpack: codeql/cpp-queries
- exclude:
    id: cpp/cleartext-transmission
- exclude:
    id: cpp/cleartext-storage-file

Neste exemplo, uma expressão regular exclui as mesmas duas consultas. Ela também excluiria todas as consultas futuras adicionadas ao conjunto com identificadores que começam com: cpp/cleartext-:

- qlpack: codeql/cpp-queries
- exclude:
    id:
      - /^cpp\/cleartext-.*/

Para definir um conjunto que selecione todas as consultas no conjunto padrão do pacote codeql/cpp-queries do CodeQL e depois refine-as para incluir apenas consultas de segurança, use:

- qlpack: codeql/cpp-queries
- include:
    tags contain: security

Para definir um conjunto que seleciona todas as consultas com @kind problem e @precision high no diretório my-custom-queries, use:

- queries: my-custom-queries
- include:
    kind: problem
    precision: very-high

Observe que a definição do conjunto de consultas a seguir se comporta de maneira diferente da definição acima. Essa definição seleciona as consultas que são @kind problem ou @precision very-high:

- queries: my-custom-queries
- include:
    kind: problem
- include:
    precision: very-high

Para criar um conjunto que selecione todas as consultas com @kind problem no diretório my-custom-queries, exceto aquelas com @problem.severity recommendation, use:

- queries: my-custom-queries
- include:
    kind: problem
- exclude:
    problem.severity: recommendation

Para criar um conjunto que selecione todas as consultas com @tag security e @precision high ou very-high no pacote codeql/cpp-queries do CodeQL, use:

- queries: .
  from: codeql/cpp-queries
- include:
    tags contain: security
    precision:
    - high
    - very-high

Note

Você pode usar o comando codeql resolve queries /path/to/suite.qls para ver quais consultas são selecionadas por uma definição de conjunto de consultas. Para obter mais informações, confira "resolve queries".

Como reutilizar definições de conjunto de consultas existentes

As definições de conjunto de consultas existentes podem ser reutilizadas especificando:

  • Uma instrução import: adiciona as consultas selecionadas por um arquivo .qls já definido ao conjunto atual:

    - import: <path-to-query-suite>
    

    O caminho para o conjunto importado precisa ser relativo ao pacote do CodeQL que contém a definição do conjunto atual. Se o conjunto de consultas importado estiver em um pacote do QL diferente, use:

    - import: <path-to-query-suite>
      from: <ql-pack>
      version: ^x.y.z
    

    O campo version é opcional e especifica um intervalo de versões compatíveis deste pacote do CodeQL. Se você não especificar uma versão, será usada a mais recente do pacote.

    As consultas adicionadas usando uma instrução import podem ser filtradas usando as instruções subsequentes exclude.

  • Uma instrução apply: adiciona todas as instruções de um arquivo .qls já definido ao conjunto atual. As instruções no arquivo .qls aplicado são executadas como se aparecessem no lugar de apply. As instruções include e exclude do conjunto aplicado também atuam em consultas adicionadas por instruções anteriores:

    - apply: <path-to-query-suite>
    

    A instrução apply também pode ser usada para aplicar um conjunto de condições reutilizáveis, salvas em um arquivo .yml, a várias definições de consulta. Veja os exemplos abaixo para obter mais informações.

Exemplos de reutilização

Para usar as mesmas condições em várias definições de conjunto de consultas, crie um arquivo .yml separado contendo as instruções. Por exemplo, salve o seguinte em um arquivo chamado reusable-instructions.yml:

- include:
    kind:
    - problem
    - path-problem
    tags contain: security
    precision:
    - high
    - very-high

Adicione reusable-instructions.yml ao mesmo pacote do CodeQL que o conjunto de consultas atual. Depois, em um ou mais conjuntos de consultas, use a instrução apply para aplicar as instruções reutilizáveis ao conjunto atual. Por exemplo:

- queries: queries/cpp/custom
- apply: reusable-instructions.yml

Isso filtrará as consultas em queries/cpp/custom para incluir apenas aquelas que correspondem às condições reutilizáveis.

Você também pode criar uma definição de conjunto usando reusable-instructions.yml em consultas em um pacote do CodeQL diferente. Se o arquivo .qls estiver no mesmo pacote do CodeQL que as consultas, você poderá adicionar um campo from logo após a instrução apply:

# load queries from the default suite of my-org/my-other-custom-queries
- qlpack: my-org/my-other-custom-queries

# apply the reusable instructions from the my-org/my-custom-instructions CodeQL pack
- apply: reusable-instructions.yml
  from: my-org/my-custom-instructions
  version: ^1.2.3 # optional

Um caso de uso comum de uma instrução import é aplicar um filtro adicional a consultas de outro conjunto de consultas. Por exemplo, esse conjunto filtrará ainda mais o conjunto cpp-security-and-quality e excluirá as consultas de precisão low e medium:

- import: codeql-suites/cpp-security-and-quality.qls
  from: codeql/cpp-queries
- exclude:
    precision:
      - low
      - medium

Se você quiser executar include nas consultas importadas de outro pacote, a sintaxe será um pouco diferente:

- import: codeql-suites/cpp-security-and-quality.qls
  from: codeql/cpp-queries
- exclude: {}
- include:
    precision:
      - very-high
      - high

Observe a instrução vazia exclude. Isso é necessário para garantir que a próxima instrução include consiga filtrar as consultas do conjunto importado.

Nomeando um conjunto de consultas

Você pode dar um nome para o conjunto de consultas especificando uma instrução description:

- description: <name-of-query-suite>

Como salvar um conjunto de consultas

Salve o conjunto de consultas em um arquivo com uma extensão .qls e adicione-o a um pacote do CodeQL. Para obter mais informações, confira "Como personalizar a análise com pacotes CodeQL".

Usando conjuntos de consultas com CodeQL

Você pode especificar conjuntos de consultas na linha de comando para qualquer comando que aceite arquivos .qls. Por exemplo, você pode compilar as consultas selecionadas por uma definição de conjunto usando query compile ou usar as consultas em uma análise usando database analyze. Para obter mais informações sobre como analisar bancos de dados do CodeQL, confira "Como analisar o código com as consultas CodeQL".

Leitura adicional