🐛 fix(ci): anchor the dist_* wiring gate to the lint job's steps - #325
Merged
Conversation
The gate compared file-global line numbers and locked onto the first `head -1` match. Moving the operator-sdk install step out of `lint` into the earlier `gitleaks` job kept it green -- rc=0, "ok - ci.yaml installs operator-sdk before the dist_* glob" -- while the job that actually runs the dist_* glob had no binary. That is exactly the permanent red the gate exists to prevent. Every anchor is now resolved with yq over `.jobs.lint.steps`: a matching step in another job is not a match, and each anchor must resolve to exactly one step, so a duplicate fails loudly instead of silently resolving to the first hit. Type guards on `.jobs.lint` and `.jobs.lint.steps` stop a renamed job from making the whole gate select over an empty list. A self-test mutates the real workflow with yq and asserts the checks reject all three shapes (install moved to gitleaks, installed twice, installed after the glob), so the gate proves its own non-vacuity on every CI run rather than only on the happy path.
The diff printed above the failure is symmetric -- "<" is a config/crd/bases kind absent from spec.customresourcedefinitions.owned, ">" is an owned[] entry whose CRD base is gone -- but the remedy named only the first direction. On a stale owned[] entry it told the reader to declare every config/crd/bases kind under owned, which is the opposite of the fix and sends them looking for a kind that is already there. State both directions and tie each to the diff marker that produced it.
… not comments
The operator-sdk assertion grepped the raw release.yaml while this same
script already establishes a comment-stripped view for exactly this
reason. release.yaml documents the operator-sdk prerequisite in a comment
directly above the step that installs it, so commenting out the run: line
left the gate green: with the install disabled the check still printed
'All dist OperatorHub PR tests passed.' at rc=0.
The story named ${CODE}; that variable is derived from
hack/operatorhub-pr.sh, so reusing it here would assert about a different
file. Applied the same discipline through a workflow-scoped
${WORKFLOW_CODE} instead.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
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.



Problem
The
dist_*wiring gate was structurally unable to detect the failure it exists toprevent. It located its anchors by grepping the whole
ci.yamlfor line numbersand took the first hit with
head -1. File-global positions carry no job scope, somoving the
operator-sdkinstall step out oflintinto any other job — anywhereearlier in the file — still satisfied "install comes before the glob". The gate stayed
green while the
lintjob ran thedist_*test glob with nooperator-sdkbinary onPATH.
Fix
The gate now resolves every anchor via
yqover.jobs.lint.stepsspecifically, so astep in a sibling job is simply not visible to it. Each anchor must match exactly
once — zero matches and duplicate matches are both hard failures, closing the
head -1hole where a second copy masked a moved original. Ordering is asserted onstep indices within the job, not on file lines.
The gate ships a built-in self-test: it mutates the real workflow into each known
broken shape and asserts the gate rejects it. That makes the gate's own detection power
a tested property rather than an assumption.
dist_olm_bundle_test.shanddist_operatorhub_pr_test.shget the same anchoringcorrection applied to their smaller equivalents.
Verification
An independent reviewer ran a 16-shape mutation sweep and confirmed 11 of 16 shapes
are now caught, versus roughly 0 for the old gate. The fix was proven by
differential: the same mutated
ci.yamlleaves the old gate green (rc=0) and makes thenew gate red (rc=1).
Scope
Three shell test scripts. Zero Go files, zero workflow files — no runtime or CI
behaviour changes, only the gate that guards it.