Skip to content

fix: give each step execution its own runner file command directory - #6154

Open
McNultyyy wants to merge 1 commit into
nektos:masterfrom
McNultyyy:act-split/2-step-command-dirs
Open

fix: give each step execution its own runner file command directory#6154
McNultyyy wants to merge 1 commit into
nektos:masterfrom
McNultyyy:act-split/2-step-command-dirs

Conversation

@McNultyyy

Copy link
Copy Markdown

Refs #2184, #2697, #2553.

Every step writes its file commands to the same five paths in the job container — workflow/outputcmd.txt, statecmd.txt, pathcmd.txt, envs.txt, SUMMARY.md — and reads them back after it finishes. A step therefore reads whatever the previously executed step left behind.

The visible consequence is composite actions leaking outputs. GitHub scopes an output written by a composite action's inner step to that inner step, exposing only the outputs the action declares in its outputs:. In act the inner step's writes to $GITHUB_OUTPUT are still sitting in the shared file when the enclosing job step processes it, so they surface as outputs of the step that used the action.

What this does

Each step execution gets its own workflow/cmds-<n>-<stage>/ directory, so nothing is inherited from the previous step.

Two related fixes for the same root cause — step-scoped data keyed off mutable state:

  • File command results are recorded against the id of the step they belong to, rather than whatever RunContext.CurrentStep holds by the time they are read. Same for the ::set-output / ::save-state handlers, which now take the step id of the step whose output stream they are attached to.
  • Composite script names are derived from a new stable parentStepID instead of CurrentStep.

Testing

New composite-undeclared-outputs fixture, added to the docker TestRunEvent table. It asserts that an output a composite action declares is visible on the step that used it, and that outputs it does not declare are not — for a plain composite and one nesting another composite, over both $GITHUB_OUTPUT and legacy ::set-output.

It fails on master and passes with this change, which is the point of including it.

The rest of the composite and file-command suite is green: uses-composite, uses-nested-composite, composite-fail-with-output, act-composite-env-test, do-not-leak-step-env-in-composite, uses-composite-with-pre-and-post-steps, outputs, GITHUB_STATE, environment-files.

Things to be aware of

  • The in-container paths of $GITHUB_OUTPUT, $GITHUB_ENV, $GITHUB_PATH, $GITHUB_STATE and $GITHUB_STEP_SUMMARY change. Anything that hard-codes them rather than reading the environment variable would break — I could not find such a case, but it is worth a second pair of eyes.
  • The per-execution directories are not cleaned up, so they accumulate for the lifetime of the job container. Negligible in size, but it is a change from one fixed set of files.
  • $GITHUB_STEP_SUMMARY becomes per step execution rather than per step id. Summaries are already emitted per step, so this should not be observable.
  • The four step unit tests matched the old fixed paths exactly; they now match through a matchCmdFile helper.

I have deliberately not marked #2184 / #2697 / #2553 as closed. This addresses the mechanism all three describe, but they should be re-checked against the original reproductions before closing.

🤖 Generated with Claude Code

Every step wrote its file commands to the same paths in the job
container: workflow/outputcmd.txt, statecmd.txt, pathcmd.txt, envs.txt
and SUMMARY.md. A step therefore read whatever the previously executed
step had left in them.

The visible consequence is composite actions leaking outputs. GitHub
scopes an output written by a composite action's inner step to that
inner step, and exposes only the outputs the action declares. In act the
inner step's writes to $GITHUB_OUTPUT were still sitting in the shared
file when the enclosing job step processed it, so they appeared as
outputs of the step that used the action.

Each step execution now gets its own directory. The file commands are
also recorded against the id of the step they belong to instead of the
mutable CurrentStep field, and composite script names are derived from
the stable id of the step the composite runs for rather than from
CurrentStep.

The new composite-undeclared-outputs fixture covers a plain and a nested
composite action, over both $GITHUB_OUTPUT and ::set-output. It fails on
master and passes here.

Refs nektos#2184, nektos#2697, nektos#2553

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant