Skip to content

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

@iaingalloway

Description

@iaingalloway

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions