Repository navigation
feat: run an imported workflow end to end on the host - #83
Merged
Merged
Conversation
A run options host takes over the provider steps. Before a job runs, the runner asks it to prepare the job's steps for the combination about to run: the host places the phases an imported action declares around the job's own steps and adds job-level environment its provider carries. When the run reaches a provider step the preparation left in place, the host resolves it into commands, each of which receives the runner's file commands and its own report entry like a native step, and the first failure stops the rest. The resolver sees what the job's earlier steps produced, both their outputs and the environment they wrote. A run without a host is unchanged: provider steps are still rejected upfront, or reported skipped when the run was told to skip them.
The run command now wires a GitHub Actions host into the runner's step host port. Before each job runs, the host expands every action the job's uses steps name and places the pre and post phases it declared around the job's own steps, the placement the library documents from the runner's own phases. When the run reaches a provider step, the host resolves it with the view that moment holds: a uses step expands against what the job's earlier steps produced, so a with mapping or a condition reading a step output works, and a step carrying a run has its condition, command text, environment and working directory evaluated as written. Local ./ references resolve against the workspace. A remote owner/repo reference is fetched as a tarball from the API, following the one redirect with the token re-attached, extracted once per reference into a directory the run removes at its end, and served as a tree. A node action's entry runs under the node the CLI itself runs under, with its inputs in the environment as the runner derives them. The neutral run context maps onto the github context's own names, needs results and step outputs reach expressions through the runner's reports, and secrets arrive by --secret name=value or --secret name, which reads the environment variable and never appears on a command line; the platform token is supplied as secrets.GITHUB_TOKEN wherever the run has one. Neither is printed, logged or stored. A docker:// reference and a step of another provider stay provider steps: skipped when the run was told to skip provider steps, and rejected naming them otherwise, as before. The demonstration is a unit test over the real CLI entry: a workflow imported then run through --local, using a composite action, a node action, a GITHUB_OUTPUT hand-off and an if gate, asserted on its effects on the workspace; a second test feeds a synthetic tarball through the injected fetch port and asserts the phase placement; docker, secrets and shell rejections are held to their messages.
…s declare Resolving the pinned actions/checkout through a host run showed two shapes its schemas rejected that GitHub's own syntax page carries and actions in wide use declare: an input's default written with no value, which reads as null and means no default (mapped as absent, not the text null), and a node action's outputs at the root of its metadata, each a description with no value because the entry sets the value at run time through its output file. A composite action's outputs stay under runs with their expressions, which is where that form declares them.
Fetches the pinned actions/checkout over the network through the same resolver a run supplies, extracts the tarball, and reads its metadata as the node action it is and its entry file. The token goes along when the environment holds one, so a private clone resolves it too. The extraction also learned the shape real tarballs carry that the synthetic feed did not: a directory entry for the repository root itself, and directory names ending in the slash that ends them.
…wned The Run directly and Import sections of the README and the runner discussion in docs/providers.md now describe the two moments a run resolves GitHub's own steps in, the context expressions evaluate with, where secrets and the platform token come from, and the constructs that stay provider-owned unless the run was told to skip them.
Mearman
force-pushed
the
feat/host-run-wiring
branch
from
October 11, 2026 22:05
7b55288 to
2931d7e
Compare
A wrapper-form call runs one step range of a job while the provider's own runner has already run the steps around it as native steps, so preparing the whole job expanded actions whose steps were outside the range, fetching and even failing on them. The preparation view now carries the range, and a host resolves the actions of the steps that will run, so a step outside the range contributes nothing, not even the phases its action declares. Caught by this repository's own wrapper-form test job in CI.
The metadata syntax page documents an optional author, which actions/setup-node and other published actions carry, so it is read as data beside the branding rather than rejected. The three actions this repository's own pipeline pins all parse against the node schema now.
Member
Author
|
@codex security review |
Mearman
marked this pull request as ready for review
October 11, 2026 22:25
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
🎉 This PR is included in version 0.6.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Runs an imported native workflow end to end on the host through one command:
importthenrun --localexecutes a node action, a composite action, aGITHUB_OUTPUThand-off between steps and anif:gate reading a step output, with no container and no generated file (#76, on top of #77's evaluator, #80's runner file commands, #81's composite resolution and #82's node expansion).The runner's run options gain a step host port: before a job runs, the host is asked to prepare the job's steps for the combination about to run, and when the run reaches a provider step the preparation left in place, the host resolves it into the commands to run, each of which receives the runner's file commands and its own report entry like a native step. A run without a host is unchanged. The conformance kit covers the port: placement, per-command reports and file commands, the first failure stopping the rest, resolution against what earlier steps produced, the skip and unhandled answers, and that a job which does not run is never prepared.
The CLI supplies that host for GitHub's steps, in the two moments the hosted runner itself works in. Before a job runs it expands every action the job's
usessteps name and places thepreandpostphases it declared around the job's own steps, the placement the library documents from the runner's own phases; the expanded steps are discarded, because the same action expands again when the step is reached, against what the job's earlier steps by then produced, which is the view GitHub evaluates awith:mapping and a step condition with. A step carrying aruninstead resolves directly: its condition decides whether it runs, and its command text, environment and working directory are evaluated as written. The neutral run context maps onto thegithubcontext's own names, step outputs and needed-job results reach expressions through the runner's reports, and secrets arrive by--secret name=valueor--secret name, which reads the environment variable of that name; neither secret values nor the token are printed, logged or stored. Local./references resolve against the workspace, anowner/repo@refreference is fetched as a tarball from the API with the token re-attached across the one redirect, extracted once per reference by a reader that carries the pax headers a repository tarball actually holds, and removed at the run's end; a node action's entry runs under the CLI's own node.A wrapper-form call runs one step range of a job while the provider's own runner has already run the steps around it as native steps, so the preparation view carries the range and a host resolves the actions of the steps that will run; this repository's own wrapper-form test job in CI is what caught that.
A
docker://reference and another provider's steps stay provider-owned, skipped by--skip-provider-stepsand failing the run without it; the same flag now skips whole actions, for a host that has already supplied the toolchain those steps would install, which is what this repository's own local pipeline run passes it for.Resolving the real pinned
actions/checkoutthrough the fetching resolver showed metadata shapes the node schema wrongly rejected, fixed here: an inputdefaultwritten with no value, which reads as null and means no default; a node action's outputs at the root of its metadata, each a description with no value because the entry sets the value at run time; and the optionalauthorthe syntax page documents. The three actions this repository's own pipeline pins all parse against the schema now.The demonstration is a unit test over the real CLI entry with real ports: a workflow fixture holding a composite action and a node action, imported then run through
--local, asserted on its effects on the workspace (files written, the output hand-off reaching a later expression, the gated step skipped when its condition is false, the secret never echoed), a second test feeding a synthetic tarball through the injected fetch port with a pax global header and a long path and asserting the pre/main/post placement, and tests holding the docker, missing-secret and shell rejections to their messages. The integration suite resolves the pinned checkout action over the network through the same resolver and reads its metadata as the node action it is.Fixes #76