🐧

validate-pr-review-action で Pull Request の review を validation

に公開

以前、自分で Pull Request にコミットを push して approve する self approve を防ぐ方法を考察し、 CLI ツールと GitHub Action を作って記事を書きました。

https://zenn.dev/shunsuke_suzuki/articles/deny-self-approve

今回はその内容を発展させ、新たに開発した GitHub Action を紹介します。

https://github.com/suzuki-shunsuke/validate-pr-review-action

Validate PR Review Action は pull request の review を validation する action です。
Pull Request をマージする前に pull_request_review event で実行して validation します。
この action を実行する job を Branch Rulesets の Required Checks に追加することで、 validation が通らない限りマージできないようにします。

name: Validate pull request reviews
on:
  pull_request_review:
    types:
      - submitted
      - dismissed
jobs:
  validate-pr-review:
    runs-on: ubuntu-24.04
    timeout-minutes: 5
    permissions:
      pull-requests: read # To get pull requests
      contents: read # To get pull request commits
    steps:
      - uses: suzuki-shunsuke/validate-pr-review-action@bd967a12742566a5e3fb02878e4e2447da68f72e # v0.0.4

validate-pr-review-action は GitHub GraphQL API で pull request の author, commits, reviews などを取得し、以下のようなバリデーションを行います。

  • PR の最新の commit に対して PR に commit している人以外が approve していなければなりません
    • 古い commit への approve は無視します
    • PR の committer の approve は無視します
  • GitHub App や信頼できない Machine User による approve は無視します
    • 不正に approve している可能性があるため
  • 以下の場合、 2 人以上が approve していなければなりません
    • 信頼できない Machine User や GitHub App が commit している場合
      • 信頼できない Machine User などを悪用して commit して自分で approve している可能性があるため
    • PR の作成者が信頼できない Machine User や GitHub App の場合
      • 信頼できない Machine User などを悪用して PR を作成して自分で approve している可能性があるため
    • GitHub User に紐づかない commit が含まれる場合
      • User を誤魔化して自分で commit して approve している可能性があるため

これらの validation により、先述の記事で挙げた 3 つのパターン全てに対応できていることになります。

  1. codeowner 権限を持つ Machine User を悪用して approve => PR できない Machine User の approve は無視
  2. 自分以外が作成した PR に自分で commit を追加して自分で approve => PR の committer の approve は無視
  3. 自分以外が作成した PR に Machine User や bot で commit を追加して自分で approve => 信頼できない Machine User や GitHub App が commit している場合、 2 approve を要求

Branch Rulesets で Commit Signing を必須にする

Branch Rulesets で Commit Signing を必須にしましょう。
そうでないと、他の人になりすまして commit をして自分で approve することができてしまいます。
Branch Rulesets で必須にすることができるため、 validate-pr-review-action は commit signing によるバリデーションは行いません。

信頼できる GitHub App と信頼できる(ない) Machine User

action の input で信頼できる GitHub App と信頼できる(ない) Machine User のリストを指定することができます。

- uses: suzuki-shunsuke/validate-pr-review-action@bd967a12742566a5e3fb02878e4e2447da68f72e # v0.0.4
  with:
    trusted_apps: |
      renovate
      dependabot
    trusted_machine_users: |
      suzuki-shunsuke-bot
    untrusted_machine_users: |
      mini-core
      /-bot$/

untrusted_machine_users では正規表現が使えますが、 trusted_appstrusted_machine_users では使えません。
これは正規表現で意図せず GitHub App や Machine User を信頼できるものとして扱わないようにするためです。
正規表現を使う際は /-bot$/ のように正規表現を / で囲います。
trusted_machine_usersuntrused_machine_users の正規表現にマッチする一部のユーザーを除外するのに使うことを想定しています。

ある GitHub App が信頼できるかどうか、ある User が信頼できない Machine User であるかどうかは、それらが適切に管理されているか、悪用できる状態にあるかによって決まります。

例えばある GitHub App が Organization の全リポジトリにインストールされていて contents:write や pull_requests:write 権限を持っていて App ID や Private Key が Organization Variables と Organization Secrets で全リポジトリに共有されているような場合、その GitHub App は信頼できません。
Organization のメンバーであれば誰でも任意のリポジトリの任意のブランチからその GitHub App を悪用して PR や commit を作成したり PR を approve したりすることができるからです。

デフォルトでは renovatedependabot は信頼できる GitHub App とし、それ以外は信頼できない GitHub App とします。
当然ですが、適切に管理されていない GitHub App を trusted_apps に追加するのはやめましょう。

Machine User については、一部の信頼できる Machine User を除き、全ての Machine User を信頼できないものとして指定しましょう。

GitHub App や Machine User の適切な管理

どのように管理すれば適切に管理されていると言えるでしょう?
人・組織によって基準は異なるかと思いますが、以下のような点が挙げられます。

  • 組織内で PAT や Private Key が広く知られていない
    • 不特定多数のメンバーに知られている場合、適切に管理されているとは言えません。 revoke するべきでしょう
  • Rulesets によって適切に保護された branch や tag で実行される workflow からのみ Personal Access Token や Private Key が参照できるようにします
    • GitHub Environment Secrets で保護したり、 AWS Secrets Manager や Google Secret Manager のような secret manager で管理して OIDC で repository や branch, tag, workflow によってアクセスを制限する必要があります
  • それらの workflow の変更は validate-pr-review-action によって review が必須になっている必要があります

Client/Server Model Action

feature branch など、適切に保護された branch 以外で GitHub App や Machine User を使いたいケースは当然あります。
その場合、 Client/Server Model Actions (以下 CSM Actions) が役に立ちます。

https://github.com/csm-actions/docs

CSM Actions で現状実装されている action の種類は多くありませんが、以下のようなセキュリティ的に重要な action がサポートされています。

下記の記事で紹介した Securefix Action も csm-actions に移動しました。

https://zenn.dev/shunsuke_suzuki/articles/securefix-action

セキュアな PR branch の update

validate-pr-review-action は PR の committer の approve を無視します。
これは review を強制するために必要ですが、 reviewer が PR の update branch をしてしまうと、その人以外が approve しないといけなくなるという欠点もあります。
実際、 reviewer が update branch したくなるケースはままあります。
そこで、 CSM Actions の Update Branch Action を使うと Client/Server Model でセキュアに update branch することができます。

https://github.com/csm-actions/update-branch-action

Discussion