diff --git a/.github/scripts/tests/release-runner-cache.test.mjs b/.github/scripts/tests/release-runner-cache.test.mjs index 84cbbee0e9d..9e4b8fe7155 100644 --- a/.github/scripts/tests/release-runner-cache.test.mjs +++ b/.github/scripts/tests/release-runner-cache.test.mjs @@ -18,11 +18,13 @@ test("Runner dependency caching selects the package's pinned compiler before com assert.match(runner, /shared-key: release-runner-v1/); }); -test("the shared cache excludes workspace artifacts and only saves the exact master-push source", () => { +test("the shared cache excludes workspace artifacts and only restores or saves the exact master-push source", () => { assert.match(runner, /cache-workspace-crates: false/); assert.match(runner, /cache-bin: false/); const saveIf = runner.match(/^\s*save-if: (.+)$/m)?.[1]; assert.equal(saveIf, "${{ github.repository == 'paperclipai/paperclip' && github.event_name == 'push' && github.ref == 'refs/heads/master' && inputs.ref == github.sha }}"); + const cacheStep = runner.split(" - name: Cache Runner Rust dependencies")[1].split(" - name: Install dependencies")[0]; + assert.equal(cacheStep.match(/^\s*if: (.+)$/m)?.[1], saveIf); assert.doesNotMatch(runner, /cache-on-failure: true|cache-all-crates: true/); }); diff --git a/.github/workflows/release-verify.yml b/.github/workflows/release-verify.yml index 5b25fea478f..4a7b9e2e297 100644 --- a/.github/workflows/release-verify.yml +++ b/.github/workflows/release-verify.yml @@ -236,6 +236,9 @@ jobs: echo "RUSTUP_TOOLCHAIN=$toolchain" >> "$GITHUB_ENV" - name: Cache Runner Rust dependencies + # Restore and save only within trusted master-push verification. GitHub + # isolates branch/PR caches from master; other callers compile afresh. + if: ${{ github.repository == 'paperclipai/paperclip' && github.event_name == 'push' && github.ref == 'refs/heads/master' && inputs.ref == github.sha }} uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: workspaces: packages/paperclip-runner/runner -> target diff --git a/doc/RELEASE-AUTOMATION-SETUP.md b/doc/RELEASE-AUTOMATION-SETUP.md index a7629295f81..7896b6cf98a 100644 --- a/doc/RELEASE-AUTOMATION-SETUP.md +++ b/doc/RELEASE-AUTOMATION-SETUP.md @@ -346,8 +346,16 @@ callers of this reusable verification workflow reuse the same dependency cache. Workspace crates and installed Cargo binaries are excluded. Every run still builds the Runner workspace and runs `check:all`, including the Rust and -TypeScript tests. Only a successful master-push run verifying that push's exact -SHA saves the shared cache. Manual candidate verification can restore it without -saving. A miss or eviction costs compilation time but does not change the checks. +TypeScript tests. Only an own-repository master-push run verifying that push's exact +SHA can restore the cache, and only a successful run saves it. PR, tag, and +manual candidate verification compile without this cache. A miss or eviction costs compilation time but does not change the checks. To discard old dependency caches, increment the shared-key version and let the next successful master verification warm it again. + +The trust boundary is the protected master branch, not the cache-key text. +GitHub does not let master restore caches created by a child branch, sibling +branch, tag, or PR merge ref. Both permitted restore scopes (current branch and +default branch) are master here. A workflow with authority to execute arbitrary +code on master can affect verification directly and is already trusted. The +cache contains dependency build artifacts, not credentials or workspace output. +See [GitHub cache access restrictions](https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#restrictions-for-accessing-a-cache).