feat(cache): add cache-mode client behavior (read-denied warning + ACTIONS_CACHE_MODE skip)#2447
Draft
philip-gai wants to merge 11 commits into
Draft
feat(cache): add cache-mode client behavior (read-denied warning + ACTIONS_CACHE_MODE skip)#2447philip-gai wants to merge 11 commits into
philip-gai wants to merge 11 commits into
Conversation
Mirror the existing cache write-denied handling on the restore path. When the receiver refuses a download URL because the run's token has no readable cache scopes, it returns a twirp PermissionDenied (HTTP 403). The twirp client wraps that 403 in a generic Error, so the stable 'cache read denied:' prefix is embedded in the message rather than at the start. - Add CACHE_READ_DENIED_PREFIX and CacheReadDeniedError - Dispatch on the prefix in the restoreCacheV2 catch block (V2 only), log a policy-specific warning, and report a cache miss so the run continues - Add a test mirroring the write-denied coverage
Re-throw CacheReadDeniedError from an inner try/catch around GetCacheEntryDownloadURL and dispatch on typedError.name in the outer catch, matching how saveCacheV2 handles CacheWriteDeniedError.
Extend the read-denied handling to Cache Service v1 so GHES (which forces v1 via _apis/artifactcache) is covered when read-scope enforcement ships there. - Surface the receiver's error body message from getCacheEntry instead of a generic status-code error, so the cache read denied: prefix reaches callers - Re-throw CacheReadDeniedError from restoreCacheV1 and dispatch on it in the outer catch, mirroring restoreCacheV2 and the write-denied v1 handling - Add a v1 read-denied test
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves cache restore resilience by detecting policy-driven cache read denials (insufficient read permissions) and surfacing them as a clear core.warning while treating the restore as a cache miss so workflows continue.
Changes:
- Added read-denial detection via
CACHE_READ_DENIED_PREFIXand a dedicatedCacheReadDeniedErrorfor targeted handling. - Updated both cache restore implementations (v1 REST + v2 Twirp/gRPC) to reclassify read-denied failures into a single warning and continue as a miss.
- Adjusted v1
getCacheEntryto selectively surface the receiver’s denial message and added tests + release/version bumps.
Show a summary per file
| File | Description |
|---|---|
| packages/cache/src/internal/cacheHttpClient.ts | Surfaces receiver error message only for cache read denied: so restore paths can reclassify it. |
| packages/cache/src/cache.ts | Adds read-denied prefix + error type and handles read-denied restores as warning + cache miss for both v1/v2. |
| packages/cache/tests/restoreCache.test.ts | Adds v1 tests asserting warning behavior and cache-miss semantics for read denial. |
| packages/cache/tests/restoreCacheV2.test.ts | Adds v2 test asserting warning behavior and cache-miss semantics for wrapped read-denied errors. |
| packages/cache/tests/cacheHttpClient.test.ts | Adds tests ensuring getCacheEntry only surfaces body for read-denied cases. |
| packages/cache/RELEASES.md | Documents the 6.2.0 behavior change. |
| packages/cache/package.json | Bumps @actions/cache version to 6.2.0. |
| packages/cache/package-lock.json | Updates lockfile version metadata to 6.2.0. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Files not reviewed (1)
- packages/cache/package-lock.json: Generated file
- Files reviewed: 7/8 changed files
- Comments generated: 1
- Review effort level: Low
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR adds client-side cache-mode behavior to
@actions/cache. It combines two related pieces of work:ACTIONS_CACHE_MODEenvironment variable to skip cache operations the effective mode does not permit.Cache-mode values are
none | read | write | write-only(hyphenated). It is a partial lattice, not linear: readable modes = {read, write}, writable modes = {write, write-only}, none = neither. TheACTIONS_CACHE_MODEenv var is provided by the Actions runner, and is gated on the service side. When it is unset or unrecognized, behavior is identical to today (regression-safe).Read-denied warning
When the cache service denies a download because the token has no readable scopes, the run should continue with a clear warning instead of a confusing failure.
CacheReadDeniedErrorand the sharedcache read denied:prefix constant.core.warning, then returns a cache miss.cache write denied:) for consistency.ACTIONS_CACHE_MODE skip
Skip operations the effective cache-mode does not permit, before any tar or network work.
none,write-only).none,read).undefined); save skip returns the existing not-saved sentinel (-1). Neither throws.core.infoline per skip; extra detail (paths, key) is behindACTIONS_STEP_DEBUG.Rationale for skipping restore on
write-only: write-only tokens have no read scope, so a restore would be denied service-side and trip the read-denied warning. Skipping client-side avoids the wasted round-trip and gives a clearer message.Companion changes
ACTIONS_CACHE_MODEinto the step environment.Notes
packages/cache/RELEASES.mdupdated under the 6.2.0 entry.https://github.com/github/actions-persistence/issues/1168