Skip to content

gh aw fix: move-step-run-expressions-to-env-bindings codemod inserts invalid env bindings when GitHub expressions appear in bash comments #38681

@corygehr

Description

@corygehr

Summary

The move-step-run-expressions-to-env-bindings codemod (applied by gh aw fix --write and transitively by gh aw upgrade) scans bash comment lines inside run: | blocks. When a ${{ ... }} expression appears inside a comment — purely as documentation, not as a real reference — the codemod still:

  1. Generates an EXPR_<hash> env binding containing the literal expression text, and
  2. Rewrites the comment line, replacing the original ${{ ... }} with $EXPR_<hash>.

If the documented expression contains a glob/wildcard (e.g. ${{ steps.foo.outputs.* }} used to mean "any output of steps.foo"), the generated env binding becomes invalid GitHub Actions YAML because steps.foo.outputs.* is not a valid expression.

This produces a workflow that immediately fails to compile (or runs but fails at the env-binding evaluation step), and the only mitigation is to revert the affected file and re-run gh aw compile without fix.

Versions seen

Reproduced on v0.79.2, v0.79.3, and v0.79.6. Have not verified v0.79.4 or v0.79.5 specifically; suspect the regression has been latent across all of these.

Minimal reproduction

A workflow repro.md with a pre-step that:

  • Has a real expression in its run: body, AND
  • Documents the placeholder name in a bash comment that happens to use wildcard prose syntax:
---
on:
  workflow_dispatch:
steps:
  - id: parse
    name: Parse inputs
    run: |
      echo "value=hello" >> "$GITHUB_OUTPUT"

  - name: Use parsed value
    env:
      VALUE: ${{ steps.parse.outputs.value }}
    run: |
      echo "Got: $VALUE"
      # Note: the prompt placeholders ${{ steps.parse.outputs.* }} resolve to
      # empty strings in the rendered prompt because they're evaluated in a
      # different job context.
---

# Repro

Run gh aw fix --write repro (or gh aw upgrade). The codemod produces:

- name: Use parsed value
  env:
    VALUE: ${{ steps.parse.outputs.value }}
    EXPR_<hash>: ${{ steps.parse.outputs.* }}   # ← invalid expression
  run: |
    echo "Got: $VALUE"
    # Note: the prompt placeholders $EXPR_<hash> resolve to
    # empty strings in the rendered prompt because they're evaluated in a
    # different job context.

The new EXPR_<hash>: ${{ steps.parse.outputs.* }} is an invalid expression and the workflow fails.

Expected behavior

The codemod should ignore expressions that appear inside bash comment lines (i.e. lines whose first non-whitespace character inside run: | is #). Comments are documentation — they don't reference outputs and shouldn't trigger env-binding extraction.

Suggested fix

In the move-step-run-expressions-to-env-bindings codemod, when iterating over lines of a run: | block, skip lines matching ^\s*# before scanning for ${{ ... }} patterns.

Current workaround

After running gh aw fix --write or gh aw upgrade, revert any source .md whose only diff is a spurious EXPR_<hash>: ${{ ... }} env binding paired with a bash-comment-line substitution, then re-run gh aw compile to refresh the lock file.

Metadata

Metadata

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