GitHub Actionsのキャッシュを読み取り専用にする方法|cache-modeでジョブ別に保存権限を制御

GitHub Actionsのキャッシュを読み取り専用にするには、.github/workflows 配下のワークフローYAMLに cache-mode: read を追加します。ワークフロー全体に適用できるほか、jobs.<job_id>.cache-modeでジョブ単位に上書きできます。ジョブ側の設定が優先されるため、全体は読み取り専用にし、信頼できるキャッシュ更新ジョブだけ保存を許可する構成が基本です。

cache-modeは2026年9月10日にGitHub.comの全プランで一般提供されました。キャッシュの復元と保存を別々に制御でき、キャッシュポイズニング対策として最小権限を適用できます。([GitHub Blog][1])

目次

最初に結論:cache-modeをreadに設定する

ワークフロー内のすべてのジョブでキャッシュ保存を禁止したい場合は、cache-mode: readをトップレベルに記述します。

name: CI

on:
  push:
  pull_request:

cache-mode: read

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Restore npm cache
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            npm-${{ runner.os }}-

      - run: npm ci
      - run: npm test

この設定では、testジョブは既存キャッシュを復元できますが、新しいキャッシュは保存できません。

トップレベルのcache-modeは、ワークフロー内のすべてのジョブに適用されます。ただし、個別のジョブにjobs.<job_id>.cache-modeが設定されている場合は、ジョブ側の値が優先されます。([GitHub Docs][2])

cache-modeで指定できる4つの設定値

cache-modeでは、キャッシュの復元と保存を次の4段階で制御できます。

設定値キャッシュの復元キャッシュの保存主な用途
read可能不可テスト、Lint、プルリクエストの検証
write可能可能信頼できるブランチのビルド
write-only不可可能クリーンな環境からキャッシュを生成する専用ジョブ
none不可不可デプロイ、署名、キャッシュ不要のジョブ

([GitHub Docs][2])

特に間違えやすいのが、writeとwrite-onlyの違いです。

writeは、既存キャッシュを復元したうえで、新しいキャッシュも保存できます。一方、write-onlyは保存専用であり、既存キャッシュを復元しません。

キャッシュを利用しながら更新したい通常のビルドにはwrite、古いキャッシュを一切取り込まずに新しいキャッシュを作りたいジョブにはwrite-onlyが適しています。

ジョブごとにキャッシュ保存権限を変更する

実務では、ワークフロー全体をreadにして、キャッシュ更新が必要なジョブだけwriteまたはwrite-onlyにする構成が安全です。

次の例では、テストジョブは読み取り専用とし、mainブランチへのpushで実行されるキャッシュ生成ジョブだけ保存を許可しています。

name: CI

on:
  push:
    branches:
      - main
  pull_request:

cache-mode: read

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Restore npm cache
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

      - run: npm ci
      - run: npm test

  cache-warm:
    needs: test
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    cache-mode: write-only

    steps:
      - uses: actions/checkout@v6

      - name: Prepare npm cache
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

      - run: npm ci

この構成には、次の利点があります。

  • プルリクエストのテストからキャッシュを保存できない
  • mainブランチのテスト成功後だけキャッシュを生成できる
  • write-onlyにより、キャッシュ生成ジョブ自身は既存キャッシュを復元しない
  • 保存権限をワークフロー全体へ広げずに済む

キャッシュ生成ジョブでも既存キャッシュを利用したい場合は、write-onlyをwriteへ変更します。

readにするとキャッシュ保存処理は失敗するのか

cache-mode: readのジョブでactions/cacheが保存を試みても、通常はジョブ全体が失敗するわけではありません。

許可されていないキャッシュ操作はスキップされ、次のように扱われます。

  • 復元が禁止されている場合はキャッシュミスとして扱われる
  • 保存が禁止されている場合は保存処理だけが行われない
  • 情報メッセージがログに記録される
  • ステップやワークフローはそのまま続行する

有効な設定値は、ランナー上のACTIONS_CACHE_MODE環境変数にも反映されます。想定どおりのモードになっているか調査するときに利用できます。([GitHub Docs][2])

意図をさらに明確にしたい場合は、読み取り専用ジョブでactions/cache/restoreを使用する方法もあります。ただし、cache-mode: readを設定していれば、キャッシュサービス側でも保存は制限されます。

cache-modeを省略した場合の既定値

cache-modeを指定していないワークフローでは、トリガーの信頼度に応じてreadまたはwriteが自動的に適用されます。

トリガーの区分cache-mode省略時の実効値
信頼されたトリガーwrite
低信頼トリガーread

