Disable automatic caching for sensitive events (#992)
test / test-act (push) Failing after 29s
test / test-uv-no-modify-path (push) Failing after 42s
test / test-specific-version (map[expected-version:0.3.2 version-input:0.3.2]) (push) Failing after 42s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25]) (push) Failing after 44s
test / test-specific-version (map[expected-version:0.1.45 resolution-strategy:highest version-input:>=0.1,<0.2]) (push) Failing after 47s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25,<0.5]) (push) Failing after 50s
test / test-latest-version (latest) (push) Failing after 55s
test / test-default-version (ubuntu-latest) (push) Failing after 57s
test / test-specific-version (map[expected-version:0.1.0 resolution-strategy:lowest version-input:>=0.1.0,<0.2]) (push) Failing after 1m0s
test / test-latest-version (>=0.8) (push) Failing after 1m0s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3.x]) (push) Failing after 1m2s
test / test-from-working-directory-version (map[expected-version:0.5.15 working-directory:__tests__/fixtures/uv-toml-project]) (push) Failing after 23s
test / test-version-file-version (map[expected-version:0.5.15 version-file:__tests__/fixtures/.tool-versions]) (push) Failing after 28s
test / test-activate-environment (ubuntu-latest) (push) Failing after 31s
test / test-debian-unstable (push) Failing after 35s
test / test-activate-environment-no-project (push) Failing after 37s
test / test-restore-cache-dependency-glob (push) Skipped
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3]) (push) Failing after 56s
test / test-from-working-directory-version (map[expected-version:0.5.14 working-directory:__tests__/fixtures/pyproject-toml-project]) (push) Failing after 56s
test / test-specific-version (map[expected-version:0.4.30 version-input:>=0.4.25,<0.5]) (push) Failing after 57s
test / test-specific-version (map[expected-version:0.3.0 version-input:0.3.0]) (push) Failing after 59s
test / test-version-file-version (map[expected-version:0.6.17 version-file:__tests__/fixtures/uv-in-requirements-txt-project/requirements.txt]) (push) Failing after 24s
test / test-version-file-version (map[expected-version:0.8.3 version-file:__tests__/fixtures/uv-in-requirements-hash-txt-project/requirements.txt]) (push) Failing after 25s
test / test-malformed-pyproject-file-fallback (push) Failing after 23s
test / test-checksum (map[checksum:4d9279ad5ca596b1e2d703901d508430eb07564dc4d8837de9e2fca9c90f8ecd os:ubuntu-latest]) (push) Failing after 27s
test / test-with-explicit-token (push) Failing after 30s
test / test-python-version (ubuntu-latest) (push) Failing after 30s
test / test-uvx (push) Failing after 32s
test / test-tool-install (ubuntu-latest) (push) Failing after 34s
test / test-activate-environment-custom-path (ubuntu-latest) (push) Failing after 32s
test / test-musl (push) Failing after 33s
test / test-setup-cache (auto, ubuntu-latest) (push) Failing after 30s
test / test-setup-cache (true, ubuntu-latest) (push) Failing after 27s
test / test-setup-cache (false, ubuntu-latest) (push) Failing after 30s
test / test-cache-key-os-version (ubuntu-22.04, ubuntu-22.04) (push) Failing after 39s
test / test-cache-prune-force (push) Failing after 31s
CodeQL / Analyze (TypeScript) (push) Failing after 2m20s
test / test-setup-cache-requirements-txt (push) Failing after 31s
test / lint (push) Failing after 1m55s
test / test-restore-cache-requirements-txt (push) Skipped
test / test-setup-cache-dependency-glob (push) Failing after 29s
test / test-setup-cache-save-cache-false (push) Failing after 29s
test / test-restore-cache-save-cache-false (push) Skipped
test / test-setup-cache-restore-cache-false (push) Failing after 31s
test / test-restore-cache-restore-cache-false (push) Skipped
test / test-cache-local (map[expected-cache-dir:/home/runner/work/_temp/setup-uv-cache os:ubuntu-latest]) (push) Failing after 32s
test / test-cache-local-cache-disabled (push) Failing after 32s
test / test-cache-local-cache-disabled-but-explicit-path (push) Failing after 32s
test / test-custom-manifest-file (push) Failing after 31s
test / test-download-from-astral-mirror-false (push) Failing after 31s
test / test-no-python-version (push) Failing after 35s
test / test-cache-dir-from-file (push) Failing after 34s
test / test-python-install-dir (map[expected-python-dir:/home/runner/work/_temp/uv-python-dir os:ubuntu-latest]) (push) Failing after 29s
test / test-absolute-path (push) Failing after 36s
test / test-relative-path (push) Failing after 41s
test / test-cache-python-missing-managed-install-dir (push) Failing after 28s
test / test-workflow-run (push) Failing after 27s
test / test-cache-python-installs (push) Failing after 34s
test / test-restore-python-installs (push) Skipped
test / validate-typings (push) Successful in 37s
test / test-default-version (macos-14) (push) Canceled after 0s
test / test-default-version (macos-latest) (push) Canceled after 0s
test / test-default-version (windows-latest) (push) Canceled after 0s
test / test-checksum (map[checksum:a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218 os:macos-latest]) (push) Canceled after 0s
test / test-tool-install (macos-14) (push) Canceled after 0s
test / test-tool-install (macos-latest) (push) Canceled after 0s
test / test-tool-install (windows-latest) (push) Canceled after 0s
test / test-python-version (macos-latest) (push) Canceled after 0s
test / test-python-version (windows-latest) (push) Canceled after 0s
test / test-activate-environment (macos-latest) (push) Canceled after 0s
test / test-activate-environment (windows-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (macos-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (windows-latest) (push) Canceled after 0s
test / test-cache-key-os-version (macos-14, macos-14) (push) Canceled after 0s
test / test-cache-key-os-version (macos-15, macos-15) (push) Canceled after 0s
test / test-cache-key-os-version (ubuntu-24.04, ubuntu-24.04) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2022, windows-2022) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2025, windows-2025) (push) Canceled after 0s
test / test-setup-cache (auto, windows-latest) (push) Canceled after 0s
test / test-setup-cache (false, windows-latest) (push) Canceled after 0s
test / test-setup-cache (true, windows-latest) (push) Canceled after 0s
test / test-restore-cache (auto, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (auto, windows-latest) (push) Canceled after 0s
test / test-restore-cache (false, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (false, windows-latest) (push) Canceled after 0s
test / test-restore-cache (true, windows-latest) (push) Canceled after 0s
test / test-python-install-dir (map[expected-python-dir:D:\a\_temp\uv-python-dir os:windows-latest]) (push) Canceled after 0s
test / test-restore-cache (true, ubuntu-latest) (push) Canceled after 0s
test / test-cache-local (map[expected-cache-dir:D:\a\_temp\setup-uv-cache os:windows-latest]) (push) Canceled after 0s
test / all-tests-passed (push) Canceled after 0s
Release Drafter / ✏️ Draft release (push) Canceled after 0s

## Summary

- disable `enable-cache: auto` for `pull_request_target`,
`workflow_run`, and `release` events
- disable automatic caching for tag pushes while leaving branch pushes
unchanged
- preserve explicit `enable-cache: true` as an override
- run a `workflow_run` integration fixture with `act` in pull request CI
and verify caching is disabled
- document the behavior and update the published bundles

## Testing

- `npm run all`
- `actionlint .github/workflows/test.yml
__tests__/workflows/workflow-run.yml`
- `uvx zizmor __tests__/workflows/workflow-run.yml`

Closes #984

Refs: pi-session 019fec42-9b26-714e-a359-830ac4401ecd
This commit is contained in:
Kevin Stillhammer
2026-08-10 18:12:08 +02:00
committed by GitHub
parent b68407c192
commit f45168497b
9 changed files with 181 additions and 6 deletions
+20
View File
@@ -1087,6 +1087,25 @@ jobs:
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
test-workflow-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install act
run: gh extension install https://github.com/nektos/gh-act
env:
GH_TOKEN: ${{ github.token }}
- name: Verify workflow_run disables automatic caching with act
run: |
gh act workflow_run \
-W __tests__/workflows/workflow-run.yml \
-P ubuntu-latest=catthehacker/ubuntu:act-latest \
--env RUNNER_ENVIRONMENT=github-hosted
env:
GH_TOKEN: ${{ github.token }}
validate-typings: validate-typings:
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
steps: steps:
@@ -1143,6 +1162,7 @@ jobs:
- test-restore-python-installs - test-restore-python-installs
- test-python-install-dir - test-python-install-dir
- test-act - test-act
- test-workflow-run
- validate-typings - validate-typings
if: always() if: always()
steps: steps:
+1 -1
View File
@@ -74,7 +74,7 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
# Used when downloading uv from GitHub releases # Used when downloading uv from GitHub releases
github-token: ${{ github.token }} github-token: ${{ github.token }}
# Enable uploading of the uv cache: true, false, or auto (enabled on GitHub-hosted runners, disabled on self-hosted runners) # Enable the GitHub Actions cache for uv: true, false, or auto (enabled on GitHub-hosted runners except for release, tag push, pull_request_target, and workflow_run events; disabled on self-hosted runners)
enable-cache: "auto" enable-cache: "auto"
# Glob pattern to match files relative to the repository root to control the cache # Glob pattern to match files relative to the repository root to control the cache
+64
View File
@@ -12,6 +12,8 @@ import {
let mockInputs: Record<string, string> = {}; let mockInputs: Record<string, string> = {};
const tempDirs: string[] = []; const tempDirs: string[] = [];
const ORIGINAL_GITHUB_EVENT_NAME = process.env.GITHUB_EVENT_NAME;
const ORIGINAL_GITHUB_REF = process.env.GITHUB_REF;
const ORIGINAL_HOME = process.env.HOME; const ORIGINAL_HOME = process.env.HOME;
const ORIGINAL_RUNNER_ENVIRONMENT = process.env.RUNNER_ENVIRONMENT; const ORIGINAL_RUNNER_ENVIRONMENT = process.env.RUNNER_ENVIRONMENT;
const ORIGINAL_RUNNER_TEMP = process.env.RUNNER_TEMP; const ORIGINAL_RUNNER_TEMP = process.env.RUNNER_TEMP;
@@ -52,6 +54,8 @@ function createTempProject(files: Record<string, string> = {}): string {
function resetEnvironment(): void { function resetEnvironment(): void {
jest.clearAllMocks(); jest.clearAllMocks();
mockInputs = {}; mockInputs = {};
delete process.env.GITHUB_EVENT_NAME;
delete process.env.GITHUB_REF;
process.env.HOME = "/home/testuser"; process.env.HOME = "/home/testuser";
delete process.env.RUNNER_ENVIRONMENT; delete process.env.RUNNER_ENVIRONMENT;
delete process.env.RUNNER_TEMP; delete process.env.RUNNER_TEMP;
@@ -64,6 +68,8 @@ function restoreEnvironment(): void {
fs.rmSync(dir, { force: true, recursive: true }); fs.rmSync(dir, { force: true, recursive: true });
} }
process.env.GITHUB_EVENT_NAME = ORIGINAL_GITHUB_EVENT_NAME;
process.env.GITHUB_REF = ORIGINAL_GITHUB_REF;
process.env.HOME = ORIGINAL_HOME; process.env.HOME = ORIGINAL_HOME;
process.env.RUNNER_ENVIRONMENT = ORIGINAL_RUNNER_ENVIRONMENT; process.env.RUNNER_ENVIRONMENT = ORIGINAL_RUNNER_ENVIRONMENT;
process.env.RUNNER_TEMP = ORIGINAL_RUNNER_TEMP; process.env.RUNNER_TEMP = ORIGINAL_RUNNER_TEMP;
@@ -94,6 +100,64 @@ describe("loadInputs", () => {
expect(inputs.resolutionStrategy).toBe("highest"); expect(inputs.resolutionStrategy).toBe("highest");
}); });
it.each([
"pull_request_target",
"workflow_run",
"release",
])("disables automatic caching for the %s event", (eventName) => {
mockInputs["working-directory"] = "/workspace";
mockInputs["enable-cache"] = "auto";
process.env.RUNNER_ENVIRONMENT = "github-hosted";
process.env.RUNNER_TEMP = "/runner-temp";
process.env.GITHUB_EVENT_NAME = eventName;
const inputs = loadInputs();
expect(inputs.enableCache).toBe(false);
expect(mockInfo).toHaveBeenCalledWith(
`Caching is disabled for the ${eventName} event`,
);
});
it("disables automatic caching for tag pushes", () => {
mockInputs["working-directory"] = "/workspace";
mockInputs["enable-cache"] = "auto";
process.env.RUNNER_ENVIRONMENT = "github-hosted";
process.env.RUNNER_TEMP = "/runner-temp";
process.env.GITHUB_EVENT_NAME = "push";
process.env.GITHUB_REF = "refs/tags/v1.0.0";
const inputs = loadInputs();
expect(inputs.enableCache).toBe(false);
expect(mockInfo).toHaveBeenCalledWith("Caching is disabled for tag pushes");
});
it("enables automatic caching for branch pushes", () => {
mockInputs["working-directory"] = "/workspace";
mockInputs["enable-cache"] = "auto";
process.env.RUNNER_ENVIRONMENT = "github-hosted";
process.env.RUNNER_TEMP = "/runner-temp";
process.env.GITHUB_EVENT_NAME = "push";
process.env.GITHUB_REF = "refs/heads/main";
const inputs = loadInputs();
expect(inputs.enableCache).toBe(true);
});
it("honors explicitly enabled caching for sensitive events", () => {
mockInputs["working-directory"] = "/workspace";
mockInputs["enable-cache"] = "true";
process.env.RUNNER_ENVIRONMENT = "github-hosted";
process.env.RUNNER_TEMP = "/runner-temp";
process.env.GITHUB_EVENT_NAME = "release";
const inputs = loadInputs();
expect(inputs.enableCache).toBe(true);
});
it("uses cache-dir from pyproject.toml when present", () => { it("uses cache-dir from pyproject.toml when present", () => {
mockInputs["working-directory"] = createTempProject({ mockInputs["working-directory"] = createTempProject({
"pyproject.toml": `[project] "pyproject.toml": `[project]
+42
View File
@@ -0,0 +1,42 @@
name: "test workflow_run caching"
on: # zizmor: ignore[dangerous-triggers] this workflow is a test fixture executed by act only
workflow_run:
workflows:
- test
types:
- completed
permissions:
contents: read
jobs:
test-cache-disabled:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup uv with automatic caching
id: setup-uv
uses: ./
- name: Verify automatic caching is disabled
env:
CACHE_KEY: ${{ steps.setup-uv.outputs.cache-key }}
run: |
if [ "$GITHUB_EVENT_NAME" != "workflow_run" ]; then
echo "Expected workflow_run event, got: $GITHUB_EVENT_NAME"
exit 1
fi
if [ "$RUNNER_ENVIRONMENT" != "github-hosted" ]; then
echo "Expected a simulated GitHub-hosted runner, got: $RUNNER_ENVIRONMENT"
exit 1
fi
if [ -n "$CACHE_KEY" ]; then
echo "Cache key should not be set for a workflow_run event: $CACHE_KEY"
exit 1
fi
if [ -n "$UV_CACHE_DIR" ]; then
echo "UV_CACHE_DIR should not be set for a workflow_run event: $UV_CACHE_DIR"
exit 1
fi
+1 -1
View File
@@ -33,7 +33,7 @@ inputs:
required: false required: false
default: ${{ github.token }} default: ${{ github.token }}
enable-cache: enable-cache:
description: "Enable uploading of the uv cache" description: "Enable the GitHub Actions cache for uv. 'auto' enables caching on GitHub-hosted runners except for release, tag push, pull_request_target, and workflow_run events."
default: "auto" default: "auto"
cache-dependency-glob: cache-dependency-glob:
description: description:
Generated Vendored
+14 -1
View File
@@ -62624,7 +62624,20 @@ function getVenvPath(workingDirectory, activateEnvironment) {
function getEnableCache() { function getEnableCache() {
const enableCacheInput = getInput("enable-cache"); const enableCacheInput = getInput("enable-cache");
if (enableCacheInput === "auto") { if (enableCacheInput === "auto") {
return process.env.RUNNER_ENVIRONMENT === "github-hosted"; if (process.env.RUNNER_ENVIRONMENT !== "github-hosted") {
return false;
}
const eventName = process.env.GITHUB_EVENT_NAME;
const isTagPush = eventName === "push" && process.env.GITHUB_REF?.startsWith("refs/tags/");
if (isTagPush) {
info2("Caching is disabled for tag pushes");
return false;
}
if (eventName === "pull_request_target" || eventName === "workflow_run" || eventName === "release") {
info2(`Caching is disabled for the ${eventName} event`);
return false;
}
return true;
} }
return enableCacheInput === "true"; return enableCacheInput === "true";
} }
Generated Vendored
+14 -1
View File
@@ -98255,7 +98255,20 @@ function getVenvPath(workingDirectory, activateEnvironment2) {
function getEnableCache() { function getEnableCache() {
const enableCacheInput = getInput("enable-cache"); const enableCacheInput = getInput("enable-cache");
if (enableCacheInput === "auto") { if (enableCacheInput === "auto") {
return process.env.RUNNER_ENVIRONMENT === "github-hosted"; if (process.env.RUNNER_ENVIRONMENT !== "github-hosted") {
return false;
}
const eventName = process.env.GITHUB_EVENT_NAME;
const isTagPush = eventName === "push" && process.env.GITHUB_REF?.startsWith("refs/tags/");
if (isTagPush) {
info2("Caching is disabled for tag pushes");
return false;
}
if (eventName === "pull_request_target" || eventName === "workflow_run" || eventName === "release") {
info2(`Caching is disabled for the ${eventName} event`);
return false;
}
return true;
} }
return enableCacheInput === "true"; return enableCacheInput === "true";
} }
+4 -1
View File
@@ -38,7 +38,10 @@ The computed cache key is available as the `cache-key` output:
If you enable caching, the [uv cache](https://docs.astral.sh/uv/concepts/cache/) will be uploaded to If you enable caching, the [uv cache](https://docs.astral.sh/uv/concepts/cache/) will be uploaded to
the GitHub Actions cache. This can speed up runs that reuse the cache by several minutes. the GitHub Actions cache. This can speed up runs that reuse the cache by several minutes.
Caching is enabled by default on GitHub-hosted runners. With the default `enable-cache: auto`, caching is enabled on GitHub-hosted runners except for
`release`, tag push, `pull_request_target`, and `workflow_run` events. Caching is disabled for these
events to prevent insecure or release-sensitive jobs from restoring potentially poisoned caches.
Set `enable-cache: true` to explicitly enable caching for any event.
> [!TIP] > [!TIP]
> >
+21 -1
View File
@@ -140,7 +140,27 @@ function getVenvPath(
function getEnableCache(): boolean { function getEnableCache(): boolean {
const enableCacheInput = core.getInput("enable-cache"); const enableCacheInput = core.getInput("enable-cache");
if (enableCacheInput === "auto") { if (enableCacheInput === "auto") {
return process.env.RUNNER_ENVIRONMENT === "github-hosted"; if (process.env.RUNNER_ENVIRONMENT !== "github-hosted") {
return false;
}
const eventName = process.env.GITHUB_EVENT_NAME;
const isTagPush =
eventName === "push" && process.env.GITHUB_REF?.startsWith("refs/tags/");
if (isTagPush) {
log.info("Caching is disabled for tag pushes");
return false;
}
if (
eventName === "pull_request_target" ||
eventName === "workflow_run" ||
eventName === "release"
) {
log.info(`Caching is disabled for the ${eventName} event`);
return false;
}
return true;
} }
return enableCacheInput === "true"; return enableCacheInput === "true";
} }