静的解析ツールとreviewdogを組み合わせて、レビューを自動化する
はじめに
AWS をはじめとするクラウドや Kubernetes に触れていると、IaC を実践するために Terraform や Helm に触れる機会が多くなります。
今回は、静的解析ツールと reviewdog を組み合わせたレビューの自動化について提案したいと思います。 https://github.com/reviewdog/reviewdog
目標
以下の手順で、自動レビューの仕組みの実現を目的とします。
- feature ブランチにコードをコミットする
- CI で静的解析
- 解析結果を reviewdog でコメントしてもらう
静的解析ツールの紹介
使用する静的解析ツールは以下の3つです
- Trivy
- Kics
- Checkov
詳しい使い方などは以下のブログで紹介しました。 https://blog.takenoko.dev/blog/2023/08/static-analysis-iac/
reviewdog
reviewdog は入力データに Reviewdog Diagnostic Format
(以下 rdjson) というフォーマットをサポートしています。
reviewdog supports Reviewdog Diagnostic Format (RDFormat) as a generic diagnostic format
そのフォーマットは以下の通りです。
静的解析ツールと reviewdog の連携
以前のブログで静的解析ツールについて紹介しました。これらのツールは、解析結果を json 形式で出力できます。
また、reviewdog は rdjson 形式の入力を受け取ることができます。
このため、解析ツールの出力結果を jq コマンドを用いて整形し、rdjson 形式に変換することで、これらのツールを組み合わせることができます。
ここでは、解析ツールの出力を jq で rdjson へ変換する方法を紹介します。
解析に使用する Helm Chart を作成します。
jqのオプション
静的解析ツールとreviewdogとの連携に使用する jq のオプションを紹介します。
使用するオプションは --slurpfile
と -f, --from-file
です。
--slurpfile
--slurpfile <変数名> <ファイル名>
という形で使用します。
以下のサンプルでは、data.json
ファイルにある json データを jq 内の val
変数にバインドし、jq のフィルターに渡しています。
-f, --from-file
-f <ファイル名> / --from-file <ファイル名>
という形で使用します。
ファイルにフィルターを書くことでテンプレートのような使い方もできます。
先ほどの --argjson
と組み合わせると複雑なフィルターも 1 行でかけます。
解析結果のフォーマットと rdjson への変換
Trivy
変換に使用するデータ
Trivy での解析結果を results.json
にリダイレクトします。
results.json
は以下のようになります。
results.json
jq で使用するフィルターは以下の通りです。
jq を使って、Trivy の解析結果 (results.json) を rdjson に変換します。
jq -n --slurpfile trivy results.json -f trivy.jq
これで Trivy の解析結果を rdjson に変換できました。
後ほど、この変換の流れを CI で実行します。
Kics
変換に使用するデータ
Kics での解析結果を results.json
に書き出します。
※ デフォルトのファイル名は results
です。 --output-name
オプションで名前を変更できます。
jq で使用するフィルターは以下の通りです。
jq を使って、Kics の解析結果 (results.json) を rdjson に変換します。
jq -n --slurpfile kics results.json -f kics.jq
これで Kics の解析結果を rdjson に変換できました。
後ほど、この変換の流れを CI で実行します。
Checkov
変換に使用するデータ
Checkov での解析結果を results.json
にリダイレクトします。
jq で使用するフィルターは以下の通りです。
jq を使って、Checkov の解析結果 (results.json) を rdjson に変換します。
jq -n --slurpfile checkov results.json -f checkov.jq
これで Checkov の解析結果を rdjson に変換できました。
後ほど、この変換の流れを CI で実行します。
GitLab CI で実行する
API トークンを作成する
reviewdog が GitLab と連携するためには、REVIEWDOG_GITLAB_API_TOKEN
変数を定義する必要があります。
Store REVIEWDOG_GITLAB_API_TOKEN in GitLab CI variable. https://github.com/reviewdog/reviewdog#gitlab-ci
まずはじめに、画面左のナビゲーションから Settings > Access Tokens > Add new token
でトークンを新規追加します。
project access token の設定をします。
トークンの名前は任意なのでわかりやすい名前をつけてください。スコープは api
のみで十分です。
Create project access token
を作成すると、トークンが表示されるのでコピーしておいてください。
API トークンを設定する
次にトークンを変数に設定します。
画面左のナビゲーションから Settings > CI/CD > Variables > Expand
に行き、 Add variable
ボタンから変数を追加します。
変数名は REVIEWDOG_GITLAB_API_TOKEN
にして、先ほどコピーしたトークンを Value
にペーストしてください。
Add variable
ボタンを押すと設定完了です。
Trivy
解析に使用する Helm Chart を作成します。
Trivy で紹介した jq のフィルターを .gitlab/ci/trivy.jq
に定義します。
.gitlab-ci.yml
の設定は以下の通りです。
以下は CI を実行した結果です。 https://gitlab.com/kntks/helm-reviewdog/-/merge_requests/1
Kics
解析に使用する Helm Chart を作成します。
Kics で紹介した jq のフィルターを .gitlab/ci/kics.jq
に定義します。
.gitlab-ci.yml
の設定は以下の通りです。
以下は CI を実行した結果です。 https://gitlab.com/kntks/helm-reviewdog/-/merge_requests/2
Checkov
解析に使用する Helm Chart を作成します。
Checkov で紹介した jq のフィルターを .gitlab/ci/checkov.jq
に定義します。
.gitlab-ci.yml
の設定は以下の通りです。
以下は CI を実行した結果です。 https://gitlab.com/kntks/helm-reviewdog/-/merge_requests/3
GitHub Actions で実行する
GitHub Appsを作成する
GitHub Actions のワークフロー内で reviewdog がプルリクエストにコメントを書き込むためにはトークンが必要です。
今回は Personal Access Token ではなく、GitHub Apps を使用します。
以前のブログに GitHub Apps の作り方を書いたので、作成の流れは ↓ のブログに任せます。
https://blog.takenoko.dev/blog/2023/04/github-rest-api/#github-apps%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B
プライベートキーと App のインストールまで完了してください。
GitHub Apps に必要な権限は以下の通りです。 Repository permissions
name | permission |
---|---|
Contents | Read-only |
Metadata | Read-only |
Pull requests | Read and write |
info: reviewdog は [`GET /repos/{owner}/{repo}/pulls/{pull_number}`](https://docs.github.com/ja/rest/pulls/pulls#get-a-pull-request) を実行している。そのため permission に `Contents` が必要。 ![github-repository-permissions-for-pull-requests](/2023/08/static-analysis-with-reviewdog/github-repository-permissions-for-pull-requests.webp) [Repository permissions for "Pull requests"](https://docs.github.com/ja/rest/overview/permissions-required-for-github-apps?apiVersion=2022-11-28#repository-permissions-for-pull-requests)
シークレットを設定する
作成した App の ID とダウンロードしたプライベートキーをシークレットとして設定します。
Secrets
タブであることを確認したら、New repository secret
ボタンを押してシークレットを作成してください。
追加するシークレットは APP_ID
と APP_PRIVATE_KEY
です。
Trivy
GitLab のときとディレクトリ構成は同じです。
Trivy で紹介した jq のフィルターを .github/workflows/jq/trivy.jq
に定義します。
aquasecurity/trivy-action - github.com
以下は CI を実行した結果です。 https://github.com/kntks/helm-reviewdog/pull/1
Kics
kics-github-action は enable_comments
という変数があり、reviewdog を組み合わせなくてもプルリクエストにコメントを残してくれる機能があります。
そのため Kics では、jq と reviewdog を使いません。
GitLab のときとディレクトリ構成は同じです。
Github Actions - docs.kics.io Checkmarx/kics-github-action - github.com
以下は CI を実行した結果です。 https://github.com/kntks/helm-reviewdog/pull/2
Checkov
GitLab のときとディレクトリ構成は同じです。
Checkov で紹介した jq のフィルターを .github/workflows/jq/checkov.jq
に定義します。
Info: bridgecrewio/checkov-action の with で指定できる [skip_path](https://github.com/bridgecrewio/checkov-action/blob/f2bbdaa530587b5873a295ad92d78d9227aa5178/action.yml#L118-L120) はカンマ区切りで指定できる。 > skip_path: > description: 'Path ... (comma separated)'
- Integrate Checkov with GitHub Actions - checkov.io
- Integrate Checkov with GitLab CI - checkov.io
- bridgecrewio/checkov-action - github.com
以下は CI を実行した結果です。 https://github.com/kntks/helm-reviewdog/pull/3
導入に伴う課題や注意点
Checkov の MR を見ていただくとわかるのですが、ツールによっては大量の指摘を受けます。
誰が、どこまで対応するのかを決めないといけないため、人員やプロジェクトの状況が安定するまで導入するのは難しいです。
とりあえず、静的解析させてみる。でも問題ないと思いますが、具体的に検出したい内容を決め、その内容のみ検出できるようにツールのオプションを変更することをオススメします。
まとめ
静的解析ツールと reviewdog を使用したレビュー自動化の方法を GitLab CI, GitHub Actions それぞれ提案してみました。
静的解析の自動化を導入することでレビューの見逃しを削減することができ、品質の担保できるようになると思います。
設計、実装の参考になれば幸いです。