GitHub Appとは? 作りながら仕組みを理解する
GitHub Appsとは何かがよく分からなかったので、実際に作りながら学んでいきます。
GitHub Appsとは
1つめは利用者側から見た概要。2つめは開発者から見た概要です。
- GitHub AppsはGitHubの機能を拡張するツール
- GitHubを操作したり、GitHub外と連携したりできる。例えばissueを開いたり、Slackに通知したり
- リポジトリにインストールして使用する
マーケットプレイスで様々なGitHub Appsが公開されている。リポジトリにインストールするだけで同じ機能が実現できるのが嬉しい。Actionsでそれをしようとするとyamlが個別に必要になる。
パッと見でも、リポジトリ内の画像サイズを最適化してくれるアプリ、静的解析してくれるアプリ、依存関係の古いバージョンを自動で検知して更新PRを出してくれるアプリなど、多種多様。
GitHub Appsはどのように動いている?
後で作って分かりましたが、このような構成になっていました。
※必ずしもこの図のとおりでない場合もあります!(全リポジトリへの一括インストールをした場合だったり、バックエンドが非同期処理だったり、Webhook使わないAppだったり。etc)
GitHub Appsはアカウントの中のリポジトリ単位で(Allも選択できるが)インストールされ、操作権限が与えられます。インストールされたリポジトリにイベントが起こると、実行環境にWebhookが送信され、そこで具体的な処理が走ります。
具体的な処理を始める前に、認証認可フェーズがあります。
- webhookの署名検証
- GitHub Appsの検証。トークン発行
それぞれの詳細は以下です。
1. webhookの署名検証
GitHub Appから来た正しいWebhookリクエストだけを受け付けて処理を動かしたいです。それを実現するために、webhook secret
をあらかじめ設定しておき、リクエストの署名を検証します。
ドキュメントによると、webhook secret
を設定するとx-hub-signature-256
というヘッダーがリクエストにセットされます。このヘッダーの値はリクエストのbody
と秘密鍵(webhook secret)を使い、sha256のハッシュ値を割り出したもので、リクエストの署名です(暗号&復号を行っているわけではない)。
従って、リクエストのbody
と秘密鍵(webhook secret)をもってsha256のハッシュ関数を使用することで同じ値が生成されるはずで、これを持ってして署名を検証します。
これにより、同じ秘密鍵を持っているGitHub Appからリクエストが来た(変なところからリクエストが来ていない)ことが確認できます。
2. GitHub Appsの検証。トークン発行
GitHub Appが、そのAppがインストールされたリポジトリを操作する(GitHub APIを叩く)ためには、トークンを発行する必要があります。
このトークンは、公式ではinstallation access token
と呼ばれていますが、開発者の間ではGitHub App Token
と呼ばれることが多い気がします。GitHubはトークンの種類が多くややこしいので注意(personal access token)とか。
Using an installation access token to authenticate as an app installation
上記ドキュメントにもありますが、トークン発行には以下のステップが必要です。
-
installation access token
を発行するための認証・認可に必要なjwt
を発行する - 発行した
jwt
を持ってしてinstallation access token
を発行する
1. JWTの発行
ドキュメントはこちら。
Generating a JSON Web Token (JWT)
発行にはGitHub App ID
とGitHub Appの秘密鍵
の2つが必要です。秘密鍵はwebhook secretとは別物で、GitHub Appsの管理者ページから発行することができます。この秘密鍵がGitHub側と実行基盤側にあることで、正しいGitHub Appからリクエストが来ていることを検証できます。
2. installation access tokenの発行
installation access tokenの発行にはinstallation id
とjwt
が必要です。installation id
はWebhookのリクエストと同時に送られてきます。
発行後はこのtokenを使ってAPIを操作します。
GitHub Appsを作る
手を動かしていきます!
今回はチェックランを操作するGitHub Appsを作っていきます。
完成コードはこちらです。
完成アーキテクチャはこちらです。
チェックラン(check runs)とは
これ↓
よくPRをマージする前に見かける ✅ は「チェックラン」という名前がついていたのでした。チェックランは何らかの実行のことではなく、「テストをコアとするオブジェクト」 だと考えています。
- テストそのもの
- テスト実行のステータス
- テスト実行結果の詳細情報(アノテーション)
- 結果に対するアクション
- など
なお、チェックランが0個以上集まってチェックスイート
を構成します。チェックスイートはコミットごとに必ず作成され、例えばチェックスイート内のすべてのチェックランが通らないとマージさせない、みたいなことができます。
1. まずは最低限のGitHub Appを作る
GitHub Appについての記事はこちらです。
まずは形だけ作ってしまいます。
右上のSettings > Developer settings > GitHub Apps
に行きます。
以下のような感じで埋めます。
GitHub App Name: 適当
Homepage URL: 適当
Permission:
- Checks: Read and Write
- Contents: Read
Where can this GitHub App be installed?:
- Only on this account にチェックを入れる
画像はこちら
ここまでできたら一旦放置して次の作業に移ります。色々空欄のままですが、後でまた埋めに帰ってきます。
2. GitHub Appの実行環境を作る
アーキテクチャ図にあるように、GitHub Appの処理実態はLambdaなのでそれを用意します。ngrokを使うという手もありますが、セキュリティが少し気になるような仕様なので代わりにLambdaにしています。
関数URL
を使って、API Gatewayを置かずに直接アクセス可能にし、リソース量を減らしています。
2-1. Serverless Frameworkを準備
Lambdaの準備はなんでも良いですが、せっかくなのでServerless Framework
で作ってみます。
serverless.yml
でLambda
, IAM Policy
, IAM Role
を作っています。serverless framework(※CloudFormation)
ではParameter Store
のSecure Stringパラメータを作れず、暗号化なしのStringパラメータしか作れないので、その部分だけcreate_ssm.sh
で作っています。一回だけ実行してください。
./create_ssm.sh
npm ci && npm run deploy
2-2. シークレットの値を書き換え
3つのパラメータが作成されていると思うので、値を書きかえていきます。すべてGitHub Appの画面から取得 or 設定可能です。
GitHub Appのwebhook secret:
- 管理者画面で適当に決め、それを反映させます
GitHub App ID:
- 管理者画面の上の方にあります
GitHub Appの秘密鍵:
- 管理者画面の下の方にPrivate Keysという欄があるので、そこで発行します
3. GitHub Appをインストールする
実際にテストリポジトリにGitHub Appをインストールしていきます。
管理者画面のInstall App
からインストールできた…と思います。インストールしたいリポジトリを選択します(別にAllでもいいです)
4. インストールしたリポジトリに変更を加える
適当にコミットしてPRを生成してみると、チェックに失敗します(そういう実装なので…)。
details
に行くといろいろ見れます。annotation
という機能を使っていて、README.md
にそれをつけるようにしているので、README.md
のfile changedが以下の画像のようになります。
プルリク
チェック
README.mdのFile Changed
action
という機能も使っていて、これを作成するとボタンを生成することができます。ボタンをユーザに押させて、さらなる処理を行うことができます。(例えばチェックを再実行するとか、issueを〇〇するとか)
今回の実装だとclick to fix
というボタンがあり、これを押すとチェックに成功します。
おわりに
GitHub App
を実際に作ってみて、どのような仕組みになっているか詳しく知ることができました。副作用でChecks API
やServerless Framework
も少し知ることができたので、やはり作って手を動かすのが大事ですね。
自作GitHub Appというおもちゃができたので、また気になったときに中身を変更して遊んでいこうと思います(テスト書かなきゃ)
Discussion