CodeQL クエリ スイートの作成について
Note
この記事では、GitHub Enterprise Server 3.15 の初期リリースに含まれている CodeQL CLI 2.18.4 バンドルで使用できる機能について説明します。
サイト管理者が CodeQL CLI のバージョンをより新しいリリースに更新している場合は、この記事の GitHub Enterprise Cloud バージョンで最新の機能に関する情報を参照してください。
CodeQL クエリ スイートでは、ファイル名、ディスク上または CodeQL パック内の場所、またはメタデータ プロパティに基づいてクエリを選択することができます。 CodeQL 分析で頻繁に使用するクエリのクエリ スイートを作成します。
クエリ スイートを使用すると、各クエリ ファイルへのパスを個別に指定せずに、複数のクエリを CodeQL に渡すことができます。 クエリ スイートの定義は、拡張子が .qls
の YAML ファイルに格納されます。 スイートの定義は一連の命令であり、各命令は、(通常は) 1 つのキーを持つ YAML マッピングです。 これらの命令は、クエリ スイートの定義に指定された順序で実行されます。 スイートの定義の命令がすべて実行されると、結果は、選択されたクエリのセットになります。
Note
クエリ スイートに追加するカスタム クエリは CodeQL パック内にあり、正しいクエリ メタデータを含んでいる必要があります。 詳しくは、「CodeQL CLI でのカスタム クエリの使用」を参照してください。
クエリ スイートに追加するクエリの場所指定
クエリ スイートを作成するときは、選びたいクエリの場所を最初に指定する必要があります。 次を使用して、1 つ以上のクエリの場所を定義できます。
-
query
命令: CodeQL に、指定した 1 つ以上の.ql
ファイルを検索するように指示します。- query: <path-to-query>
引数は、スイート定義を含む CodeQL パックを基準にした 1 つ以上のファイル パスである必要があります。
-
queries
命令: CodeQL に、ディレクトリ内の.ql
ファイルを再帰的にスキャンするように指示します。- queries: <path-to-subdirectory>
ディレクトリのパスは、スイート定義ファイルを含む CodeQL パックのルートを基準にする必要があります。 別の CodeQL パックに対するクエリを検索するには、
from
フィールドを追加します。- queries: <path-to-subdirectory> from: <ql-pack-name> version: ^x.y.z
version
フィールドは省略可能であり、この CodeQL パックの互換性のあるバージョンの範囲を指定するものです。 バージョンを指定しない場合は、パックの最新バージョンが使用されます。 -
qlpack
命令: CodeQL に、名前付き CodeQL パックの既定のスイート内のクエリを解決するように指示します。- qlpack: <qlpack-name> version: ^x.y.z
クエリ パックの既定のスイートには、そのクエリ パック内で推奨されるクエリのセットが含まれています。 すべてのクエリ パックに既定のスイートがあるわけではありません。 指定されたクエリ パックで既定のスイートが定義されていない場合、qlpack 命令はパック内のすべてのクエリに解決されます。
version
フィールドは省略可能であり、この CodeQL パックの互換性のあるバージョンの範囲を指定するものです。 バージョンを指定しない場合は、パックの最新バージョンが使用されます。
Note
パス名がクエリ スイート定義に表示される場合は、常にスラッシュ /
をディレクトリ区切りとして指定する必要があります。 これにより、クエリ スイート定義がすべてのオペレーティング システムで確実に機能します。
スイート定義には少なくとも 1 つの query
、queries
、または qlpack
命令を追加する必要があります。それ以外の場合、クエリは選ばれません。 スイートにこれ以上の命令が含まれない場合は、ファイルの一覧、指定されたディレクトリ、または名前付き CodeQL パックで見つかったすべてのクエリが選ばれます。 さらにフィルター処理命令がある場合は、それらの命令によって課される制約に一致するクエリのみが選ばれます。
クエリ スイートでのクエリのフィルター処理
query
、queries
、または qlpack
命令を指定してスイートに追加するクエリの初期セットを定義した後、include
と exclude
の命令を追加できます。 次の命令では、特定のプロパティに基づいて選択条件が定義されます。
- クエリのセットに対して
include
命令を実行すると、条件に一致するすべてのクエリが選択に保持され、一致しないクエリは削除されます。 - クエリのセットに対して
exclude
命令を実行すると、条件に一致するすべてのクエリが選択から削除され、一致しないクエリは保持されます。
フィルター命令の順序は重要です。 命令の場所指定後に表示される最初のフィルター命令によって、既定でクエリを含めるか除外するかが決まります。 最初のフィルターが include
の場合、最初に場所指定されたクエリは、明示的な include
フィルターと一致する場合にのみスイートの一部になります。 最初のフィルターが exclude
の場合、最初に場所指定されたクエリは、明示的に除外されている場合にのみスイートの一部になります。
後続の命令は順番に実行され、ファイル内で後にある命令の方が前にある命令よりも優先されます。 そのため、include
命令は、同じクエリに一致する後の exclude
命令によってオーバーライドできます。 同様に、exclude
は後の include
によってオーバーライドできます。
どちらの命令でも、引数は制約ブロックです。つまり、制約を表す YAML マップです。 各制約はマップ エントリであり、この場合のキーは通常、クエリ メタデータ プロパティです。 次の値が考えられます。
- 1 つの文字列。
/
で囲まれた正規表現。- 文字列、正規表現、またはその両方を含むリスト。
制約に一致させるには、メタデータ値が文字列または正規表現のいずれかに一致する必要があります。 複数のメタデータ キーがある場合は、各キーを一致させる必要があります。
照合に使用できる標準メタデータ キーは description
、id
、kind
、name
、tags
、precision
、および problem.severity
です。
クエリ メタデータ プロパティについて詳しくは、「CodeQL クエリのメタデータ」を参照してください。
メタデータ タグに加えて、制約ブロック内のキーは次の場合もあります。
query filename
: クエリ ファイル名の最後のパス コンポーネントと照合します。query path
: その外側の CodeQL パックを基準にしたクエリ ファイルのパスと照合します。tags contain
: 指定した照合文字列の 1 つが、@tags
メタデータ プロパティの値のスペースで区切られたコンポーネントのいずれかと一致する必要があります。tags contain all
: 指定した各照合文字列は、@tags
メタデータ プロパティのコンポーネントのいずれかと一致する必要があります。
実行するクエリのフィルター処理の例
一般的なユース ケースは、ユーザーが実行したくない特定のクエリを除き、CodeQL パックですべてのクエリを実行するクエリ スイートを作成することです。 一般的には、クエリごとに一意で安定した識別子であるクエリ id
でフィルター処理することをお勧めします。 次の 3 つのクエリ スイート定義は、意味的に同一であり、クエリ id
でフィルター処理されます。
このフィルターは、除外された識別子を持つ 2 つのクエリを除き、codeql/cpp-queries
の既定のスイート内のすべてのクエリと一致します。
- qlpack: codeql/cpp-queries
- exclude:
id:
- cpp/cleartext-transmission
- cpp/cleartext-storage-file
この例では、クエリごとに個別の exclude
命令が使用されます。
- qlpack: codeql/cpp-queries
- exclude:
id: cpp/cleartext-transmission
- exclude:
id: cpp/cleartext-storage-file
この例では、正規表現によって同じ 2 つのクエリが除外されます。 また、cpp/cleartext-
で始まる識別子を持つスイートに追加される今後のクエリも除外されます。
- qlpack: codeql/cpp-queries
- exclude:
id:
- /^cpp\/cleartext-.*/
codeql/cpp-queries
CodeQL パックの既定のスイート内のすべてのクエリを選び、セキュリティ クエリのみを含むように絞り込むスイートを定義するには、次を使用します。
- qlpack: codeql/cpp-queries
- include:
tags contain: security
my-custom-queries
ディレクトリから @kind problem
と @precision high
のすべてのクエリが選ばれるスイートを定義するには、次を使用します。
- queries: my-custom-queries
- include:
kind: problem
precision: very-high
次のクエリ スイート定義は、上記の定義とは異なる動作をします。 この定義は、@kind problem
"または" @precision very-high
であるクエリが選ばれます。__
- queries: my-custom-queries
- include:
kind: problem
- include:
precision: very-high
@problem.severity recommendation
を含むものを除き、my-custom-queries
ディレクトリから @kind problem
のすべてのクエリが選ばれるスイートを作成するには、次を使用します。
- queries: my-custom-queries
- include:
kind: problem
- exclude:
problem.severity: recommendation
codeql/cpp-queries
CodeQL パックから @tag security
と @precision high
または very-high
のすべてのクエリが選ばれるスイートを作成するには、次を使用します。
- queries: .
from: codeql/cpp-queries
- include:
tags contain: security
precision:
- high
- very-high
Note
codeql resolve queries /path/to/suite.qls
コマンドを使用すると、クエリ スイート定義で選ばれているクエリを確認できます。 詳しくは、「クエリを解決する」をご覧ください。
既存のクエリ スイート定義の再利用
既存のクエリ スイート定義は、次を指定することで再利用できます。
-
import
命令: 以前に定義した.qls
ファイルによって選択されたクエリを現在のスイートに追加します。- import: <path-to-query-suite>
インポートされたスイートのパスは、現在のスイート定義を含む CodeQL パックを基準にする必要があります。 インポートされたクエリ スイートが別の QL パックにある場合は、次を使用できます。
- import: <path-to-query-suite> from: <ql-pack> version: ^x.y.z
version
フィールドは省略可能であり、この CodeQL パックの互換性のあるバージョンの範囲を指定するものです。 バージョンを指定しない場合は、パックの最新バージョンが使用されます。import
命令を使用して追加されたクエリは、後続のexclude
命令を使用してフィルター処理できます。 -
apply
命令: 以前に定義した.qls
ファイルのすべての命令を現在のスイートに追加します。 適用された.qls
ファイル内の命令が、apply
の代わりに表示されたかのようにして実行されます。 適用されたスイートのinclude
とexclude
の命令は、以前の命令によって追加されたクエリにも作用します。- apply: <path-to-query-suite>
apply
命令を使用して、.yml
ファイルに保存された一連の再利用可能な条件を複数のクエリ定義に適用することもできます。 詳しくは、下記の例をご覧ください。
再利用性の例
複数のクエリ スイート定義で同じ条件を使用するには、命令を含む別の .yml
ファイルを作成します。 たとえば、reusable-instructions.yml
という名前のファイルに次を保存します。
- include:
kind:
- problem
- path-problem
tags contain: security
precision:
- high
- very-high
現在のクエリ スイートと同じ CodeQL パックに reusable-instructions.yml
を追加します。 次に、1 つ以上のクエリ スイートで、apply
命令を使用して、再利用可能な命令を現在のスイートに適用します。 次に例を示します。
- queries: queries/cpp/custom
- apply: reusable-instructions.yml
これにより、queries/cpp/custom
のクエリがフィルター処理され、再利用可能な条件に一致するもののみが含まれるようになります。
別の CodeQL パックのクエリで reusable-instructions.yml
を使用してスイート定義を作成することもできます。 .qls
ファイルがクエリと同じ CodeQL パックにある場合は、apply
命令の直後に from
フィールドを追加できます。
# 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
import
命令の一般的なユース ケースは、別のクエリ スイートのクエリにさらにフィルターを適用することです。 たとえば、このスイートでは、cpp-security-and-quality
スイートをさらにフィルター処理し、low
と medium
の有効桁数クエリが除外されます。
- import: codeql-suites/cpp-security-and-quality.qls
from: codeql/cpp-queries
- exclude:
precision:
- low
- medium
別のスイートからインポートされたクエリを include
する場合、構文は少し異なります。
- import: codeql-suites/cpp-security-and-quality.qls
from: codeql/cpp-queries
- exclude: {}
- include:
precision:
- very-high
- high
空の exclude
命令に注目してください。 これは、後続の include
命令がインポートされたスイートからのクエリをフィルター処理できるようにするために必要です。
クエリ スイートの名前付け
クエリ スイートの名前を指定するには、description
命令を指定します。
- description: <name-of-query-suite>
クエリ スイートの保存
.qls
拡張子が付いたファイルにクエリ スイートを保存し、CodeQL パックに追加します。 詳しくは、「CodeQL パックを使った分析のカスタマイズ」をご覧ください。
CodeQL でのクエリ スイートの使用
.qls
ファイルを受け入れるコマンドに対して、コマンド ラインでクエリ スイートを指定できます。 たとえば、query compile
を使用してスイート定義によって選ばれたクエリをコンパイルしたり、database analyze
を使用して分析でクエリを使用したりできます。 CodeQL データベースを分析する方法について詳しくは、「CodeQL クエリによるコード分析」を参照してください。