devcontainers / devcontainers/ci

Inputs are wrong in post step when action is called through a nested composite action

Open
#442 0 comments 0 reactions 1 assignee Claimed by @v-Kaniska244 View on GitHub
Dominant language
TypeScript
Stars
496
Forks
101
PR merge metrics
No merged PRs in 30d

Description

## 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`](https://github.com/devcontainers/ci/blob/ec57048782339b3ffd4cd60975884e5a8a4795c9/github-action/src/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](https://github.com/actions/runner/issues/3514) - Wrong environment passed to node post when called by composite called by composite action
- [actions/runner#2030](https://github.com/actions/runner/issues/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:

- 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/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`:

```yaml
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`:

```yaml
# 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`:

```yaml
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`:

```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](https://github.com/github/codeql-action/pull/2557)) is to persist inputs in main using `saveState`, then read them back from `STATE_*` in the post step:

In main:

```ts
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:

```ts
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!

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.