orgu: New OSS to implement GitHub organization-wide workflows
こんにちは、プラットフォームチームのtaiki45です。この記事ではGitHubのorganization-wide workflowsを実現するソフトウェアである “orgu” を紹介します。 https://github.com/Finatext/orgu
- GitHub organizationの全リポジトリまたは特定の属性のリポジトリ群に特定のジョブを実行し続けたい
- GitHubが用意している “Ruleset workflows” は似たことを実現できるがEnterpriseプランが必要
- “orgu” というOSSを開発して、AWS Lambda(他のプラットフォーム上でも可)上で動かすことにより、organization-wide workflowsを実現しました
ちなみにorguの読み方は「オルグ」です。Organization-wide workflowsを連想させ、かつ短い名前ということで選びました。トルコ語で編み物という意味のようです。
Motivation
例えばsecrets scannningのようなCIジョブはGitHubの全リポジトリに対して実行を行いたいです。他にもGitHub Actionsのworkflowファイルのlinterやgosecのようなlinterなど、全リポジトリあるいは特定の属性のリポジトリ群に対してCIジョブを実行し続けたい、という要求は常にありました。
「ジョブ自体はreusable workflowを使って実装しつつ、テンプレートとなるリポジトリを用意してテンプレートに必須なジョブを入れておく」方法により部分的に解決を試みていたり、リポジトリ群に特定のファイルを同期するソフトウェアを開発して問題の解決を試みたりもしました。
しかし、Finatextはマルチドメイン・マルチプロダクトな会社であり、リポジトリ数は現在700を超えていて毎月二桁ペースでリポジトリ数が増えています。初期のアーキテクチャがマイクロサービスに寄りすぎていたためリポジトリ数が多かった過去はありますが、現在はその教訓を活かし必要程度の分散アーキテクチャを採用しています。それでも毎年40%という事業の急成長に従い開発するソフトウェアは増加しています。
マルチドメイン・マルチプロダクトであることの技術的なデメリットはありますが、そのおかげで高い成長率を維持できる強い事業ポートフォリオを作れています。つまり、この状況はテクノロジーで解決すべき問題です。
GitHub Ruleset workflows and post-ZIRP era
2023年1月にGitHubは “organization-wide required workflows” という機能の公開ベータを発表しました。
これはまさにFinatextが求めていた機能であり導入し便利に使っていました。そしてこのorganization-wide required workflowsの上でsecrets scanなど各種ジョブを動かす計画でジョブの開発を進めていました。
しかし、2023年8月に状況は変わります。Organization-wide required workflowsの公開ベータ卒業とともにorganization-wide required workflowsを “Repository Rules” という機能へ統合することを発表しました。
Organization-wide required workflowsには「リポジトリを管轄する」ような側面があるので、そのような機能と統合することは理にかなっています。問題はGitHubのプランとの兼ね合いでした。Organization-wide required workflowsはTeamプランでも使える機能であり、なのでFinatextでも積極的に活用する予定で導入を進めていました。しかし、Repository Rules機能はEnterprise以上のプランのユーザーのみが使える機能で、FinatextはTeamプランなので、organization-wide required workflowsを使っていたジョブは10月に止まることになりました。
もちろん、GitHubはソフトウェア開発をする場としては最も適していると判断していて、積極的にGitHubの機能を活用して開発生産性を高めています。しかし費用対効果を冷静に判断することは重要です。特にこのpost-ZIRPの時代は、利益や調達した資金をどう使うかという意思決定はより重要になってきています。Finatextも例外ではなく、時代の流れを捉えた意思決定をし続けた結果、急成長の会社ながら昨年度黒字化を達成し、今年度も引き続き黒字化を見込んでいます。
Finatextでは、積極的にGitHubを活用していることもあり、希望するメンバー全員にGitHubにアクセスできるようにしています。そのため、ユーザーあたり月$4が月$21に変化することと、それで享受できるメリットを考慮した結果、今のところTeamプランを利用し続けることにしています。
以上のような背景・経緯で、organization-wide workflowsを実現するためのソフトウェアの開発を始めました。
Introducing orgu
GitHubにはChecks APIという「GitHub Actions外でCIジョブを実行し結果をフィードバックする仕組み」があります。Checks APIについての予備知識があると読解がスムーズになると思います。

