Skip to content

fix(generate): enforce emitted-workflow validity; reject on_failure continue, gate hotfix inputs - #631

Merged
joshua-temple merged 2 commits into
mainfrom
feat/actionlint-feature-matrix-guard
Jul 18, 2026
Merged

fix(generate): enforce emitted-workflow validity; reject on_failure continue, gate hotfix inputs#631
joshua-temple merged 2 commits into
mainfrom
feat/actionlint-feature-matrix-guard

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Problem

Emitted workflows are actionlint-checked in CI only over the e2e scenario outputs, which exercise almost none of the documented manifest surface. So a documented feature could emit a workflow real GitHub rejects at parse while every scenario stayed green. Two such defects were confirmed:

  • on_failure: continue emitted continue-on-error: true on a reusable-workflow-call job (jobs.<id>.uses). GitHub forbids that key on a uses: job, so the whole orchestrate workflow was rejected at parse.
  • hotfix build passed sha and target_env unconditionally in its with: block. GitHub rejects a reusable-workflow call with undeclared workflow_call inputs, so every hotfix build failed at parse.

Fix

  • New guard TestActionlint_FeatureMatrix: generates the full workflow set for a matrix over the documented emitted-affecting manifest surface (on_failure, hotfix inputs, build matrix, deployments, rollback dispatch, retries, cancel_in_progress, components) and runs actionlint over every emitted file. Extensible by adding a row.
  • on_failure: continue is rejected at config validation. A tolerated failure cannot be expressed for a reusable-workflow-call job, so cascade refuses it loudly rather than emit invalid YAML; abort (the default) is the only supported value. The generator no longer emits continue-on-error under any input.
  • The hotfix build with: block now gates each input on the callee's declared workflow_call inputs, mirroring the orchestrate path; a callee that declares neither gets no with: block.
  • Adds an e2e scenario exercising the on_failure field (no prior scenario set it), updates the manifest JSON schema (all three copies) and the reference docs, and records the byte-identical hotfix churn in CHANGELOG.

This closes the LOUD enforcement gap: cascade never emits a workflow real GitHub rejects at parse; it either expresses the feature correctly or rejects the config loudly.

Verification

  • Guard proven RED on both defects, then GREEN after the fixes (11/11).
  • go build ./..., go test ./... (3459), go test ./... -race (3459), golangci-lint run ./... all clean.
  • e2e module: go build + go vet clean; new scenario passes discovery, schema, and integrity.
  • cascade verify --own-repo: no drift. Schema copies byte-identical.
  • Golden churn is confined to the hotfix workflow's build with: blocks (undeclared sha/target_env removed); every other surface is byte-identical.

FLEET-RELEVANT (changes generated output).

@joshua-temple
joshua-temple force-pushed the feat/actionlint-feature-matrix-guard branch from 47c70ef to b317d50 Compare July 18, 2026 06:25
…puts

cascade emitted two workflows real GitHub rejects at parse that the e2e
scenario corpus never exercised. on_failure: continue put continue-on-error on
a reusable-workflow-call job (jobs.<id>.uses), which GitHub forbids; it is now
refused at config validation because a tolerated failure cannot be expressed
for such a job, and abort is the only supported value. The hotfix build
callback passed sha and target_env unconditionally, but GitHub rejects a
reusable-workflow call with undeclared workflow_call inputs; each input is now
gated on the callee's declared inputs.

A new actionlint feature-matrix guard generates the full workflow set for the
documented manifest surface and lints every emitted file, so a feature that
emits a workflow GitHub would reject is caught in unit tests rather than only
in production. Adds an e2e scenario exercising the on_failure field, updates
the manifest schema and reference docs, and records the byte-identical churn
in the hotfix workflow.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
… its coverage

The actionlint feature-matrix guard only ran on a developer machine: no CI
lane installed actionlint, so locateActionlint t.Skip'd and the guard green-
skipped in the merge gate, exactly the silent-pass failure it exists to
catch. Install actionlint (SHA-pinned to the workflow-lint version) before
'go test' in the validate.yaml test job and the pr.yaml unit-tests lane, and
make a missing binary under CI fatal instead of skipped via a pure
resolveActionlint decision function with its own unit test.

Wire the matrix to the T1 emitted-field census so a new emitted-affecting
field is forced into actionlint coverage automatically. A sweep drives
actionlint off emittedFieldRegistry (every spliced emitted field), a second
sweep drives it off 41 per-field mutators for the emitted-affecting allowlist
entries, and a classification test fails when an allowlist field lacks both a
not-emitted reason marker and a mutator. A new field lands in the registry or
the allowlist by the existing census, and from there this guard lints its
emitted output with no new code.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
@joshua-temple
joshua-temple force-pushed the feat/actionlint-feature-matrix-guard branch from b317d50 to 33de9db Compare July 18, 2026 07:43
@joshua-temple
joshua-temple merged commit e96fe3a into main Jul 18, 2026
21 checks passed
@joshua-temple
joshua-temple deleted the feat/actionlint-feature-matrix-guard branch July 18, 2026 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant