プルリクレビュー時に使用している自作GitHub Actionsの紹介

私がプルリクレビュー時に使用している自作のGitHub Actions[「action-repository-permission」](https://github.com/sushichop/action-repository-permission)について紹介します。利用シーンは限定されるActionsですが、[GitHub Marketplaceにも公開](https://github.com/marketplace/actions/repository-permission)していますので、OSSをメンテされている方をはじめ、本機能を必要と感じた方、興味がわいた方は試してみてもらえればと思います。

# 本Actionsが提供する機能

リポジトリに対するCollaboratorとしてのユーザ権限をチェックします。主に、writeまたはadminの権限を持っているかどうかをチェックするために使うケースを想定しています。

# 使い方

## 基本

下記はIssue書き込みしたユーザについて、Collaboratorとしてwrite以上の権限を持っているかどうかをチェックする例です。ユーザが権限を持っている場合には、Actionsワークフローのコンソールに`A user trying to access is permitted`と表示されます。

```yml
on
  issue_comment:
    types:
      - created
jobs:
  steps:
    - name: Check repository permission for user
      id: permission
      uses: sushichop/action-repository-permission@v1
      with:
        required-permission: write
    - name: "The following will be executed if the permission is passed."
      run: |
        echo "A user trying to access is permitted"
```

## 応用例

本Actionsのオプション設定も使いつつ、ワークフロー記述内容に一手間加えることで、一定以上の権限を持つユーザのみが、コマンド入力感覚で特定処理を実行できるワークフローを作成できます。

下記はforkされたリポジトリからのプルリクレビュー時に、リポジトリに対してCollaboratorとしてwrite以上の権限を持つユーザが、Issueコメント欄に`/danger`とコメント入力することで、レビューチェッカーである[danger](https://danger.systems)をCI実行させる記述例です。`reaction-permitted`に設定された内容(下記ではrokcet)は、ワークフロー実行時にリアクションemojiとしてIssueコメント欄に反映されます。

一方、権限を持たないユーザが同じ内容をコメント入力した場合は、`comment-not-permitted`に設定された内容がコメント欄に反映されてワークフローが終了します。

```yml
on:
  issue_comment:
    types:
      - created

jobs:
  danger:
    name: Danger
    if: |
      github.event_name == 'issue_comment' && github.event.action == 'created'
      && github.event.issue.pull_request != null
      && startsWith(github.event.comment.body, '/danger')
    runs-on: macos-11
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Check repository permission for user
        uses: sushichop/action-repository-permission@v1
        with:
          required-permission: write
          reaction-permitted: rocket
          comment-not-permitted: Sorry, you don't have enough permission to execute `/danger`...
      - name: Clone the PR source
        uses: actions/checkout@v2
        with:
          ref: refs/pull/${{ github.event.issue.number }}/head
          fetch-depth: 0
      - name: Danger
        run: |
          bundle install
          bundle exec danger
```

# 実際にどう使われているか知りたい場合は？

私がメンテしているOSS([CocoaLumberjack/CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack)、[sushichop/Puppy](https://github.com/sushichop/Puppy)など)で本Actionsを使っているので、過去のプルリクをいくつか覗いてみてもらえるとよいかと思います。`/run_checks`や`/danger`というコメント入力が見つかるはずです。不明点がある場合は、[action-repository-permission](https://github.com/sushichop/action-repository-permission)のIssueメニューから質問していだければ幸いです。

# 最後に

現在のところ、私がGitHub Marketplaceに公開しているActionsは今回紹介した1つのみなので、今回のアドカレ投稿を契機に、そろそろ新たなActionsを作ろうかなと考えています🙂


## ※ 補足(興味のある方のみ)

__以下は長いので興味のある方のみお読みください。GitHub Actionsにおけるセキュリティに対する考え方や`GITHUB_TOKEN`の権限に関する話です。__

プルリクレビュー時において、わざわざ擬似的なコマンドを入力する形式でジョブを実行させているのは何故か？と疑問に思った方はいますでしょうか？本件について、私はセキュリティや使い勝手、その他いろいろなことを総合的に判断して考えるべき事項だと考えています。つまりケースバイスケースで考えるべきです。

実際のところ、私がメンテしているいくつかのOSSでは同じリポジトリからのプルリク(一般には悪意を持ったプルリクを出すことはないことが前提)に対してはプルリク時に全ジョブを自動実行させています。一方、forkされたリポジトリからのプルリクに対しては本Actionを使うことにより、一部のジョブについては自動実行させない([上記応用例](#応用例)のように、擬似的なコマンド入力によりワンクッションはさむ)ようにしています。これは第3者からのプルリク内容については、意識的に慎重にチェックする必要があると考えているためです。

興味が湧いた方は、Dependabotにおける`GITHUB_TOKEN`への権限に関する投稿記事[^1]を見ていただくとよいかもしれません。__紆余曲折を経て現在の仕様になっていること__に加え、__`GITHUB_TOKEN`に関するデフォルト権限はReadであること__がポイントです。記事内容から、セキュリティと運用面における柔軟性の両方を考慮していることが垣間見えないでしょうか？

今回紹介したActionsは1年半ほど前につくったものですが、最終的に現在の仕様になっているDependabotと同様に、セキュリティと運用面における柔軟性の両方を考慮した上で、第3者からのプルリクレビュー時には[上記応用例](#応用例)のワークフローを実行することを目的としてつくったActionです。

なお、GitHub Actionsのセキュリティに関しては`pull_request_target`に関するこちらの記事[^2]もあわせて読んでみると面白いかもしれません。

[^1]: https://github.blog/changelog/2021-10-06-github-actions-workflows-triggered-by-dependabot-prs-will-respect-permissions-key-in-workflows/ 

[^2]: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/