10 сентября 2026 года GitHub объявил общую доступность cache-mode для GitHub Actions. Новый ключ позволяет явно ограничить, может ли workflow или отдельный job читать кэш, записывать его, делать оба действия или полностью работать без доступа к кэшу.
Изменение выглядит небольшим, но касается важной границы доверия в CI/CD. Кэш ускоряет сборки, однако вредоносное или непроверенное содержимое кэша может попасть в более привилегированный workflow. Поэтому GitHub связывает cache-mode с принципом least privilege и отдельно предупреждает о риске cache poisoning.
Что такое cache-mode в GitHub Actions
cache-mode задаётся на уровне всего workflow или конкретного job. GitHub применяет ограничение через scoped cache tokens: job не может восстановить или сохранить кэш сверх разрешённого режима.
| Режим | Restore | Save | Типичный сценарий |
|---|---|---|---|
read |
Да | Нет | Проверки из недоверенного контекста |
write |
Да | Да | Доверенная сборка, которая поддерживает кэш |
write-only |
Нет | Да | Job создаёт кэш, но не должен потреблять существующий |
none |
Нет | Нет | Job вообще не нуждается в GitHub Actions cache |
Если режим не указан, GitHub выбирает значение по умолчанию в зависимости от типа события. Для low-trust triggers действует более ограничительная модель доступа.
Почему кэш вообще становится security-границей
Кэш GitHub Actions часто содержит зависимости, промежуточные файлы сборки, артефакты package manager или скомпилированные данные. Workflow, который восстанавливает такой кэш, фактически доверяет его содержимому настолько, насколько доверяет процессу, который этот кэш создал.
Если низкодоверенный workflow способен записать данные в область кэша, которую позже читает привилегированный workflow, появляется цепочка для cache poisoning. В худшем случае доверенная сборка может использовать подменённые файлы и выполнить код в контексте, где доступны дополнительные права или secrets.
GitHub подчёркивает: восстановленный кэш нужно рассматривать как недоверенный ввод. В кэше также не следует хранить секреты и чувствительные данные.
Безопасный default для low-trust triggers
Для событий с низким уровнем доверия GitHub применяет read-only доступ к кэшу default branch. В документации среди таких сценариев отдельно рассматриваются pull_request_target, issue_comment и workflow_run.
Это позволяет job использовать уже существующий кэш, но не создавать или перезаписывать записи, способные повлиять на другой workflow. Если save запрещён эффективным режимом, операция пропускается; сам job из-за этого не обязан падать.
Главная ловушка: явный write отменяет безопасное ограничение
Самая важная часть нового механизма — cache-mode может не только усилить, но и ослабить защиту. Если для low-trust trigger явно задать write или write-only, GitHub разрешит запись и покажет warning annotation.
То есть конфигурация ниже требует отдельного security review:
on:
pull_request_target:
cache-mode: write
Такая запись не означает автоматическую уязвимость, но она возвращает возможность сохранять кэш из контекста, который GitHub по умолчанию считает низкодоверенным. Если job обрабатывает код из fork или другой непроверенный ввод, риск становится существенно выше.
Как использовать read для проверки pull request
Для job, которому нужен кэш только ради ускорения тестов, безопаснее явно оставить чтение:
cache-mode: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ hashFiles('**/package-lock.json') }}
- run: npm ci
- run: npm test
Тогда job может получить существующий кэш, но не публикует новый. Если кэш нужно обновлять, GitHub рекомендует делать это из доверенного workflow, например запускаемого событием push.
Job-level cache-mode даёт более точную модель прав
Необязательно назначать один режим всей автоматизации. Значение на уровне jobs.<job_id>.cache-mode переопределяет workflow-level настройку для конкретного job.
cache-mode: read
jobs:
test:
runs-on: ubuntu-latest
cache-mode: read
trusted-build:
runs-on: ubuntu-latest
cache-mode: write
Практическая идея проста: не давать право записи всем job только потому, что оно требуется одному этапу сборки. Это тот же least-privilege подход, который применяют к permissions, токенам и secrets.
Что происходит с reusable workflows
cache-mode распространяется и на reusable workflows. Явно установленное ограничение вызывающего job задаёт верхнюю границу доступа для вызываемого workflow.
Например, если caller разрешает только read, reusable workflow не может повысить доступ до write. GitHub отклонит несовместимую конфигурацию ещё до выполнения. Это важно для общих корпоративных workflow, которые используются десятками репозиториев.
Когда полезен write-only
write-only — менее очевидный режим. Он запрещает restore, но разрешает save. Такой вариант подходит для отдельного доверенного job, задача которого — подготовить свежий кэш для последующих запусков, не используя существующее содержимое как входные данные.
Это помогает разорвать обратную зависимость: job создаёт состояние, но сам не доверяет ранее записанному кэшу.
Когда стоит поставить none
Если job не использует кэш, лучше запретить доступ явно через none. Это не ускорит workflow и не заменит другие permission-настройки, но уменьшит доступную поверхность.
Особенно полезно делать это в служебных jobs, которые только проверяют метаданные, публикуют статус или выполняют действия, не связанные с dependency cache.
Что проверить в существующих GitHub Actions
- какие workflows используют
actions/cacheили встроенное caching package managers; - какие events запускают эти workflows;
- есть ли
pull_request_target,issue_commentилиworkflow_run; - обрабатывается ли в таком job код или ввод из недоверенного источника;
- каким jobs реально требуется право save;
- можно ли вынести обновление кэша в доверенный
push-workflow; - какие reusable workflows вызываются и какое cache permission они получают;
- не хранятся ли в cache секреты или чувствительные файлы.
cache-mode не заменяет обычные permissions
Новый ключ управляет именно GitHub Actions cache. Он не заменяет ограничения GITHUB_TOKEN, permissions репозитория, environment protection, secrets или sandboxing runner.
Поэтому аудит CI/CD лучше проводить слоями: права токена, события запуска, доступ к кэшу, работа с secrets, доверие к checkout-коду, third-party actions и тип runner. Отдельный полезный шаг — проверять dependencies и supply chain. Недавно я разбирал доступ Dependabot к приватным GitHub Packages без PAT и обновления CodeQL 2.27.
Что это меняет для DevOps-практики
Раньше команда могла контролировать permissions токена достаточно подробно, но cache access оставался менее явной частью модели. С cache-mode кэш становится отдельным настраиваемым permission-like слоем.
Для больших репозиториев это особенно полезно вместе с reusable workflows и централизованными шаблонами. Можно зафиксировать безопасные defaults и выдавать write только тем jobs, где он действительно нужен. Для self-hosted GitHub-инфраструктуры похожий принцип контроля прав стоит применять и при обновлениях платформы — например, в материале о GitHub Enterprise Server 3.22.
Официальные источники
- GitHub Changelog — Control GitHub Actions cache access with cache-mode
- GitHub Docs — Workflow syntax: cache-mode
- GitHub Docs — Dependency caching reference
- GitHub Docs — Securely using pull_request_target
Итог
cache-mode делает доступ к GitHub Actions cache явным и позволяет применять least privilege отдельно для каждого workflow или job. Для обычной доверенной сборки write остаётся нормальным вариантом, но low-trust triggers лучше не наделять записью без конкретной причины и отдельной проверки.
Если нужно разобрать существующие GitHub Actions, reusable workflows, webhooks или автоматизацию CI/CD, можно описать задачу A.S Groups. Сначала стоит составить карту событий и прав, а уже затем менять production workflow.
Обсуждение
Вопросы и комментарии
Можно уточнить детали статьи или поделиться своим опытом. Первый комментарий проходит проверку.