GitHubのドキュメントでは、デフォルトブランチのキャッシュへ書き込める信頼されたトリガーとして、主に次のイベントが挙げられています。

  • push
  • workflow_dispatch
  • repository_dispatch
  • delete
  • registry_package
  • page_build
  • schedule

一方、pull_request_target、issue_comment、workflow_runなど、外部ユーザーの操作や入力の影響を受ける可能性があるイベントは、デフォルトブランチのキャッシュに対して原則読み取り専用になります。([GitHub Docs][3])

既存のワークフローにcache-modeを追加しなくても、従来の安全側の既定動作は継続します。ただし、権限の意図をYAML上で明確にし、再利用ワークフローへの権限伝播を確実に制限するには、明示的な設定が有効です。([GitHub Blog][1])

pull_requestは特別な扱いになる

通常のpull_requestイベントは、pull_request_targetと同じ扱いではありません。

pull_requestで生成されたキャッシュは、refs/pull/.../mergeというプルリクエスト固有のマージ参照にスコープされます。そのキャッシュは、デフォルトブランチや別のプルリクエストから復元できないため、デフォルトブランチのキャッシュ書き込み制限とは別の仕組みで隔離されています。([GitHub Docs][3])

ただし、ワークフローを見ただけで権限を判断しやすくするため、プルリクエストの検証ジョブにはcache-mode: readを明示する運用も有効です。

低信頼イベントにwriteを設定するときの注意点

次のようにpull_request_targetでwriteを明示すると、GitHubが適用する読み取り専用の既定値を上書きします。

on:
  pull_request_target:

cache-mode: write

この設定は構文上可能ですが、キャッシュポイズニングの危険性が高まります。GitHub Actionsは、低信頼トリガーにwriteまたはwrite-onlyを明示した場合、警告を表示します。([GitHub Blog][1])

キャッシュポイズニングとは、攻撃者の影響を受けるワークフローが不正なファイルをキャッシュへ保存し、そのキャッシュを後から権限の強いワークフローが復元してしまう攻撃です。復元されたスクリプト、実行ファイル、ビルド成果物などが後続処理で使用されると、意図しないコードが実行される可能性があります。([GitHub Docs][3])

低信頼イベントでキャッシュが必要な場合は、次の構成を優先します。

  • 低信頼イベントのジョブはreadにする
  • pushなど信頼できるイベントでキャッシュを更新する
  • キャッシュ更新ジョブでは外部から渡されたコードや入力を処理しない
  • デプロイや署名など重要なジョブではnoneを検討する
  • キャッシュ対象にトークン、認証情報、秘密鍵を含めない

readは「安全なキャッシュだけを読む」という意味ではない

cache-mode: readは、そのジョブによるキャッシュ保存を禁止する設定です。復元されるキャッシュの内容が安全であることを保証する機能ではありません。

別のワークフローが不正なキャッシュを保存していれば、readのジョブがそのキャッシュを復元する可能性は残ります。また、GitHub Actionsのキャッシュは署名や内容検証が行われる仕組みではありません。([GitHub Docs][3])

そのため、次のようなジョブではreadではなくnoneが適しています。

  • 本番環境へのデプロイ
  • コード署名やパッケージ署名
  • リリース成果物の最終生成
  • キャッシュされた実行ファイルを信用できない処理
  • 外部リポジトリ由来のワークフローを呼び出す処理

**保存を禁止したいならread、復元も保存も禁止したいならnone**と判断すると分かりやすくなります。

再利用ワークフローのキャッシュ権限を制限する

再利用ワークフローを呼び出すジョブにも、cache-modeを設定できます。

jobs:
  shared-ci:
    uses: example-org/shared-workflows/.github/workflows/ci.yml@v1
    cache-mode: read

呼び出し側で明示したcache-modeは、呼び出された再利用ワークフローの上限になります。呼び出し側がreadしか許可していないのに、再利用ワークフロー側がwriteを要求すると、ワークフローは開始されず、検証エラーになります。([GitHub Docs][2])

readとwrite-onlyも、単純な強弱関係ではありません。

  • readは復元だけを許可する
  • write-onlyは保存だけを許可する

権限が重ならないため、呼び出し側がread、呼び出し先がwrite-onlyという組み合わせも、上限を超えた要求として扱われます。([GitHub Docs][3])

呼び出し側ではcache-modeを明示する

再利用ワークフローでは、呼び出し側のcache-modeを省略しないことが重要です。

GitHubのドキュメントによると、呼び出しジョブに明示的なcache-modeがなく、低信頼トリガーによる実効既定値だけがreadになっている場合、呼び出された再利用ワークフローがwriteを明示的に要求できるケースがあります。確実に読み取り専用へ制限するには、呼び出しジョブにcache-mode: readを記述します。([GitHub Docs][3])

