GitHub Actionsの自動PRが他のアクションを起動しない問題



# 背景

みなさん、GitHub Actionsは使っているでしょうか。最近ではDependaBotを使ってパッケージの最新化を監視し自動的にマージしたりとかなり進んだ機能を持っています。たくさんの機能がありついていけませんが、少しずつ触らないとと思っています。

先日、このツール群を使って、プロジェクトの依存ライブラリを自動的に最新状態に更新するようなワークフロー設定を試みました。設定はプルリクエストの自動作成とマージを通じてDockerイメージのビルドと公開までの一連の全工程を、完全自動化することを目指しました。設定を終え、マージも自動で完了して下記の通り問題ないように見えます。この時点で大分満足しています。

![Screenshot 2024-05-06 at 13.07.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/dbf9eee4-2b3e-547d-328a-7e3c5fe51676.png)

しかし、実際にはマージ後にトリガーするはずのDockerイメージのビルドとプッシュを行うワークフローが、予定通りに起動していないという問題が発生していました。

# 課題

この問題の原因は、Dependabotによるプルリクエストの自動マージ後に予定されていたDockerのビルドとプッシュのアクションがトリガーされなかったことでした。この問題の根本原因は、GitHub Actionsのセキュリティポリシーにあり、自動化されたプロセスによる無限のループや潜在的な悪用を防ぐための措置のようです。コミュニティでも意見交換と解決方法が共有されていますので、せっかくなのでDockerイメージのプッシュまでやってみます。


# 解決方法

## パーソナルアクセストークンを使用する
GithubActionsでは、標準的にGithubの操作をするためのトークン`secrets.GITHUB_TOKEN`が使用可能で、リポジトリのほとんどの操作が可能です。実際プルリクエストを操作するためにこのトークンを使用しています。しかし、前述の理由からこのトークン経由からの操作はアクションを経由したトリガーとみなされ、他の設定しているワークフローを起動することができません。

そこで、パーソナルアクセストークン(PAT)を使用することで、自動生成されたプルリクエストから他のワークフローをトリガーすることが可能になります。私が試した方法の中で最小限の変更で修正可能でかつ、標準的な回避策としてGitHubによって推奨されています。手順は以下の通りです：

1. [GitHubの設定](https://github.com/settings/tokens)で新しいPATを生成します
1. トークン生成時には以下の権限を有効にします：
   - `repo` (プライベートリポジトリの完全な制御)
   - `read:org`
   - `read:discussion`
    
    ![Screenshot 2024-05-06 at 2.08.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/09dddeb6-df4a-55c0-52d9-e9438e70a8c6.png)
1. 生成したトークンをリポジトリのSettings > Secrets and variablesから`REPO_SCOPED_TOKEN`として追加する![Screenshot 2024-05-06 at 2.12.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/f0fd5d5a-cbd9-c040-b9f2-b14ef6aa5768.png)
![Screenshot 2024-05-06 at 2.13.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/43b123e1-0170-e73e-5a89-bcb1507fd6d3.png)

1. ワークフローの定義で、`${{ secrets.GITHUB_TOKEN }}`の代わりに`${{ secrets.REPO_SCOPED_TOKEN }}`を使用します

      ```yaml
      - name: Approve and enable auto-merge for Dependabot PRs
        if: |
          ${{ ( steps.metadata.outputs.package-ecosystem == 'hex' && steps.metadata.outputs.update-type == 'version-update:semver-patch' ) || steps.metadata.outputs.package-ecosystem == 'github-actions' }}
        run: |
          gh pr review --approve "$PR_URL"
          gh pr edit "$PR_URL" -t "(auto merged) $PR_TITLE"
          gh pr merge --auto --merge "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          PR_TITLE: ${{ github.event.pull_request.title }}
          GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }} ⭐️変更
      ```
1. 自身によってプルリクエストが操作されたように見えますが、実際には自動的に完了しています
![Screenshot 2024-05-06 at 3.16.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/d1f20582-2dcb-d49b-2670-79bc5e01741d.png)
1. この後、mainへのpushトリガーを設定しているワークフローが自動的にトリガーします

画像の通り、PATを使用すると、自動生成されたプルリクエストがGitHub Actionsではなく、トークンの所有者である個人ユーザーによって作成されたものと見なされます。そのため、リポジトリのポリシーによっては、このユーザーが変更をリクエストしたりプルリクエストを承認したりすることができなくなる可能性があります。


## その他の解決方法

公式サイトでは他にも下記のような解決方法を提供しています。

1. **デフォルトのGITHUB_TOKENを使用する方法**
   - プルリクエストを作成して、手動で一度閉じてから再度開くことで`on: pull_request`ワークフローを起動し、チェックを追加します。誤ってチェックなしでプルリクエストをマージすることを防ぐために、ブランチ保護ルールを使用します。
1. **SSH（デプロイキー）を使用してプルリクエストブランチをプッシュする方法**
   - デプロイキーはリポジトリごとに設定できるため、PATを使用するよりも安全だと言えます。しかし、この方法では`on: push`ワークフローのみがトリガーされます。
1. **マシンアカウントを使用して、そのフォークからプルリクエストを作成する方法**
   - これは最も安全な方法です。PATはマシンアカウントのフォークのみにアクセス許可を与えるため、メインリポジトリには影響しません。この方法では`on: pull_request`ワークフローが起動しますが、フォーク内のプッシュイベントによっては`on: push`ワークフローは起動しません。
1. **GitHubアプリを使用してトークンを生成する方法**
   - GitHubアプリによって生成されたトークンはPATを使用するよりも安全です。GitHubアプリのアクセス権限はより細かく設定でき、アプリがインストールされているリポジトリにのみスコープされます。この方法では`on: push`と`on: pull_request`の両方のワークフローがトリガーされます。

詳細は下記を確認ください。

https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs

# さいごに

お疲れ様でした。ワークフローは構成要素が多く全てを把握しづらいと思います。公開リポジトリにdockerイメージ公開までのワークフローをおいていますので参考にしてください。リポジトリは下記のワークフローから構成される、最小限の構成を持っていますので、同じような要件を満たしたい新規プロジェクトの下敷きにしてもいいと思います。

* **dependabot update**:
    * 毎日ccxtの更新有無を確認
    * 更新があればmainへのプルリクエストを発行
* **dependabot auto merge**: 
    * botから発行されたプルリクエストを見つけたらトリガーする
    * 自動的にdockerイメージをビルド&テストする
    * テストを通過したらプルリクエストを承認・マージする
* **docker build and test**: 
    * mainブランチにpush(変更があった)時にトリガー
    * dockerイメージをビルドしてDockerHubにpush

https://github.com/sammrai/fetch_ohlcv


# 参考
https://github.com/orgs/community/discussions/65321

https://github.com/peter-evans/create-pull-request/issues/48