GitHub Actionsでgit pushした時の「The requested URL returned error: 403」に対応した話

# この記事は？
- すごく久々にGitHub Actionsを触った
- Actionsを流している中で、「変更差分が生まれたものをリポジトリに保存したい」となった
- その中で The requested URL returned error: 403 で引っかかった
- あれこれ引っかかったので自分用のメモとしても残すことにした

# ちょっとだけ経緯説明

## なぜ、Actionsの中でgit pushしたかったか？

### 元々やりたかったこと

JavaのプログラムをGitHub Actionsでビルドして、そのビルド結果を特定の場所に置く。  
置いたファイルを別のツールが取得し、そのツールがAWSにデプロイする... ということがやりたかった。  
要はCI/CDである。

### 正攻法を取ると

公式ドキュメントの[ワークフロー データを成果物として保存する](https://docs.github.com/ja/actions/using-workflows/storing-workflow-data-as-artifacts)に沿って成果物を格納し、[ワークフローの成果物をダウンロードする](https://docs.github.com/ja/actions/managing-workflow-runs/downloading-workflow-artifacts) に沿って、GitHub CLIで落とすのが良いと思います。

### じゃあなんで正攻法にしなかったの？

利用するCDのツールが GitHub のWebhookで飛ばされてくるイベントを解釈してから動き出すのですが、このツールでは残念ながら「GitHub Actionsの処理が完了したこと」をトリガーにすることができなかったのです。  
そのためやや美しくはないのですが、「GitHub Actionsでビルドした成果物を再度、リポジトリの特定のディレクトリに格納することでpushのイベントを起こし、それをトリガーとしてファイル取得をする」とすることにしました。

# で、結局どんな設定をすればいいの？

## まずはActions全体で書き込み権限をもらえ

リポジトリの設定で、 ［Settings］>［Actions］> ［General］ に遷移すると一般設定があるので、ここで一番上を選んで読み書きの権限をActionsに付与してあげてください。
画像中では一番下のチェックボックスにチェックが入っていますが、pull requestに関わる処理を行う時に必要となるだけで、今回の話題としてはチェック外れていても大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129674/f6a5cd59-4281-5c12-ff34-3b4b6e607921.png)

## pushするユーザを設定せよ

yamlの中で、git pushするためのgitのユーザ指定を行います。
ユーザ名、メールアドレスはenvとしてまとめるのが綺麗だと思いました。
その際、好みにもよりますが、調べる限り、次の設定が良さそうです。

```text
env:
  GITHUB_MAIL: 41898282+github-actions[bot]@users.noreply.github.com
  GITHUB_NAME: github-actions[bot]
```

実際に自身のユーザアカウントを使うこともできますが、この設定だとGitHub Actionsで動いたものとして区別出来るので視認性という意味で良さそうです。

## pushするための書き込み権限を付与せよ

Actionsでの動作にはワークフロー実行時に発行されるアクセストークン(GITHUB_TOKEN)が使用されます。
[GITHUB_TOKENについての公式ドキュメント](https://docs.github.com/ja/actions/security-guides/automatic-token-authentication) にもあるように、権限は狭いものになっています。
もっと言えば、2023年2月以降に作成されたリポジトリではデフォルトのパーミッションが読み取りのみに設定されているようです。
See: [GitHub Actions - Updating the default GITHUB_TOKEN permissions to read-only | GitHub Changelog](https://github.blog/changelog/2023-02-02-github-actions-updating-the-default-github_token-permissions-to-read-only/)

GITHUB_TOKENはジョブが失敗するタイミング、または最大24時間でその権限は失効するとのことですが、その権限は利用するAPIに紐づいて設定する必要があるようです。

つまり。こちらのAPI一覧を見つつ、必要なものに対して権限をwriteにしてあげることになります。
https://docs.github.com/en/rest/overview/permissions-required-for-github-apps?apiVersion=2022-11-28#contents

今回の記事目的からはpushに関するものなので、contentsですが、場合によってはそれ以外の設定も必要になるかと思います。

```text
permissions:
  contents: write
```

こちらの記事のように、えいやっと全部writeにしてしまうのも良いのですが、使うものに合わせて権限付与する方が望ましいです。

https://qiita.com/robozushi10/items/0b91739a685d50303a73 

## pushのjobを書け

あとはjobを書くだけです。
次の誰かのために書き方サンプル置いておきます。このサンプルはmainにpushするものになっているので、ブランチ戦略に合わせて書き換えが必要なことにご注意ください。

```
name: Java build with Gradle

on:
  push:
    branches: [ "main" ]

permissions:
  contents: write

env:
  OUTPUT_WAR_FILE: output.war
  GITHUB_MAIL: 41898282+github-actions[bot]@users.noreply.github.com
  GITHUB_NAME: github-actions[bot]

jobs:
  build:
    runs-on: ubuntu
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    - name: Set up JDK 17
      uses: actions/setup-java@v3
    - name: Setup and execute Gradle 'clean' and 'build' task
      uses: gradle/gradle-build-action@v2
      with:
        arguments: clean build
    - name: Set current datetime as env variable
      env:
        TZ: 'Asia/Tokyo'
      run: echo "CURRENT_DATETIME=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
    - name: Commit artifact
      run: |
        git remote set-url origin https://github-actions:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
        git config --local user.email ${{ env.GITHUB_MAIL }}
        git config --local user.name ${{ env.GITHUB_NAME }}
        cp -p build/libs/${{ env.OUTPUT_WAR_FILE }} output/${{ env.OUTPUT_WAR_FILE }}
        echo -e ${{ env.CURRENT_DATETIME }} > ${{ env.DELIVERY_DIR }}/build_date.txt
        git add output/${{ env.OUTPUT_WAR_FILE }}
        git add output/build_date.txt
        git commit -m ":robot: GitHub Actionsによるビルド結果格納:${{ env.CURRENT_DATETIME }}"
        git push origin main

```

こんな感じのcommitが増えます。commit message に `:robot:` を入れておくと絵文字でメッセージ送れるので、自動化されてる感がちょっと増す気がします。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129674/c39ada11-c223-5e9a-1fb9-e6e3fd41b2fa.png)



# TIPS

APIからいちいち権限探すのめんどくせーな、と思っていたら、わりかし最近に「権限を教えてくれる仕組み」ができたpublic betaで公開された様子。
See: https://developer.mamezou-tech.com/blogs/2023/06/28/set-minimum-permissions-to-github-actions-workflow/