実際のワークフローを見直す手順

キャッシュを使用しているワークフローを探す

まず、.github/workflows配下からキャッシュ関連の設定を検索します。

git grep -nE 'actions/cache|cache:' -- .github/workflows

actions/cacheだけでなく、actions/setup-nodeやactions/setup-pythonなどのcacheオプションも確認します。

ジョブごとに必要な操作を分類する

各ジョブについて、次の2点を確認します。

  • 既存キャッシュを復元する必要があるか
  • 新しいキャッシュを保存する必要があるか

判断結果を4つのモードに当てはめます。

ジョブの役割推奨する設定
テストやLintで既存キャッシュだけ使うread
信頼できるビルドで復元と保存を行うwrite
クリーンな状態からキャッシュを生成するwrite-only
デプロイなどでキャッシュを一切使わないnone

ワークフロー全体をreadにする

複数のイベントや多数のジョブを含むワークフローでは、まずトップレベルをreadにします。

cache-mode: read

これにより、新しく追加されたジョブが意図せずキャッシュ保存権限を持つことを防ぎやすくなります。

保存が必要なジョブだけ上書きする

信頼できるトリガーで実行されるジョブだけ、writeまたはwrite-onlyへ変更します。

jobs:
  build:
    cache-mode: write

  test:
    cache-mode: read

  deploy:
    cache-mode: none

再利用ワークフローの呼び出し元も確認する

uses:で別のワークフローを呼び出しているジョブには、明示的なcache-modeを設定します。

特に低信頼イベントから呼び出される場合は、既定値に任せずreadまたはnoneを指定します。

よくある設定ミス

複数イベントのワークフロー全体をwriteにする

次の設定では、pushだけでなく、同じワークフローを起動するすべてのイベントにwriteが適用されます。

on:
  push:
  pull_request_target:

cache-mode: write

pull_request_targetに対する安全側の既定値も上書きされるため、避けるべき構成です。

ワークフロー全体はreadにし、push時だけ実行する特定ジョブをwriteにします。

permissionsだけでキャッシュ権限を制御しようとする

permissions:は主にGITHUB_TOKENの権限を制御する設定です。キャッシュの復元・保存権限は、専用のcache-modeで設定します。

permissions:
  contents: read

cache-mode: read

両方を設定することで、リポジトリ操作とキャッシュ操作を個別に最小権限化できます。cache-modeはスコープ付きのキャッシュトークンとしてキャッシュサービス側で強制されます。([GitHub Docs][2])

デプロイジョブをreadにして安心する

readはキャッシュを復元できます。デプロイ処理でキャッシュを一切利用させたくない場合は、noneを指定します。

jobs:
  deploy:
    cache-mode: none

キャッシュ保存がスキップされたらジョブも失敗すると思う

cache-modeによって禁止された保存処理は、通常はスキップされるだけです。

キャッシュが更新されていないのにワークフローが成功している場合は、ログとACTIONS_CACHE_MODEを確認します。([GitHub Docs][3])

GitHub Enterprise Serverで利用できるか

cache-modeの一般提供が明記されている対象は、GitHub.comの全プランです。GitHub Enterprise Serverについては、2026年9月10日の発表だけでは提供バージョンや時期を確定できません。([GitHub Blog][1])

GitHub Enterprise Serverを利用している場合は、導入済みバージョンのリリースノートとワークフロー構文ドキュメントにcache-modeが掲載されているかを確認してください。

cache-modeは全体をreadにして必要なジョブだけ緩める

GitHub Actionsのキャッシュを読み取り専用にする基本設定は、トップレベルのcache-mode: readです。

そのうえで、ジョブの役割に応じて権限を変更します。

  • 復元だけ必要ならread
  • 復元と保存が必要ならwrite
  • 保存だけ必要ならwrite-only
  • キャッシュを完全に禁止するならnone

複数のイベントを扱うワークフローでは、全体をreadにして、信頼できるpushなどで動くキャッシュ更新ジョブだけをwriteまたはwrite-onlyにする構成が適しています。

まず.github/workflows配下のキャッシュ利用箇所を洗い出し、各ジョブに本当に保存権限が必要かを確認してください。特にpull_request_targetなどの低信頼イベントと、再利用ワークフローの呼び出しジョブは、既定値に任せずcache-modeを明示することが重要です。
[1]: https://github.blog/changelog/2026-09-10-control-github-actions-cache-access-with-cache-mode/ “Control GitHub Actions cache access with cache-mode – GitHub Changelog”
[2]: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax “Workflow syntax for GitHub Actions – GitHub Docs”
[3]: https://docs.github.com/en/actions/reference/dependency-caching-reference “Dependency caching reference – GitHub Docs”

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次