From 974f2a8de3804346cdde940f0a118bc25aae56b3 Mon Sep 17 00:00:00 2001 From: Salman Chishti <13schishti@gmail.com> Date: Mon, 9 Mar 2026 05:35:59 -0700 Subject: [PATCH] feat: add cache-write input for read-only cache mode Add a 'cache-write' input (default: true) that controls whether the cache is saved at the end of the workflow. When set to 'false', the action will restore cached dependencies but skip saving, providing a read-only cache mode. This is useful for preventing cache poisoning attacks from untrusted PR builds while still benefiting from cached dependencies. --- action.yml | 4 ++++ dist/cleanup/index.js | 5 +++++ src/cleanup-java.ts | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/action.yml b/action.yml index 21a4269d7..31514b5d5 100644 --- a/action.yml +++ b/action.yml @@ -59,6 +59,10 @@ inputs: cache-dependency-path: description: 'The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.' required: false + cache-write: + description: 'Whether to save the cache at the end of the workflow. Set to false for cache read-only mode, useful for preventing cache poisoning from untrusted PR builds.' + required: false + default: true job-status: description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting' default: ${{ job.status }} diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 7cb02105d..02f526dd3 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -76919,6 +76919,11 @@ function removePrivateKeyFromKeychain() { */ function saveCache() { return __awaiter(this, void 0, void 0, function* () { + const cacheWriteEnabled = core.getInput('cache-write'); + if (cacheWriteEnabled === 'false') { + core.info('Cache write is disabled (read-only mode). Skipping cache save.'); + return Promise.resolve(); + } const jobStatus = (0, util_1.isJobStatusSuccess)(); const cache = core.getInput(constants.INPUT_CACHE); return jobStatus && cache ? (0, cache_1.save)(cache) : Promise.resolve(); diff --git a/src/cleanup-java.ts b/src/cleanup-java.ts index e09e6a2d0..cdcab284d 100644 --- a/src/cleanup-java.ts +++ b/src/cleanup-java.ts @@ -25,6 +25,12 @@ async function removePrivateKeyFromKeychain() { * @returns Promise that will be resolved when the save process finishes */ async function saveCache() { + const cacheWriteEnabled = core.getInput('cache-write'); + if (cacheWriteEnabled === 'false') { + core.info('Cache write is disabled (read-only mode). Skipping cache save.'); + return Promise.resolve(); + } + const jobStatus = isJobStatusSuccess(); const cache = core.getInput(constants.INPUT_CACHE); return jobStatus && cache ? save(cache) : Promise.resolve();