GitHub APIを使うBotたちのGitHub Appsへの移行

どうもこんにちは、ソーシャルゲーム事業部ゲーム技研の谷脇です。

この記事はTech KAYAC Advent Calendar 2019 Migration Trackの14日目の記事です。13日目はAmazon S3 Signature V2 廃止対応にまつわるあれこれでした。

従来のGitHub APIを使うBot

カヤックではGitHubを使っています。また、各プロジェクトでは自動化されたワークフローの一環として、Slack上でのコマンドからPull Requestを作成したり、レビュワースロットを実行したり、勝手に手順書を生成してissueに貼るなどしています。

こういったBotたちはGitHub上のリソースを操作するために、GitHub APIを使用しています。Organization内のPrivateリポジトリを操作するためには、認証のためにGitHub Tokenが必要です。

Machine userのGitHubアカウント

GitHub APIを叩く際にはGitHubの認証トークンを使います。認証トークンは、アカウントの設定ページから発行できるものです。

大事なのは、この認証トークンは1つのアカウントに紐づくもの、ということです。つまり、Botにもそれぞれに人間のユーザのようなGitHubアカウントを作成してトークンを発行して付与しなければいけない、ということになります。

従来はプロジェクトごとにBotアカウントを作成し、リポジトリのコラボレーターにBotを追加して、BotアカウントのトークンでAPIを実行していました。

BotがGitHubアカウントを持つ際の問題点

BotがGitHubアカウントを持つことでこれまで対応してきましたが、

  • 1つのアカウントをチーム内で共有して管理するモデルの危うさ
  • Botアカウントの管理がOrganizationから出来ない
  • GitHubのEnterpriseプランだとBotアカウントも1ヶ月あたり21ドルかかり、Botの数が増えるとばかにならないため
  • 1つのBotアカウントを複数プロジェクトでまたいで使うにはトークンが持つ権限が強すぎる

などなど、様々なデメリットがありました。そこで、ユーザではなくGitHub Appsの認証情報でAPIを実行しようと考えました。

普通のBotアカウントとGitHub Appsの違い

GitHub Appsはユーザアカウントとは違います。ユーザもしくはOrganizationが作成・管理を行うAppという位置づけです。似たような概念としてOAuth Appsがありますが、OAuth Appsに比べると出来ることが増えています。

以下にこれらの比較を示します。

項目 ユーザアカウント OAuth Apps GitHub Apps
誰が作るか ユーザ自身がサインアップ ユーザもしくはOrganizationが作る ユーザもしくはOrganizationが作る
複数ユーザでの管理 現実的に不可能 OrganizationのAdminのみが可能 OrganizationのAdmin以外も管理権限を付与出来る
一般ユーザとしてのAPI実行 可能 OAuthで可能 OAuthで可能
一般ユーザに紐付かないAPI実行 Botアカウントであれば可能 不可能 Installation Tokenで可能
GitHub EnterpriseでのSeat課金 される されない されない
トークンの有効期限 なし あり(OAuth) あり(1時間)
リポジトリの制限設定 ユーザが属するリポジトリ全てのみ OAuth認証したユーザが見れるリポジトリ全てのみ InstallしたOrganizationの管理画面で制限可能

また、GitHub AppsはユーザやOrganizationが作成するものですが、作成したユーザやOrganization以外が、同じGitHub Appsをインストールすることも可能です。一般に公開されているGitHub AppsはMarketplaceでもGitHub Actionsとともに並んでいます。

GitHub Appsは認証トークンの更新をし続けなければ使い続けられない反面、管理の面やコストの面でメリットが大きいと判断しました。

というわけで、既存のアカウントを作って運用していたBotをGitHub Appsに移行することにしました。

GitHub Appsでの認証トークンの取得方法

普通のユーザでは、設定画面から認証トークンを発行すればそれがずっと使えますが、GitHub Appsの場合は違います。GitHub Appsの認証トークンの発行は以下の段階を踏んで行います。

参考: Authenticating with GitHub Apps

  1. GitHub Appsを対象のOrganizationにインストール
  2. 秘密鍵をGitHub Appsの設定画面で作成しダウンロード
  3. App IDをIssuerクレームに含んだJSON Web Tokenを、先に作成した秘密鍵で署名する
  4. 何らかの方法でインストールしたOrganizationに対応するInstallation IDを取得する
  5. 作成したJWTをAuthorizationヘッダに含めて https://api.github.com/app/installations/:installation_id/access_token を叩く

最後のAPIのレスポンスで1時間の有効期限がある認証トークンを取得できます。このトークンでは、ユーザの認証トークンと同様に、ほとんどのAPIに対して使用することが出来ます。

Installation IDの取得方法

Organizationに対応するInstallation IDを調べる方法はいくつかあります。

一つは、インストール時にGitHub AppsのWebhookを見ることです。あらかじめWebhookのサーバを立ててログを取っていなくても、GitHub AppsのAdvanced -> Recent Deliversから見ることが出来ます。

