Description
When devcontainers/ci is called from within a composite action, images are built correctly but pushed under the wrong tags (or not at all). The push happens in the post step at main.ts#L255, which re-reads inputs via core.getInput('imageTag') and core.getInput('imageName'). At post time, those calls return incorrect values.
Root cause
This is a known GHA runner bug: when a node action with a post step is called through a composite action, the runner restores the wrong INPUT_* environment for the post step. Instead of the values the action itself received, it receives the input values of the nearest ancestor composite action.
- actions/runner#3514 - Wrong environment passed to node post when called by composite called by composite action
- actions/runner#2030 - Composite: Nested actions post steps have the wrong context
To reproduce
You can view an MVCE demonstrating this issue at: https://github.com/iaingalloway/devcontainers-ci-inputs-mcve
You can see an affected workflow run:
You can view an MCVE of the underlying issue in actions/runner at: https://github.com/iainlane/composite-action-inputs-mvce
Call devcontainers/ci from a composite action that itself receives imageName/imageTag as inputs:
.github/workflows/repro.yml:
name: Post hook sees wrong input
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Log in to registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Call outer composite
uses: ./.github/actions/outer-composite
.github/actions/outer-composite/action.yml:
# Outer composite action
name: Outer composite
description: Sets the value to bar and calls the inner composite
runs:
using: composite
steps:
- name: Call inner composite
uses: ./.github/actions/inner-composite
with:
image-tag: foo
.github/actions/inner-composite/action.yml:
name: Inner composite
description: Passes a value to the devcontainers/ci action
inputs:
image-tag:
description: Image tag to build and push
required: true
runs:
using: composite
steps:
- name: Build and push devcontainer image
uses: devcontainers/ci@b63b30de439b47a52267f241112c5b453b673db5
with:
imageName: ghcr.io/${{ github.repository }}/devcontainer
imageTag: ${{ inputs.image-tag }}
push: always
subFolder: src
./src/devcontainer.json:
{
"image": "mcr.microsoft.com/devcontainers/base@sha256:e389149057371298eaeb72e736fc2c4dcb79974de222dd471d2e6d675d2f61c4"
}
Observed: post step attempts to push latest (by default, because INPUT_IMAGETAG is not set in the post context).
Expected: post step should push foo.
Workaround (for maintainers)
The fix used by github/codeql-action (codeql-action#2557) is to persist inputs in main using saveState, then read them back from STATE_* in the post step:
In main:
core.saveState('imageName', imageName);
core.saveState('imageTag', imageTag);
core.saveState('push', push);
core.saveState('platform', platform);
In post, replace core.getInput('imageName') / core.getInput('imageTag') / core.getInput('push') / core.getInput('platform') with:
core.getState('push')
core.getState('imageName')
core.getState('imageTag')
core.getState('platform')
This sidesteps the runner bug entirely since state is stored in STATE_* env vars which are not subject to the same mis-evaluation.
Happy to submit a PR with this change if it would be helpful!
Description
When
devcontainers/ciis called from within a composite action, images are built correctly but pushed under the wrong tags (or not at all). The push happens in the post step atmain.ts#L255, which re-reads inputs viacore.getInput('imageTag')andcore.getInput('imageName'). At post time, those calls return incorrect values.Root cause
This is a known GHA runner bug: when a node action with a post step is called through a composite action, the runner restores the wrong
INPUT_*environment for the post step. Instead of the values the action itself received, it receives the input values of the nearest ancestor composite action.To reproduce
You can view an MVCE demonstrating this issue at: https://github.com/iaingalloway/devcontainers-ci-inputs-mcve
You can see an affected workflow run:
The image is built with the correct tag here: https://github.com/iaingalloway/devcontainers-ci-inputs-mcve/actions/runs/24731494052/job/72346898558#step:6:3
And the image is pushed with the wrong tag here: https://github.com/iaingalloway/devcontainers-ci-inputs-mcve/actions/runs/24731494052/job/72346898558#step:6:3
You can view an MCVE of the underlying issue in
actions/runnerat: https://github.com/iainlane/composite-action-inputs-mvceCall
devcontainers/cifrom a composite action that itself receivesimageName/imageTagas inputs:.github/workflows/repro.yml:.github/actions/outer-composite/action.yml:.github/actions/inner-composite/action.yml:./src/devcontainer.json:{ "image": "mcr.microsoft.com/devcontainers/base@sha256:e389149057371298eaeb72e736fc2c4dcb79974de222dd471d2e6d675d2f61c4" }Observed: post step attempts to push
latest(by default, becauseINPUT_IMAGETAGis not set in the post context).Expected: post step should push
foo.Workaround (for maintainers)
The fix used by
github/codeql-action(codeql-action#2557) is to persist inputs in main usingsaveState, then read them back fromSTATE_*in the post step:In main:
In post, replace
core.getInput('imageName')/core.getInput('imageTag')/core.getInput('push')/core.getInput('platform')with:This sidesteps the runner bug entirely since state is stored in
STATE_*env vars which are not subject to the same mis-evaluation.Happy to submit a PR with this change if it would be helpful!