ci: Add dynamic cache switching to warp cache
What changed, and why it matters
This commit is a routine change to Bitcoin Core's continuous integration (CI) setup. It swaps the GitHub Actions cache for a faster third-party cache service (WarpBuild) on Warp runners, while keeping GitHub's cache as a fallback for forks. There is no change to the Bitcoin software itself, to wallets, transactions, consensus rules, or network code.
No security action required. Reviewers may want to confirm that the WarpBuild cache action is pinned to a trusted version and that the provider input cannot be attacker-controlled in pull_request workflows, but these are standard CI hygiene checks rather than findings.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors .github/actions/restore-caches and .github/actions/save-caches into composite actions under .github/actions/cache/restore and .github/actions/cache/save, with internal wrappers that branch between WarpBuilds/cache/@v1 and actions/cache/@v5 based on an input provider. ci.yml is updated to pass provider: ${{ needs.runners.outputs.provider }} (or matrix.provider). ci/README.md is updated to list the new allowed actions. No application code, build scripts producing release binaries, secrets handling, or network-facing logic is modified.
Changed components
.github/actions/cache/restore/action.yml.github/actions/cache/restore/internal/action.yml.github/actions/cache/save/action.yml.github/actions/cache/save/internal/action.yml.github/workflows/ci.ymlci/README.mdInspect captured patch +188 / −91
diff --git a/.github/actions/cache/restore/action.yml b/.github/actions/cache/restore/action.yml
new file mode 100644
index 00000000..2cc5b53a
--- /dev/null
+++ b/.github/actions/cache/restore/action.yml
@@ -0,0 +1,55 @@
+name: 'Restore Caches'
+description: 'Restore ccache, depends sources, and built depends caches'
+inputs:
+ provider:
+ description: 'The cache provider to use'
+ required: true
+runs:
+ using: 'composite'
+ steps:
+ - name: Restore Ccache cache
+ id: ccache-cache
+ uses: ./.github/actions/cache/restore/internal
+ with:
+ path: ${{ env.CCACHE_DIR }}
+ key: ccache-${{ env.CONTAINER_NAME }}-${{ github.run_id }}
+ restore-keys: |
+ ccache-${{ env.CONTAINER_NAME }}-
+ provider: ${{ inputs.provider }}
+
+ - name: Restore depends sources cache
+ id: depends-sources
+ uses: ./.github/actions/cache/restore/internal
+ with:
+ path: ${{ env.SOURCES_PATH }}
+ key: depends-sources-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
+ restore-keys: |
+ depends-sources-${{ env.CONTAINER_NAME }}-
+ provider: ${{ inputs.provider }}
+
+ - name: Restore built depends cache
+ id: depends-built
+ uses: ./.github/actions/cache/restore/internal
+ with:
+ path: ${{ env.BASE_CACHE }}
+ key: depends-built-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
+ restore-keys: |
+ depends-built-${{ env.CONTAINER_NAME }}-
+ provider: ${{ inputs.provider }}
+
+ - name: Restore previous releases cache
+ id: previous-releases
+ uses: ./.github/actions/cache/restore/internal
+ with:
+ path: ${{ env.PREVIOUS_RELEASES_DIR }}
+ key: previous-releases-${{ env.CONTAINER_NAME }}-${{ env.PREVIOUS_RELEASES_HASH }}
+ restore-keys: |
+ previous-releases-${{ env.CONTAINER_NAME }}-
+ provider: ${{ inputs.provider }}
+
+ - name: export cache hits
+ shell: bash
+ run: |
+ echo "depends-sources-cache-hit=${{ steps.depends-sources.outputs.cache-hit }}" >> $GITHUB_ENV
+ echo "depends-built-cache-hit=${{ steps.depends-built.outputs.cache-hit }}" >> $GITHUB_ENV
+ echo "previous-releases-cache-hit=${{ steps.previous-releases.outputs.cache-hit }}" >> $GITHUB_ENV
diff --git a/.github/actions/cache/restore/internal/action.yml b/.github/actions/cache/restore/internal/action.yml
new file mode 100644
index 00000000..43dd2063
--- /dev/null
+++ b/.github/actions/cache/restore/internal/action.yml
@@ -0,0 +1,43 @@
+name: 'Cache Restore'
+description: 'Restore a cache with WarpBuild on Warp runners and GitHub Actions cache otherwise'
+inputs:
+ path:
+ description: 'A list of files, directories, and wildcard patterns to restore'
+ required: true
+ key:
+ description: 'An explicit key for restoring the cache'
+ required: true
+ restore-keys:
+ description: 'An ordered multiline string listing prefix-matched restore keys'
+ required: false
+ default: ''
+ provider:
+ description: 'The cache provider to use'
+ required: true
+outputs:
+ cache-hit:
+ description: 'A boolean value to indicate an exact match was found for the primary key'
+ value: ${{ steps.warp.outputs.cache-hit || steps.gha.outputs.cache-hit }}
+ cache-primary-key:
+ description: 'The primary key used to restore the cache'
+ value: ${{ steps.warp.outputs.cache-primary-key || steps.gha.outputs.cache-primary-key }}
+runs:
+ using: 'composite'
+ steps:
+ - name: Restore cache with WarpBuild
+ id: warp
+ if: ${{ inputs.provider == 'warp' }}
+ uses: WarpBuilds/cache/restore@v1
+ with:
+ path: ${{ inputs.path }}
+ key: ${{ inputs.key }}
+ restore-keys: ${{ inputs.restore-keys }}
+
+ - name: Restore cache with GitHub Actions
+ id: gha
+ if: ${{ inputs.provider == 'gha' }}
+ uses: actions/cache/restore@v5
+ with:
+ path: ${{ inputs.path }}
+ key: ${{ inputs.key }}
+ restore-keys: ${{ inputs.restore-keys }}
diff --git a/.github/actions/cache/save/action.yml b/.github/actions/cache/save/action.yml
new file mode 100644
index 00000000..5c543b3f
--- /dev/null
+++ b/.github/actions/cache/save/action.yml
@@ -0,0 +1,47 @@
+name: 'Save Caches'
+description: 'Save ccache, depends sources, and built depends caches'
+inputs:
+ provider:
+ description: 'The cache provider to use'
+ required: true
+runs:
+ using: 'composite'
+ steps:
+ - name: debug cache hit inputs
+ shell: bash
+ run: |
+ echo "depends sources direct cache hit to primary key: ${{ env.depends-sources-cache-hit }}"
+ echo "depends built direct cache hit to primary key: ${{ env.depends-built-cache-hit }}"
+ echo "previous releases direct cache hit to primary key: ${{ env.previous-releases-cache-hit }}"
+
+ - name: Save Ccache cache
+ uses: ./.github/actions/cache/save/internal
+ if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) }}
+ with:
+ path: ${{ env.CCACHE_DIR }}
+ key: ccache-${{ env.CONTAINER_NAME }}-${{ github.run_id }}
+ provider: ${{ inputs.provider }}
+
+ - name: Save depends sources cache
+ uses: ./.github/actions/cache/save/internal
+ if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.depends-sources-cache-hit != 'true') }}
+ with:
+ path: ${{ env.SOURCES_PATH }}
+ key: depends-sources-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
+ provider: ${{ inputs.provider }}
+
+ - name: Save built depends cache
+ uses: ./.github/actions/cache/save/internal
+ if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.depends-built-cache-hit != 'true' )}}
+ with:
+ path: ${{ env.BASE_CACHE }}
+ key: depends-built-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
+ provider: ${{ inputs.provider }}
+
+ - name: Save previous releases cache
+ uses: ./.github/actions/cache/save/internal
+ if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.previous-releases-cache-hit != 'true' )}}
+ with:
+ path: ${{ env.PREVIOUS_RELEASES_DIR }}
+ key: previous-releases-${{ env.CONTAINER_NAME }}-${{ env.PREVIOUS_RELEASES_HASH }}
+ provider: ${{ inputs.provider }}
diff --git a/.github/actions/cache/save/internal/action.yml b/.github/actions/cache/save/internal/action.yml
new file mode 100644
index 00000000..12f4156a
--- /dev/null
+++ b/.github/actions/cache/save/internal/action.yml
@@ -0,0 +1,28 @@
+name: 'Cache Save'
+description: 'Save a cache with WarpBuild on Warp runners and GitHub Actions cache otherwise'
+inputs:
+ path:
+ description: 'A list of files, directories, and wildcard patterns to cache'
+ required: true
+ key:
+ description: 'An explicit key for saving the cache'
+ required: true
+ provider:
+ description: 'The cache provider to use'
+ required: true
+runs:
+ using: 'composite'
+ steps:
+ - name: Save cache with WarpBuild
+ if: ${{ inputs.provider == 'warp' }}
+ uses: WarpBuilds/cache/save@v1
+ with:
+ path: ${{ inputs.path }}
+ key: ${{ inputs.key }}
+
+ - name: Save cache with GitHub Actions
+ if: ${{ inputs.provider == 'gha' }}
+ uses: actions/cache/save@v5
+ with:
+ path: ${{ inputs.path }}
+ key: ${{ inputs.key }}
diff --git a/.github/actions/restore-caches/action.yml b/.github/actions/restore-caches/action.yml
deleted file mode 100644
index ee07d68b..00000000
--- a/.github/actions/restore-caches/action.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: 'Restore Caches'
-description: 'Restore ccache, depends sources, and built depends caches'
-runs:
- using: 'composite'
- steps:
- - name: Restore Ccache cache
- id: ccache-cache
- uses: actions/cache/restore@v5
- with:
- path: ${{ env.CCACHE_DIR }}
- key: ccache-${{ env.CONTAINER_NAME }}-${{ github.run_id }}
- restore-keys: |
- ccache-${{ env.CONTAINER_NAME }}-
-
- - name: Restore depends sources cache
- id: depends-sources
- uses: actions/cache/restore@v5
- with:
- path: ${{ env.SOURCES_PATH }}
- key: depends-sources-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
- restore-keys: |
- depends-sources-${{ env.CONTAINER_NAME }}-
-
- - name: Restore built depends cache
- id: depends-built
- uses: actions/cache/restore@v5
- with:
- path: ${{ env.BASE_CACHE }}
- key: depends-built-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
- restore-keys: |
- depends-built-${{ env.CONTAINER_NAME }}-
-
- - name: Restore previous releases cache
- id: previous-releases
- uses: actions/cache/restore@v5
- with:
- path: ${{ env.PREVIOUS_RELEASES_DIR }}
- key: previous-releases-${{ env.CONTAINER_NAME }}-${{ env.PREVIOUS_RELEASES_HASH }}
- restore-keys: |
- previous-releases-${{ env.CONTAINER_NAME }}-
-
- - name: export cache hits
- shell: bash
- run: |
- echo "depends-sources-cache-hit=${{ steps.depends-sources.outputs.cache-hit }}" >> $GITHUB_ENV
- echo "depends-built-cache-hit=${{ steps.depends-built.outputs.cache-hit }}" >> $GITHUB_ENV
- echo "previous-releases-cache-hit=${{ steps.previous-releases.outputs.cache-hit }}" >> $GITHUB_ENV
diff --git a/.github/actions/save-caches/action.yml b/.github/actions/save-caches/action.yml
deleted file mode 100644
index 8667c914..00000000
--- a/.github/actions/save-caches/action.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: 'Save Caches'
-description: 'Save ccache, depends sources, and built depends caches'
-runs:
- using: 'composite'
- steps:
- - name: debug cache hit inputs
- shell: bash
- run: |
- echo "depends sources direct cache hit to primary key: ${{ env.depends-sources-cache-hit }}"
- echo "depends built direct cache hit to primary key: ${{ env.depends-built-cache-hit }}"
- echo "previous releases direct cache hit to primary key: ${{ env.previous-releases-cache-hit }}"
-
- - name: Save Ccache cache
- uses: actions/cache/save@v5
- if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) }}
- with:
- path: ${{ env.CCACHE_DIR }}
- key: ccache-${{ env.CONTAINER_NAME }}-${{ github.run_id }}
-
- - name: Save depends sources cache
- uses: actions/cache/save@v5
- if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.depends-sources-cache-hit != 'true') }}
- with:
- path: ${{ env.SOURCES_PATH }}
- key: depends-sources-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
-
- - name: Save built depends cache
- uses: actions/cache/save@v5
- if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.depends-built-cache-hit != 'true' )}}
- with:
- path: ${{ env.BASE_CACHE }}
- key: depends-built-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
-
- - name: Save previous releases cache
- uses: actions/cache/save@v5
- if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.previous-releases-cache-hit != 'true' )}}
- with:
- path: ${{ env.PREVIOUS_RELEASES_DIR }}
- key: previous-releases-${{ env.CONTAINER_NAME }}-${{ env.PREVIOUS_RELEASES_HASH }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5c44d678..8eaa68ab 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -357,7 +357,9 @@ jobs:
- name: Restore caches
id: restore-cache
- uses: ./.github/actions/restore-caches
+ uses: ./.github/actions/cache/restore
+ with:
+ provider: ${{ needs.runners.outputs.provider }}
- name: Configure Docker
uses: ./.github/actions/configure-docker
@@ -366,7 +368,9 @@ jobs:
run: ./ci/test_run_all.sh
- name: Save caches
- uses: ./.github/actions/save-caches
+ uses: ./.github/actions/cache/save
+ with:
+ provider: ${{ needs.runners.outputs.provider }}
- name: Upload built executables
uses: actions/upload-artifact@v7
@@ -547,7 +551,9 @@ jobs:
- name: Restore caches
id: restore-cache
- uses: ./.github/actions/restore-caches
+ uses: ./.github/actions/cache/restore
+ with:
+ provider: ${{ matrix.provider || needs.runners.outputs.provider }}
- name: Configure Docker
uses: ./.github/actions/configure-docker
@@ -571,7 +577,9 @@ jobs:
run: ./ci/test_run_all.sh
- name: Save caches
- uses: ./.github/actions/save-caches
+ uses: ./.github/actions/cache/save
+ with:
+ provider: ${{ matrix.provider || needs.runners.outputs.provider }}
lint:
name: 'lint'
diff --git a/ci/README.md b/ci/README.md
index 314d336b..0b6a3446 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -87,8 +87,10 @@ To configure the primary repository, follow these steps:
4. Permit the following actions to run:
1. actions/cache/restore@\*
1. actions/cache/save@\*
- 1. docker/setup-buildx-action@\*
1. actions/github-script@\*
+ 1. docker/setup-buildx-action@\*
+ 1. warpbuilds/cache/restore@\*
+ 1. warpbuilds/cache/save@\*
### Forked repositories
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.