From 45b0d171682a29fc833072d64d3bf04835e448b5 Mon Sep 17 00:00:00 2001 From: Iain Galloway Date: Wed, 22 Apr 2026 10:20:44 +0100 Subject: [PATCH] Use state to persist inputs used in the post step There is a known bug in GHA actions/runner. When a node action with a post step is called via a nested composite action, the runner restores the wrong INPUT_* environment for the post step, potentially resulting in images being incorrectly pushed or not pushed, or the wrong tags being pushed. This commit uses a workaround used in the first-party action github/codeql-action, instead of using `core.getInput` in the post step, the relevant values are stored in the main step using `core.saveState`, and then loaded in the post step using `core.getState` Fixes #442 --- github-action/src/main.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/github-action/src/main.ts b/github-action/src/main.ts index 1189788cd..46081d3fe 100644 --- a/github-action/src/main.ts +++ b/github-action/src/main.ts @@ -64,6 +64,13 @@ export async function runMain(): Promise { const userDataFolder: string = core.getInput('userDataFolder'); const mounts: string[] = core.getMultilineInput('mounts'); + // Make inputs available to the post step by saving them to state + // Otherwise they aren't available when this action is being used in a nested composite action + core.saveState('imageName', imageName); + core.saveState('imageTag', imageTag); + core.saveState('push', core.getInput('push')); + core.saveState('platform', platform); + if (platform) { const skopeoInstalled = await isSkopeoInstalled(); if (!skopeoInstalled) { @@ -211,8 +218,8 @@ export async function runMain(): Promise { } export async function runPost(): Promise { - const pushOption = emptyStringAsUndefined(core.getInput('push')); - const imageName = emptyStringAsUndefined(core.getInput('imageName')); + const pushOption = emptyStringAsUndefined(core.getState('push')); + const imageName = emptyStringAsUndefined(core.getState('imageName')); const refFilterForPush: string[] = core.getMultilineInput('refFilterForPush'); const eventFilterForPush: string[] = core.getMultilineInput('eventFilterForPush'); @@ -252,7 +259,7 @@ export async function runPost(): Promise { } const imageTag = - emptyStringAsUndefined(core.getInput('imageTag')) ?? 'latest'; + emptyStringAsUndefined(core.getState('imageTag')) ?? 'latest'; const imageTagArray = imageTag.split(/\s*,\s*/); if (!imageName) { if (pushOption) { @@ -262,7 +269,7 @@ export async function runPost(): Promise { return; } - const platform = emptyStringAsUndefined(core.getInput('platform')); + const platform = emptyStringAsUndefined(core.getState('platform')); if (platform) { for (const tag of imageTagArray) { core.info(`Copying multiplatform image '${imageName}:${tag}'...`);