BitriseでGitHub Appのトークンを取得してDangerを動かす
はじめに
NTTレゾナントテクノロジーの西添です。モバイルアプリエンジニアをやっています。
弊社のAndroid/iOSアプリ開発プロジェクトではCI/CDにBitriseを使用しています。最近、CIの一環としてBitriseのworkflowにDangerを導入し、Bitriseで実行したLintやUnit Test等の結果をPull Requestにコメントしようと試みています。要するに、機械に任せられるコードレビューは機械に任せてしまおうという発想です。
ここで問題になるのがDangerがGitHub REST APIにアクセスするために必要なトークンをどうするかです。Dangerのドキュメントにはbot用のGitHubアカウントを作成し、personal access tokenを作成するように記載されています。しかし、bot用のGitHubアカウントを作成するのは管理上もセキュリティ上も好ましくありません。
そこで注目したいのがGitHub Appです。GitHub Appは特定のOrganizationやUserに対してインストールするもので、どのリポジトリにアクセスできるか設定できたり、機能単位で権限を細かく設定できたりします。GitHub Appは必要に応じてinstallation access tokenを発行できます。これを使うとpersonal access tokenと同様にPull RequestにコメントするGitHubのREST APIが実行できます。
installation access tokenは発行から1時間で使用できなくなるため、必要なときに都度発行しなければなりません。発行プロセスは少し面倒で、次の3ステップがあります。
App IDと秘密鍵を使用してJSON Web Token (JWT)を作成する
作成したJWTとInstallation IDを使用してinstallation access tokenを作成するREST APIを実行する
APIレスポンスからtokenフィールドを取得する
このプロセスをよしなにやってくれるIntegrationがBitriseにあれば楽だったのですが、2022年3月時点では残念ながら見当たりませんでした。
ちなみに、GitHub Actionsなら上記のプロセスをやってくれるactionが既にあります。
というわけで、bashスクリプトを書いてBitriseでGitHub Appのinstallation access tokenを発行し、それをDangerで利用できるようにしてみました。以下ではその手順を説明します。
動作確認済みのStack
Android & Docker, on Ubuntu 20.04
Xcode 13.2.x on macOS 11.6 (Big Sur)
手順
1. GitHub Appの作成
まずGitHub Appを作成します。作成方法については以下の公式ドキュメントを参考にしてください。
作成の際にpermissionを選択する欄がありますが、Dangerの場合は以下のpermissionが必要です(他にもあるかもしれません)。
Commit statuses : Read and write
Contents : Read-only
Issues : Read and write
Metadata : Read-only
Pull requests : Read and write
作成できたら、OrganizationにGitHub Appをインストールします。
最後に、次のページの手順に沿って秘密鍵を作成し、App IDとInstallation IDを取得してinstallation access tokenを発行できることを確認します。
2. installation access tokenを発行するステップの追加
BitriseのWorkflow Editorで[Script] ステップを追加し、[Script content]に以下のコードをコピペします。
#!/usr/bin/env bash
echo -e "\n>>> gem install jwt\n"
gem install jwt
echo -e "\n>>> generate a JWT\n"
JWT=$(ruby << EOF
require 'openssl'
require 'jwt' # https://rubygems.org/gems/jwt
# Private key contents
private_key = OpenSSL::PKey::RSA.new(ENV['GITHUB_APP_PEM'])
# Generate the JWT
payload = {
# issued at time, 60 seconds in the past to allow for clock drift
iat: Time.now.to_i - 60,
# JWT expiration time (10 minute maximum)
exp: Time.now.to_i + (10 * 60),
# GitHub App's identifier
iss: ENV['GITHUB_APP_ID']
}
jwt = JWT.encode(payload, private_key, "RS256")
puts jwt
EOF
)
echo -e "\n>>> create an installation access token\n"
TOKEN=$(curl -s -D /dev/stderr -X POST \
-H "Authorization: Bearer ${JWT}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/app/installations/${GITHUB_APP_INSTALLATION_ID}/access_tokens \
| jq -r .token)
envman add --key GITHUB_APP_ACCESS_TOKEN --value "${TOKEN}" --sensitive
このコードはGitHubのドキュメントに載っていたコードをアレンジしたものです。これが実行されると、「GITHUB_APP_ACCESS_TOKEN」という名前のSecretな環境変数にinstallation access tokenが代入されます。なお、envmanコマンドの仕様上、GITHUB_APP_ACCESS_TOKEN変数が使用可能になるのは次のステップからである点に注意してください。このステップ内でGITHUB_APP_ACCESS_TOKEN変数を参照しても空文字が返ってきます。
ステップの名前は「Create installation access token of GitHub App」にしておきます。
3. Secretの設定
上記のステップを実行するには次の環境変数が必要です。
GITHUB_APP_PEM
GITHUB_APP_ID
GITHUB_APP_INSTALLATION_ID
いずれも秘密にすべき情報ですので、Secret Environment Variableにします。[Secrets] タブを開いて [Add new] ボタンを押し、それぞれの変数を作成しましょう。
GITHUB_APP_PEM
手順1でGitHubからダウンロードしたPEMファイル(秘密鍵)の中身をまるごとコピペします。下図のように複数行の文字列になりますが、ちゃんと動作しますので安心してください。
GITHUB_APP_ID
値にはGitHub AppのApp IDを設定します。
GITHUB_APP_INSTALLATION_ID
値にはInstallation IDを設定します。
次の手順4で [Run Danger] ステップを導入する場合はGITHUB_APP_ACCESS_TOKEN変数も作成しておきます。Workflow Editor上で [Run Danger] ステップを設定する際にSecret環境変数を選択する必要があり、その選択肢にこの変数を表示するためです。ここでは値は仮で「xxxxx」に設定しておき、上記のスクリプト実行時に正しい値を上書きします。
Dangerを利用する場合は各変数の [Expose for Pull Request?] はONにしてください。もしOFFにしていると、Pull Requestをトリガーにworkflowを実行する際に、各変数を参照できなくなってしまいます。
4. Dangerの設定
Run DangerというIntegrationのステップを追加しましょう。このステップの順序はトークン発行のステップよりも後ろにしてください。
Run Dangerの設定内の [Input variables] > [GitHub] > [Access token for your project] に手順3で作成したGITHUB_APP_ACCESS_TOKEN変数を指定します。
以上でDangerがGitHub Appのinstallation access tokenを使ってPull Requestにコメントできるようになりました。
まとめ
今回はBitriseでGitHub Appのinstallation access tokenを発行し、Dangerで使用する方法を紹介しました。今回は一例としてDangerを挙げましたが、トークンの発行部分についてはDangerに限らず様々な用途に応用できると思います。
宣伝
NTTレゾナントテクノロジーでは一緒に働いてくれるAndroid/iOSアプリエンジニアを募集中です。もし興味がありましたら採用ページを是非ご覧ください。