Skip to main content
ISSUE-717MediumThird-party actions

Conditional cache on a release path could not be resolved

Control: Release workflows must not restore an untrusted cacheยท Config key: releaseWorkflowsMustNotRestoreUntrustedCache

๐Ÿ“‹ What is this?

A release or publish job enables or disables a build cache through a GitHub expression Plumber cannot resolve per trigger: an opt-in enable input or a default-mode disable input outside the github.event_name ==/!= '<event>' shapes. The cache may be off exactly on the runs that publish - the safe pattern - or on for them; the expression does not say which statically.

โš ๏ธ Impact

If the expression yields a cache manager on the trigger that publishes, the job restores a cache any PR run can poison (the ISSUE-705 vector). If it yields an empty value there, the job is safe. Because the restore is conditional and unproven, Plumber reports this medium verify-manually finding instead of asserting the High.

๐Ÿ”ง How to fix

Make the condition statically checkable: use the ${{ github.event_name != '<publish trigger>' && '<manager>' || '' }} form (or its == inverse) so the cache is provably off on the publish trigger, split caching into a step whose if: excludes the publish trigger, or scope the cache key (and any restore-keys) to the release ref.

โœ— Before`vars.CACHE_MANAGER` is resolved at runtime; Plumber cannot prove the cache is off on the publishing run.
# .github/workflows/release.yml - โŒ Cache enablement Plumber cannot resolve
on:
workflow_dispatch:
pull_request:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-java@v4
with:
cache: ${{ vars.CACHE_MANAGER }} # on? off? depends on a repo variable
- run: npm publish
โœ“ AfterThe expression is empty exactly on `workflow_dispatch`, the only trigger that publishes - Plumber resolves it and stays silent.
# .github/workflows/release.yml - โœ… Provably off on the publish trigger
on:
workflow_dispatch:
pull_request:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-java@v4
with:
cache: ${{ github.event_name != 'workflow_dispatch' && 'maven' || '' }}
- name: Publish
if: github.event_name == 'workflow_dispatch'
run: npm publish

๐Ÿ’ก Tips

  • The resolvable shapes are github.event_name ==/!= '<event>' comparisons: as a step or job if:, as the enable form ... && '<manager>' || '', or as a bare comparison on a default-mode disable input (cache: ${{ github.event_name != 'release' }} on actions/setup-go).
  • Any other whole-value expression (a vars.*, an inputs.*, a compound condition) is unresolvable and reports this code when the step can still share an event with a publish.
  • In a reusable workflow (workflow_call) github.event_name is the caller's event, and Plumber resolves the comparisons against it - conditions on the same event still cancel out.
  • PR builds keep their cache: the point of the conditional form is disabling the restore only on publish runs, not everywhere.

โš™๏ธ Configuration

This control is configured in .plumber.yaml under the github section:

github:
  controls:
    releaseWorkflowsMustNotRestoreUntrustedCache:
      enabled: true

See the CLI documentation for the full configuration reference.