GitHub Actions:「Permission to ... denied to github-actions[bot]」
ワークフローの中の git push が断られました。github-actions[bot] は GitHub が GITHUB_TOKEN に付けて見せる名前なので、push はジョブ自身のトークンで送られ、そのトークンがメッセージに出ているリポジトリに書き込めなかった、ということです。
見え方
remote: Permission to grafana/grafana.git denied to github-actions[bot]. fatal: unable to access 'https://github.com/grafana/grafana/': The requested URL returned error: 403 ##[error]The process '/usr/bin/git' failed with exit code 128
これは grafana #136263 の週1回のジョブのものです。1行目の名前を2つ読みます。「Permission to」のあとのリポジトリが push 先、「denied to」のあとのアカウントが git がサインインした相手です。自前のトークンで push したつもりなのに github-actions[bot] と出るなら、4へ進みます。
1. トークンが読み取りだけだった
- ジョブが少なく頼んでいた。grafana のジョブは
permissions: contents: readとだけ書いていて、最後のステップのpeter-evans/create-pull-requestはブランチを push する必要があります。GitHub のワークフロー構文のリファレンスには、どれかの権限を指定すると、指定しなかった権限はすべてnoneになる、とあります。procrastinate では、ワークフロー全体にcontents: readを足したことでカバレッジのジョブの push ができなくなり、push するのは main での実行だけだったので、プルリクエストのチェックは緑のままでした(procrastinate #1610)。 - 既定が読み取りだけ。Settings → Actions → General の「Workflow permissions」は、すべて読み書きか、
contentsとpackagesの読み取りだけのどちらかで、組織は後者を強制できます。permissionsを書いていないドキュメントのデプロイが、gemma #11 でこれで失敗していました。
contents: write はワークフロー全体でなく、push するジョブだけに付けます。gemma への直しの提案は、ドキュメントを1つ目のジョブで作り、gh-pages への push を2つ目のジョブでします。書き込みの権限を持つのはそのジョブだけで、プロジェクトのコードは動かしません:
jobs:
deploy:
needs: generate
permissions:
contents: write
2. ワークフローに何を書いても読み取りだけのトークンになる実行
- フォークからの
pull_request。ワークフロー構文のリファレンスには、フォークにはpermissionsでふつう書き込みの権限を与えられない、とあります。例外は管理者が「Send write tokens to workflows from pull requests」をオンにした場合で、この設定はプライベートのリポジトリにしかありません。lazypredict #579 では、プルリクエストごとにドキュメントのプレビューをgh-pagesへ push していたので、フォークからのプルリクエストはどれも赤いチェックになっていました。そこに書かれた直しは、ブランチがこのリポジトリにあるときだけプレビューを動かすことです:if: github.event.pull_request.head.repo.full_name == github.repository
- Dependabot が
push・pull_request・pull_request_review・pull_request_review_commentで始めた実行。GitHub はこれをフォークと同じに扱い、トークンは読み取りだけ、シークレットは Dependabot のシークレットだけになります。フォークと違い、こちらはpermissionsでトークンを上げられます。Dependabot のシークレットに無いシークレットはこの実行では空なので、github.tokenに切り替わるステップは bot として push します。carbon_theme #77 では、push 用のトークンがどちらのシークレットにも無く、ジョブはcontents: readでした。直しはそのジョブにcontents: writeを付けるものでした。
3. push 先が別のリポジトリだった
GitHub のドキュメントには、トークンの権限はワークフローがあるリポジトリに限られる、とあります。permissions の行では変えられません。「Permission to」のあとの名前を、自分のリポジトリと見比べます:
- ドキュメントのサイトが別の
owner.github.ioリポジトリにある(endless #552)。 - コントリビューターのフォークのブランチ。HttpArena は、保存したベンチマークの結果を
contents: writeのトークンでプルリクエストのブランチへ push し返します。組織が持つフォークでは push が断られました。メンテナーによる編集を許可できるのは、ユーザーが持つフォークだけだからです。ステップは|| echo "Warning: ..."で終わっていたので、ジョブは成功し、プルリクエストは結果なしでマージされました(HttpArena #1702)。フォークのブランチへ push するのに要ることは、GitHub:フォークのプルリクのブランチに push できないにあります。
別のリポジトリには、GitHub App のトークン(actions/create-github-app-token)か、そのリポジトリに書き込める fine-grained の個人アクセストークンをシークレットに入れて使います。そのあとで4も確かめます。checkout が自分のトークンを送り続けることがあるからです。
4. 自前のトークンはあったのに、checkout のトークンが送られた
actions/checkout は、persist-credentials: false にしない限りトークンをローカルの git の設定に保存し、その保存されたヘッダーは push の URL に書いたトークンより優先されます。この2か月にマージされた直しが3つあります:
- openai-ads-toolkit #16:
SPLIT_TOKENを入れた URL でミラーのリポジトリへ push しても、どの push も bot として送られていました。 - hriv #1645:Dependabot のワークフローが push 用に App のトークンを作っても、push は読み取りだけの
GITHUB_TOKENで認証されていました。 - endless #552:checkout を v2 から v7 に上げたあと、ドキュメントのデプロイが壊れました。v6.0.0 から checkout は認証情報を別のファイルに置き、
includeIfの設定で読み込ませます。その設定は.git/worktrees/*にも効き、デプロイのアクションはワークツリーから push します。
checkout にトークンを保存させないか、自前のトークンを checkout に渡して、保存されるほうを自分のトークンにします:
- uses: actions/checkout@v7
with:
persist-credentials: false
# or
- uses: actions/checkout@v7
with:
token: ${{ secrets.DEPLOY_TOKEN }}
見分け方
remote: error: GH006: Protected branch update failed:トークンは書き込めたが、ブランチの保護が push を断りました。たとえば、プルリクエストしか受け付けないmainへ、フォーマットのジョブが直接 push した場合です(udistribution #198)。refusing to allow a GitHub App to create or update workflow ... without `workflows` permission:push が.github/workflowsの下のファイルを変えています。workflowsはワークフローがGITHUB_TOKENに与えられる権限に入っていないので、その権限を持つ App か、workflow のスコープを持つ個人アクセストークンが要ります(spikeforge-dashboard #61・詳しくは「refusing to allow a GitHub App to create or update workflow」)。- 同じ権限不足が API の呼び出しで起きると、「Resource not accessible by integration」になります。
GITHUB_TOKENでの push は通ったのにワークフローが動かないのは、仕様です。workflow_dispatch・repository_dispatchと一部のpull_requestのイベントを除き、このトークンが起こしたイベントは新しいワークフローの実行を作りません。
失敗したジョブを IntelliJ IDEA から見るなら
Pipeline Inbox for GitHub Actions Workflows は、Lesstep が作っている JetBrains IDE(2024.1 以降)のプラグインです。すべてのリポジトリの実行を、ジョブ・ステップと一緒に IDE のツールウィンドウに並べ、いまのブランチの実行はステータスバーに出ます。読むのは無料、失敗したジョブの再実行・キャンセル・ワークフローの実行・デプロイのレビューは Pro(月 US$1.50・30日の無料試用つき)です。
GitHub と GitHub Actions は GitHub, Inc. の商標、IntelliJ IDEA は JetBrains s.r.o. の商標です。このページは GitHub, Inc.・JetBrains のいずれとも提携しておらず、承認も受けていません。
ほかに:「could not read Username for 'https://github.com'」 · 「Resource not accessible by integration」 · 「API rate limit exceeded for installation」 · 「Input required and not supplied」 · IntelliJ IDEA で使える GitHub Actions のプラグインの比較 · English