【Github actions】DependabotのPull RequestでSecretsが参照できずワークフローがFailになった場合の対処

Dependabot のPull Request(以下PR)が作られた際に開始したGithub Actionsワークフローが Secrets を参照できずに失敗していたので原因を調べてみました。

f:id:moritamorie:20210317022417p:plain

2021/3/1から適用になった以下のUpdateが影響していて、 Dependabot から実行される Github Actionsワークフローは読み取りだけが可能な GITHUB_TOKEN のみ使うことができ、いかなる Secrets も使えなくなるという変更が原因でした。

github.blog

なので、例えばpushイベントトリガーで実行されるワークフローの中で Secrets として追加しておいたPersonal access tokensを使って、取得したカバレッジのサマリをコメントで追加したり、自動でラベルを追加するといった書き込み(write)権限が必要な場合は、ワークフローが落ちる状況になっていました。

結論

以下のように

  • dependabotから実行されされた場合はpull_request_targetトリガーの時のみ実行
  • dependabot以外から実行された場合は pull_request_targetトリガー以外の時に実行

するようにしました。

on: 
  push:
  pull_request_target:
  workflow_dispatch:

name: Test
jobs:
  test:
    runs-on: ubuntu-latest
    if: (github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]') || (github.event_name != 'pull_request_target' && github.actor != 'dependabot[bot]') 
    steps:
      - uses: actions/checkout@v2
        if: (github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]')
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0
      - uses: actions/checkout@v2
        if: (github.event_name != 'pull_request_target' && github.actor != 'dependabot[bot]')
        with:
          fetch-depth: 0
      - name: SonarCloud Scan
        uses: SonarSource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

actions/checkoutのオプションに ref: ${{ github.event.pull_request.head.sha }} がないと、 mainブランチをチェックアウトしてしまうようなので pull_request_targetの場合は同時にこのオプションを付けるようにすると良いようです。(参照

このように対応することに至った具体的な経緯を共有していきます。

失敗していた原因

実行結果の詳細を見るとSet the SONAR_TOKEN env variable.というエラーが発生しており、 Secrets に設定していた値が取れていないことが確認できました。

f:id:moritamorie:20210317025933p:plain

以下のリポジトリで、同様の状況を再現してみましたので、よろしければ参考にしてみてください。

Bump axios from 0.19.1 to 0.21.1 by dependabot · Pull Request #1 · moritamori/dependabot-testing · GitHub

対応方針の検討

主に以下の3つのドキュメント・Github issueを参照しました。

これらの情報から大きく分けて3通りの対応方法があることが分かりました。

また、①と②のどちらを適用するかは場合によって異なります。いずれの場合もwrite権限が付与され Secrets にアクセスできるようになる、という点は変わりません。

  • PR自体を更新する必要がある場合
    • => ②workflow_run
  • コメントやラベル等を追加しPRを構成するだけで更新しない場合
    • => ①pull_request_target

pull_request_target トリガーを使う

2021/2/19に公開されたGithubブログの記事 によると、write(書き込み)権限があるトークンが必要な場合、以下の2020/12/15に公開されたGithubブログの記事に書いているリスクを把握したうえで pull_request_target を使ってください、という記述があったのでリスクに関する記述を読んでみました。

リスクに関する記述1: 適用用途

pull_request_target トリガーに関して以下の記述がありました。

The reason to introduce the pull_request_target trigger was to enable workflows to label PRs (e.g. needs review) or to comment on the PR. The intent is to use the trigger for PRs that do not require dangerous processing, say building or running the content of the PR.

pull_request_targetトリガを導入した理由は、ワークフローでPRにラベルを付けたり(例:needs review)、PRにコメントを付けたりできるようにするためでした。このトリガーは、PRの内容を構築したり実行したりするような危険な処理を必要としないPRに使用することを意図しています。

今回遭遇したエラーは、この用途に該当するGithubワークフローで発生したものでした。

リスクに関する記述2: 注意点

pull_request_target トリガーの中でどのような処理を実行しても良いかを考えるうえで、以下の記述が参考になりました。

a workflow triggered on pull_request_target still has the read/write repository token in memory that is potentially available to any running program.

If the workflow uses actions/checkout and does not pass the optional parameter persist-credentials as false, it makes it even worse.

The default for the parameter is true. It means that in any subsequent steps any running code can simply read the stored repository token from the disk.

日本語にすると

pull_request_target でトリガーされたワークフローでは、メモリ内に読み取り/書き込み可能なリポジトリトークンが残っており、実行中のプログラムから利用できる可能性があります。

ワークフローが actions/checkout を使用していて、オプションのパラメータ persist-credentials を false にしていない場合は、さらに悪い状況になります。このパラメータのデフォルトはtrueです。

これは、後続のステップで、実行中のコードがディスクから保存されたリポジトリトークンを単純に読み取れることを意味します。リポジトリへの書き込みアクセスやシークレットが必要ない場合は、pull_request トリガーを使用してください。

という感じかと思います。

workflow_run を使う

リスクに関する記述1: 適用用途

workflow_run トリガーに関して以下の記述がありました。

Together with the pull_request_target, a new trigger workflow_run was introduced to enable scenarios that require building the untrusted code and also need write permissions to update the PR with e.g. code coverage results or other test results.

pull_request_target と共に、新しいトリガ workflow_run が導入され、信頼できないコードの構築を必要とするシナリオや、コードカバレッジの結果やその他のテスト結果などで PR を更新するための書き込み権限を必要とするシナリオを可能にしました。

Dependabot によって実行される Github actions ワークフローの中でPRを更新するようなケースでは workflow_run を使うと良さそうです。

リスクに関する記述2: 注意点

workflow_run トリガーの中でどのような処理を実行しても良いかを考えるうえで、以下の記述が参考になりました。

To do this in a secure manner, the untrusted code must be handled via the pull_request trigger so that it is isolated in an unprivileged environment.

これを安全に行うためには、信頼できないコードは、権限のない環境で隔離されるように、pull_requestトリガを介して処理されなければなりません。

③Dependabotを諦めてRenovateに乗り換える

対応が煩雑なので Renovate への置き換える方もでてきているようです、合わせて検討すると良いかもしれません。

github.com

対応したコード

用途に適した対応が①pull_request_target トリガーを使うだったので、Github issueコメント記載されていた対応コードのサンプルを参考に対応してみました。

Dependabot cant read secrets anymore · Issue #3253 · dependabot/dependabot-core · GitHub

ワークフローが正常に動くようになることを確認した検証用リポジトリも共有しておきます。 github.com

private registriesを使う場合

2021/3/15に以下のリリースがあり、GitHub Packagesやnpm等のプライベートレジストリを使ってパッケージの更新を行っている場合はよりセキュアに Secrets を使うことができるようになったので、こちらの方法と併せて対応すると良さそうです。

github.blog

Dependabot secretsの検証

もしかすると、 private registriesで使用可能な以下の DependabotSecrets を設定することで、Github actions ワークフローから参照できるようにならないかな、と思って試してみたのですがうまくいきませんでした。dependabot.ymlの中からしか参照できないようです。

f:id:moritamorie:20210317125542p:plain

Github actions ワークフローで行っている Secrets を使った処理を Dependabot の機能に移せる場合に、 Dependabot のprivate registriesの使用を検討すると良さそうです。

検証した際のGithubリポジトリを以下に記載しておきます。

Bump axios from 0.19.1 to 0.21.1 by dependabot · Pull Request #1 · moritamori/dependabot-testing3 · GitHub

参考資料