CircleCI から GitHub Apps 経由で Pull Request にコメントを投げる
こんにちは、iwanaga です。
サムネイルは note creator の方のを借りました。感謝。
今回は、表題の件のソースコードを垂れ流します。
すごい初歩的なことだからか、ユースケースがレアだからか、あまり情報がなかったので。
最終形
最終的な図はこんな感じ。
terraform plan の結果を毎回 CI ページを確認するのは面倒なので、自動で PR にコメントがついてほしい。
CI ユーザ用の GitHub クレデンシャルを用意するのはバッドプラクティスなので、GitHub Apps を使いたい。
GitHub Apps を作る
この辺を参考に作成してください。
Homepage URL は必須なので、リポジトリへのリンクとかにしておきます。
Identifying and authorizing users / Post installation / Webhook は何も設定しなくて OK。作成完了したら、アカウントにインストールする。
App Id を確認し、Private keys を生成してダウンロードしておく。
こんな感じ。
Private Key を CircleCI の環境変数に登録
CircleCI の環境変数は一行しか登録できないので、エンコードして登録し、CI で使用するときにデコードして使います。
# このコマンドで出力された値を GITHUB_APPS_PEM_BASE64 として CircleCI に登録する
$ > cat path/to/private-key.pem | base64
tfnotify config を書く
今回は terraform plan の結果を PR にコメントしたいので tfnotify を使います。
ci: circleci
notifier:
github:
token: $GITHUB_APPS_TOKEN # これ大事
repository:
owner: "iwanaga" # github account name
name: "repository-name" # github repository name
terraform:
plan:
template: |
{{ .Title }} <sup>[CI link!!]( {{ .Link }} )</sup>
{{ .Message }}
{{if .Result}}
<pre><code>{{ .Result }}
</pre></code>
{{end}}
<details><summary>Details (Click me)</summary>
<pre><code>{{ .Body }}
</pre></code></details>
CI の実装
version: 2.1
anchors:
working_directory: &working_directory
working_directory: ~/repo
resource_class: &resource_class
resource_class: medium
jobs:
github-apps-token:
<<: *resource_class
<<: *working_directory
docker:
- image: cimg/base:2021.04
steps:
- run:
name: commands
command: |
header=$(echo -n '{"alg":"RS256","typ":"JWT"}' | base64 -w 0)
now=$(date "+%s")
iat=$((${now} - 60))
exp=$((${now} + (10 * 60)))
github_app_id="000000" # App ID
payload=$(echo -n "{\"iat\":${iat},\"exp\":${exp},\"iss\":${github_app_id}}" | base64 -w 0)
echo $GITHUB_APPS_PEM_BASE64 | base64 --decode > ./githubapps
unsigned_token="${header}.${payload}"
signed_token=$(echo -n $(echo -n "${unsigned_token}" | openssl dgst -binary -sha256 -sign "./githubapps" | base64))
rm ./githubapps
jwt="${unsigned_token}.${signed_token}"
user_name="iwanaga" # githubアカウント
installation_id=$(
curl -s -X GET \
-H "Authorization: Bearer ${jwt}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/app/installations" \
| jq -r ".[] | select(.account.login == \"${user_name}\" and .account.type == \"User\") | .id"
) # account_type が Organization の場合は $user_name は OrganizationName にする
echo $(
curl -s -X POST \
-H "Authorization: Bearer ${jwt}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/app/installations/${installation_id}/access_tokens" \
| jq -r ".token"
) > ./githubapps_token
- persist_to_workspace:
root: .
paths:
- ./githubapps_token
plan:
<<: *resource_class
<<: *working_directory
docker:
- image: docker.mirror.hashicorp.services/hashicorp/terraform:light
steps:
- checkout
- restore_cache:
keys:
- bin-tfnotify
- run:
name: intall tfnotify
command: |
if ! type tfnotify >/dev/null 2>&1; then
apk update && apk add curl
curl -fL -o tfnotify.tar.gz https://github.com/mercari/tfnotify/releases/download/v0.7.5/tfnotify_linux_amd64.tar.gz
tar -C /usr/bin -xzf ./tfnotify.tar.gz
fi
- attach_workspace:
at: /githubapps
- run:
name: terraform init & plan
command: |
terraform init -input=false
terraform plan | GITHUB_APPS_TOKEN=$(cat /githubapps/githubapps_token) tfnotify --config tfnotify.yml plan
- save_cache:
key: bin-tfnotify
paths:
- /usr/bin/tfnotify
workflows:
test_build_deploy:
jobs:
- github-apps-token
- plan:
requires:
- github-apps-token
時限トークンの生成し、ファイルに保持
# これ以前のコードは時限トークンリクエストのための jwt を作成するためのコード、コメント部分以外はそのまま使えるはず
# 他 Job で使いたいのでファイルに出力して、persist_to_workspace します
echo $(
curl -s -X POST \
-H "Authorization: Bearer ${jwt}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/app/installations/${installation_id}/access_tokens" \
| jq -r ".token"
) > ./githubapps_token
生成したトークンを使用して tfnotify に渡す
- attach_workspace:
at: /githubapps # アタッチして
- run:
name: terraform init & plan
command: |
terraform init -input=false
# 環境変数にセットして tfnotify から参照できるようにする
terraform plan | GITHUB_APPS_TOKEN=$(cat /githubapps/githubapps_token) tfnotify --config tfnotify.yml plan
まとめ
githubapps_token というファイルに書き出される時限トークンは、当然 tfnotify に限らず他の用途にも使えます。
CircleCI で GitHub API を使うようなケースがどれほどあるのか不明ですが、ご参考になれば幸いです。
関係ないですが、CircleCI の AWS OIDC 対応はいつになったら実装されるんですかね。遅れまくっているようですが…