🐈‍⬛

GitHub Appとは? 作りながら仕組みを理解する

2023/06/26に公開

GitHub Appsとは何かがよく分からなかったので、実際に作りながら学んでいきます。

GitHub Appsとは

https://docs.github.com/en/apps/overview
https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps

1つめは利用者側から見た概要。2つめは開発者から見た概要です。

  • GitHub AppsはGitHubの機能を拡張するツール
  • GitHubを操作したり、GitHub外と連携したりできる。例えばissueを開いたり、Slackに通知したり
  • リポジトリにインストールして使用する

マーケットプレイスで様々なGitHub Appsが公開されている。リポジトリにインストールするだけで同じ機能が実現できるのが嬉しい。Actionsでそれをしようとするとyamlが個別に必要になる。

https://github.com/marketplace?type=apps

パッと見でも、リポジトリ内の画像サイズを最適化してくれるアプリ、静的解析してくれるアプリ、依存関係の古いバージョンを自動で検知して更新PRを出してくれるアプリなど、多種多様。

GitHub Appsはどのように動いている?

後で作って分かりましたが、このような構成になっていました。



※必ずしもこの図のとおりでない場合もあります!(全リポジトリへの一括インストールをした場合だったり、バックエンドが非同期処理だったり、Webhook使わないAppだったり。etc)

GitHub Appsはアカウントの中のリポジトリ単位で(Allも選択できるが)インストールされ、操作権限が与えられます。インストールされたリポジトリにイベントが起こると、実行環境にWebhookが送信され、そこで具体的な処理が走ります。

具体的な処理を始める前に、認証認可フェーズがあります。

  1. webhookの署名検証
  2. GitHub Appsの検証。トークン発行

それぞれの詳細は以下です。

1. webhookの署名検証

GitHub Appから来た正しいWebhookリクエストだけを受け付けて処理を動かしたいです。それを実現するために、webhook secretをあらかじめ設定しておき、リクエストの署名を検証します。

https://docs.github.com/en/webhooks-and-events/webhooks/securing-your-webhooks

ドキュメントによると、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

上記ドキュメントにもありますが、トークン発行には以下のステップが必要です。

  1. installation access tokenを発行するための認証・認可に必要なjwtを発行する
  2. 発行したjwtを持ってしてinstallation access tokenを発行する

1. JWTの発行
ドキュメントはこちら。

Generating a JSON Web Token (JWT)

発行にはGitHub App IDGitHub Appの秘密鍵の2つが必要です。秘密鍵はwebhook secretとは別物で、GitHub Appsの管理者ページから発行することができます。この秘密鍵がGitHub側と実行基盤側にあることで、正しいGitHub Appからリクエストが来ていることを検証できます。

2. installation access tokenの発行
installation access tokenの発行にはinstallation idjwtが必要です。installation idはWebhookのリクエストと同時に送られてきます。

発行後はこのtokenを使ってAPIを操作します。

GitHub Appsを作る

手を動かしていきます!
今回はチェックランを操作するGitHub Appsを作っていきます。

完成コードはこちらです。
https://github.com/a-takamin/github_app_test/tree/main

完成アーキテクチャはこちらです。

チェックラン(check runs)とは

これ↓

https://docs.github.com/en/rest/guides/using-the-rest-api-to-interact-with-checks

よくPRをマージする前に見かける ✅ は「チェックラン」という名前がついていたのでした。チェックランは何らかの実行のことではなく、「テストをコアとするオブジェクト」 だと考えています。

  • テストそのもの
  • テスト実行のステータス
  • テスト実行結果の詳細情報(アノテーション)
  • 結果に対するアクション
  • など

なお、チェックランが0個以上集まってチェックスイートを構成します。チェックスイートはコミットごとに必ず作成され、例えばチェックスイート内のすべてのチェックランが通らないとマージさせない、みたいなことができます。

1. まずは最低限のGitHub Appを作る

GitHub Appについての記事はこちらです。

https://docs.github.com/ja/apps/using-github-apps/about-using-github-apps

まずは形だけ作ってしまいます。
右上の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.ymlLambda, 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 APIServerless Frameworkも少し知ることができたので、やはり作って手を動かすのが大事ですね。

自作GitHub Appというおもちゃができたので、また気になったときに中身を変更して遊んでいこうと思います(テスト書かなきゃ)

Discussion