orguのアーキテクチャは、GitHubからのイベントを受け取る “orgu-front” と実際にCIジョブを実行する “orgu-runner” の2つに分かれています。デフォルトではAWS Lambda上で動かす想定で、Finatextでも実際にLambda上でジョブを実行しています。orgu自体はKubernetes上などLambda以外で動かす拡張ができるように設計・実装しています。
GitHub Appsのwebhookイベントを利用して “pull_request synchronize” や “check_suite requested” などのイベントをorgu-frontが受け取ります。orgu-frontはイベントを “Event Queue” に送ります。このEvent QueueはキューイングとファンアウトができるものならなんでもOKです。デフォルトではAmazon EventBridge Event BusをEvent Queueとして使っています。orgu-frontはイベントをキューしたことをGitHubのChecks APIを使って開発者に伝えています。
Event Queueによってイベントはファンアウトされます。ファンアウトした先でイベントのフィルター処理をはさんでいます。これは、特定の属性のリポジトリに対してのみジョブを実行したい時に、他の関係ないリポジトリのイベントでorgu-runnerを起動するとコンピューティングリソースの無駄になるからです。デフォルトではAmazon EventBridgeの “event patterns” という機能を使って実現しています。また、Finatextではリポジトリの属性は管理はGitHubの “custom properties” という機能を使って行っていて、orguでもそれを使っています。
Event Queueのフィルターを通過したイベントによってorgu-runnerのイベントループが実行されます。orgu-runnerはジョブを実行するリポジトリをテンポラリなディレクトリにクローンしてきて、その中でジョブの実行をします。orgu-runnerもGitHubのChecks APIを使ってジョブの起動や終了ステータスやログを開発者に伝えています。
orgu-runnerはジョブを実行する時に、一時的に有効なGitHub installation access tokenやリポジトリ名やpull request情報やリポジトリのcustom propertiesなどをジョブに環境変数経由で伝えます。ジョブは受け取った情報を利用してジョブを実行しつつ、受け取ったアクセストークンを利用してGitHubのAPIにジョブの実行結果を投げます。ジョブの実行結果を伝える方法は自由に選択できるようになっていますが、reviewdogというソフトウェアがおすすめです。従来のようにpull requestにコメントする形でフィードバックもできますし、Checks APIを使ってより見やすくうるさくない方法でフィードバックすることもできます。
Secrets scanのようなジョブでは、GitHubのUI経由で開発者にフィードバックするだけでなく、Opsgenieというアラート管理のサービスを使ってアラートを作成して、秘匿値となりえる値の検出から対応完了までをトラックできるようにしています。この辺りの「どのようにジョブの結果をアウトプットするか」はorguでは管理していないので、ジョブ毎に自由にカスタマイズできるようになっています。
orgu-runnerの構成についてもう少し。orgu-frontはorguが用意しているコンテナイメージを使って動かすことができますが、orgu-runnerのコンテナイメージは各CIジョブ毎にユニークなものを作成します。これはジョブが必要な依存をコンテナイメージ内に用意するためで、各コンテナイメージ内にorguのバイナリを入れて、コンテナ実行のエントリーポイントはorgu-runnerのコマンドになります。orgu-runnerのイベントループ内でCIジョブが起動して実行されるイメージです。言葉で説明するとわかりにくいですが、リポジトリの example/Dockerfile
に実際の Dockerfile
があるのでそれを見てもらうと理解が早いと思います。
User experience
orguの使用イメージを掴んでもらうため、いくつかのスクリーンショットを貼ります。ここではsecrets scan という、リポジトリにプッシュされた秘匿値らしきものを検知するCIジョブを走らせてみます。
Status checksの様子。GitHub Actionsのワークフローと同じように、今はチェックマーク(✅)になっている箇所がジョブの実行中は黄色で実行中っぽいUIになります。

orgu-runnerがジョブの実行結果をフィードバックしているUIです。GitHubのChecks APIを使って開発者へフィードバックしています。このsecrets scanジョブでは実行対象のリポジトリだけでなく、secrets scanの設定を置いているリポジトリ(ここでは gitleaks-config
)をチェックアウトする必要があるため、ジョブの内部で orgu checkout
コマンドを使ってクローンしてきています。Status checksと同じく、ジョブの実行中はチェックマークが黄色になっていてグルグル動いていてジョブ実行中っぽいUIになります。ジョブが失敗した時はここで、ジョブの失敗を終了コードやログとともに開発者へ伝えます。
ちなみに、スクリーンショットからは見切れてますが、右上に “Re-run all checks” というリトライのためのボタンが用意されていて、ここからジョブを再実行できるようにもなっています。

CIジョブが特に問題を見つけなかった時は、上記のようなUIで開発者へジョブの実行だけフィードバックします。ジョブが、例えば秘匿値を見つけた場合など、なにか問題を見つけた時はジョブ自身がpull requestコメントやChecks APIを使って開発者へフィードバックします。
Checks APIではアノテーションを使ってフィードバックします。スクショではマークダウンがうまく適用できてないのとHTMLタグも残念な感じになってますが修正したので見逃してください…

Checks APIを使った時のpull requestの “Checks” タブのUIです。ジョブの実行自体は成功に終わってるので、orgu-runnerが run-secrets-scan
check経由で成功を報告しています。ジョブの中でChecks APIを使ったcheckが secrets-scan
で、このcheckは秘匿値が見つかったので失敗を報告しています。

Pull requestコメントでフィードバックする場合のイメージです。アノテーションより良くも悪くも注目度があるので、ジョブによってはこの報告スタイルが向いてることもあります。

Getting Started
Mediumだとコードブロックが見にくいと思うので、リポジトリのREADMEに用意しています。簡単に手元で動作させることもできるようになっているのでぜひ試してみてください。
Outside of AWS Lambda
orguはAWS Lambda以外でも動くように設計をしています。その辺りはREADMEに書いたので気になった方は読んでみてください。
orguの実装
orguはRustで実装しています。特徴としては、gitコマンドを呼び出すのではなくlibgit2というライブラリを使ってgit周りのオペレーションをしているので、orgu-runnerのコンテナイメージにgitコマンドがなくても動くgitコマンドフリーになっているところがあります。git fetch中のログ出力もいい感じにカスタマイズできるのも利点です。欠点としては、libgit2のRustバインディングであるgit2 crateがかなりがんばってくれてはいるんですが、async対応なpure RustなGitライブラリが望まれますね…gitoxideゴゴゴ
他はありきたりですが、clapやtracingあたりのライブラリが強力で、言語自体の表現力が高いことやコンパイラが賢くて書きやすかったです。デファクトなGitHubクライアントライブラリが不在な気がするのでここだけどうにかしたいですね…ゴゴゴ
おわりに
Platform Engineering Kaigi 2024というイベントで登壇する予定です。プラットフォームエンジニアリングの領域の技術的な取り組みについて喋る予定なので、興味があればぜひ聞きに来てください。このorguの話などおもしろいと思います!
引き続きおもしろいと思う情報発信をしていく予定なので、よければ筆者のXアカウントをフォローしてもらえるとうれしいです! https://x.com/taiki45
Finatextに興味を少しでも持っていただけたら、ぜひテックブログの他の記事や採用情報を覗いてみてください!