f:id:mackee_w:20191213163412p:plain

もう一つはhttps://api.github.com/app/installationsというAPIを叩いて、インストールされたOrganization一覧を表示して、合致するOrganizationのIDを抜き出す方法です。このAPIを叩く際の認証方法は、認証トークンを取得する際と同じJWTで可能です。

各Botでの対応

ほとんどのGitHub APIを使うためのライブラリはGITHUB_TOKEN環境変数に認証トークンを入れたり、コンストラクタの引数として認証トークンを渡すなどの手法とをっています。

ただ、これらはGitHub Appsの有効期限があるトークンには対応していません。ですので、トークンを定期的に更新する機構が必要です。

Perlの場合

カヤックでは複数のプロジェクトでPerlを使っており、BotもPerlで書かれています。PerlでGitHubのAPIを叩く際には、Pithubというライブラリを使用しています。

Pithubも例に漏れず、コンストラクタに文字列として認証トークンを渡す形式です。そこで、文字列として評価されたときにトークンを発行し、有効期限が切れない間はそれをキャッシュして返し続け、切れたら再発行するようなオブジェクトを作るモジュールを作成しました。

GitHub::Apps::Auth

このモジュールの詳細については、Perl Advent Calendar 201914日目の記事に記載しています。

Goの場合

Goでサーバアプリケーションを書いているプロジェクトでは、BotもGoで書いています。GoでGitHubのAPIを叩く際には、github.com/google/go-githubを使っています。

このパッケージでもGitHub Appsのトークンはそのままでは使えません。Perlの場合と同様に、有効期限が切れるごとに更新するような工夫が必要です。

まさにそのようなことをやってくれるパッケージが、github.com/bradleyfalzon/ghinstallationです。

このパッケージで、まずHTTPのClientを作ってそれをgo-githubのNewに渡すだけでGitHub Appsの認証トークンを使ってAPIを叩くことが出来ます。

gitコマンドの場合

Botの中には、gitリポジトリをチェックアウトして操作した上でコミットするものも存在します。単一のリポジトリのみの操作であれば書き込み許可したDeploy Keyでも構わないのですが、Organization内の別のprivate repositoryをsubmoduleするなど、一度に複数のリポジトリを扱いたい場合には、Deploy Keyは使えません。

GitHub Appsで発行した認証トークンは普通のユーザの認証トークンと同様に、httpsプロトコルでのgitの操作時の認証にも使えます。ただ、毎回発行しては入力するというのも手間なので、もともとgitに存在するcredential helperの仕組みを利用して、GitHub Appsの認証トークンを使うコマンドを作りました。

git-credential-github-apps

Windows, Mac, Linuxそれぞれに対応したビルド済みバイナリがReleasesにありますので、それをダウンロードし、パスが通るところに置いてお使いください。

このコマンドはもとも存在する、Python製のgit-credential-github-app-authのGo移植版であるとも言えますが、細かい使い方は違いますのでご注意ください。

使い方としては、パスが通るところにgit-credential-github-appsを設置した上で、

$ git config --global credential.helper 'github-apps -privatekey <path to private key> -appid <App ID> -login <organization>'

と設定すれば、GitHub Appsの認証トークンでgitの操作が行われます。loginはOrganizationの名前を入れてください。git-credential-github-appsがInstallation IDを自動で検索します。

また、git-credential-github-app-authとは違い、1時間の有効期限の間であればファイルにトークンをキャッシュして使用するようになっています。

まとめ

  • ユーザアカウントのトークンを使うのに比べてGitHub Appsの方が管理の面などでメリットがある
  • 認証トークンの作り方が違うのと、定期的に再発行しないといけないので注意
  • 定期的にトークン再発行して今までのモジュールやgitコマンドを使う方法について説明しました

この記事を見て試してみて、うまく動かないよという情報があれば教えてください。直したりアドバイスなど力になれることがあるかもしれません。

明日はid:handlenameさんの「s3_backup(Lambda)をCross Reagion Replicationに変えた」です。

Web上でBlenderでつけたアニメーションの複数切り替え

この記事はTech KAYAC Advent Calendar 2019の14日目の記事です。

こんにちは!クライアント事業部技術部の@yumikokhです。
新卒4年目、今年からWebフロント→サーバーサイド所属になりましてお仕事で演出ごりごりすることはなくなったのですが、
趣味でWebGLや3Dソフト(Cinema4D, Blender)の勉強をしています。

今回は、Blenderでつけた複数のキーフレームアニメーションをWeb上で切り替える方法を最短ルートでお届けします!

つくるもの

サンプルページを用意しました

シンプルですね!
こんなかんじで、アニメーションを切り替える画面を作ります。

準備

  • Blender v2.8-

    • こちらからインストールできます
    • Blenderは超高機能な上に無料でオープンソースな3Dソフトです。
    • 今回はjsライブラリの Three.js を使用するため、 glTF2.0形式のデータが必要です
    • glTFはJSONによって3Dモデルやシーンを表現する便利なフォーマットのことです(ざっくり)
    • v2.7xまでglTF2.0のエクスポートにはアドオンが別途必要でしたが、v2.8から標準装備になったそう(^^)
  • なんらかのエディター

    • 特にこだわりがなければVSCodeで間違いないでしょう
    • サンプルコードをそのまま使えばファイル名変えるだけでOK

Blenderでアニメーションの元データをつくろう

さっそく新しいファイルを開きましょう!おきまりの箱が見えていますね

f:id:wyumikokh:20191213074709p:plain
最初の画面
この箱に適当にアニメーションをつけていきます。

キーフレームを打つ

キューブを選択した状態で K を打つと、↓のメニューがでてきます。
まずは位置にキーフレームを打ちたいので位置を選択します。

f:id:wyumikokh:20191213075007p:plain
キーフレーム挿入メニュー

最初のフレームにキーが打たれました!
↓がタイムラインで、青い縦線が今いる位置なので、1フレーム目が表示されています。(タイムラインの領域が狭い場合は境界をホバーすると領域をドラッグできそうなカーソルに変わるはずです)

f:id:wyumikokh:20191213075227p:plain
最初のフレーム

次に、適当に青線をドラッグしてフレーム位置を変えてみましょう。
適当で大丈夫ですがだいたい10フレームくらいに動かしたら、Z位置の値を変えて箱を浮かせてみましょう
値を変えたあとは右側のひし形をクリックしてキーを打ちます。キーを打たないと値はリセットされるのでご注意を!

f:id:wyumikokh:20191213080339p:plain
Z位置を変えてキーをうつ

同じ要領で適当に20フレームあたりに青線をドラッグし、Z位置を0にしてキーを打ちましょう。
これで1つ目のキーフレームアニメーションは完成です!
青線を最初の位置に戻して再生ボタンorスペースキーを打つと箱が飛び跳ねる(とまで躍動感はないですがw)はずです!

f:id:wyumikokh:20191213080834p:plain
キーフレーム完成

アクションを作成

次に左上のアイコンを選択し、ドープシートに切り替えます。

f:id:wyumikokh:20191213081224p:plain
ドープシートに切り替える

切り替えたらドープシート と書かれたプルダウンメニューから アクション を選択します。
すると↓のような表示が現れます。ここでWeb上で切り替えるためにアクション単位で保存します。
CubeAnimation をお好きな名前でOKです。
今のアニメーションをアクションとして保存するには、名前右の盾のようなアイコンをクリックします。

f:id:wyumikokh:20191213081523p:plain
アクション

これで1つ目のアニメーションを設定できました!

2つ目以降のアニメーション

先程の盾アイコンの右にあるアイコンをクリックして新規アクションを作成+今あるキーを削除し、先程の要領で新しいアニメーションを作成します。

ファイル書き出し

ファイル > エクスポート > glTF2.0 を選択し、「モディファイアーを適用」「+Yが上」にチェックして書き出します。

f:id:wyumikokh:20191213082337p:plain
glTF2.0をエクスポート

Web上で動かそう

実装する前に、glTF Viewer で先程書き出したデータが正しく表示されるか確認します。
glTF Viewerからもアニメーションの切り替えができるはずです

↑で問題がなければ実装です!
実装と言っても、Three.jsに必要な機能がほとんど準備されてます!やったぜ!

全体のコードはこちらにあるので、カメラやライティングなどベースとなるオブジェクトについては割愛させていただきます。

glTFデータの読み込み

GLTFLoaderを使います。指定したglTFデータを読み込み、Threejs用にいい感じにparseしてくれます。

const loader = new THREE.GLTFLoader();
loader.load("./sample-anim.glb", gltf => {
  // ロード後の処理
  scene.add(gltf.scene); // gltfのシーンを乗っける
  // gltf.animationsの中にBlenderで作成したアニメーションデータが入っている
}

アニメーションの切り替え

AnimationMixerを通して、先程読み込んだanimationを AnimationAction に変換します

// animationはgltf.animationsの中の要素
const mixer = new THREE.AnimationMixer(gltf.scene);
const action = mixer.clipAction(animation);

AnimationActionはアニメーションのタイムラインの制御を簡単にしてくれるもので、↓のようにチェーンで直感的な記述ができます。
loopの有無、種類の指定やアニメーションが切り替わるときに唐突に切り替わるのを防ぐためFadein/outする関数も用意されてます。

action.reset().play().fadeIn(0.5);

さいごに

いかがだったでしょうか? Blenderは学生時代に少〜しだけかじってたのですがUIがかなり美しくなってて驚きでした。これで無料ってほんとありがたいですね。
3D表現が気軽にできて、夢広がります(^o^) 最後までご覧いただきありがとうございました!!誰かのお役に立てたら幸いです!