ci: fix all actionlint/shellcheck findings, wire actionlint into Lint (#247) - #271
Merged
Conversation
actionlint (which shells out to shellcheck per `run:` block) had never been run in any CI gate, so 15 findings across ci.yml, release.yml, publish-ccplugins.yml and sync-ccplugins-fork.yml were latent and undetected (the issue's own reproduction quoted 5 of them; the other 10 were already present in ci.yml and publish-ccplugins.yml at the same commit — verified by re-running actionlint against f606c37 directly). actionlint's acceptance criterion 3 ("runs clean on .github/workflows/") requires all of them fixed, not only the 5 named in the title, since the newly-wired gate would fail on day one otherwise. Root cause and fix per finding: - SC2015 (3x, ci.yml + release.yml postgres-setup step) and SC2034 (1x each): the `A && break || sleep` retry idiom is ambiguous AND silently swallows exhaustion (all N attempts fail -> the for loop still exits 0, since the last statement executed was `sleep`, and the failure surfaces later as an opaque, unrelated error). Rewritten as explicit `if/then/break` with an attempt counter that both loops now read (fixing SC2034 by *using* the counter, not renaming it) and an explicit `exit 1` with a message when a loop exhausts every attempt (matching this repo's existing retry-with- backoff-fail-loudly convention used for the HF/FlashRank model downloads). Verified with a bash harness exercising both the success and exhaustion paths, and under `set -euo pipefail`. - SC2086 (release.yml changelog step): `${PREV_TAG}..HEAD` unquoted -> quoted. Same class of finding (release.yml, publish-ccplugins.yml `$UPSTREAM`) fixed by quoting each occurrence. - SC2046 (publish-ccplugins.yml): unquoted `$(date ...)` embedded in `echo manual-$(date ...)` -> quoted. - SC2129 (publish-ccplugins.yml + sync-ccplugins-fork.yml Summary steps): individual `>> "$GITHUB_STEP_SUMMARY"` redirects per echo -> one `{ ...; } >> file` block. Wiring: ci.yml's Lint job now downloads actionlint 1.7.12 from its GitHub Release, verifies it against the release's own linux_amd64 sha256 (recomputed locally against the published checksums.txt, not trusted blindly), and runs `actionlint -color` — pinned by tag + checksum rather than `go install @latest` / curl|bash, matching this repo's supply-chain-hardening stance. Verification (criterion 5): the runner-local PostgreSQL retry-loop fix is identical in ci.yml and release.yml; ci.yml's `test` job exercises it on every push/PR, giving a real (not just YAML-read) execution. release.yml's own `test` job only runs on a `v*` tag push, so `workflow_dispatch` was added as a verification-only trigger; the release-producing jobs (github-release, build, sbom, publish-pypi) are gated to `startsWith(github.ref, 'refs/tags/')` so a dispatched run cannot cut a release, publish to PyPI, or fire the ccplugins-fork publish workflow — it only proves `test` passes. Fixes #247 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Yu6EnWspTfqHoGkExyS6u
cdeust
force-pushed
the
fix-actionlint-wiring-247
branch
from
July 30, 2026 00:25
9a70490 to
9c79fad
Compare
This was referenced Jul 30, 2026
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.
Summary
Fixes #247.
actionlintwas never wired into any CI gate, so its findingsacross
.github/workflows/were latent and undetected. This PR fixes everyfinding
actionlintreports against the repo (15 total across 4 files — theissue quoted 5; the other 10 were already present in
ci.ymlandpublish-ccplugins.ymlat the commit the issue cites,f606c37, confirmed byre-running
actionlintagainst that exact commit) and wiresactionlintinto
ci.yml'sLintjob so this class of defect is gated from now on.Acceptance criteria (issue #247):
SC2034(i appears unused) inrelease.ymlresolved by wiring thecounter into a real use (attempt-count message + a fail-loud exit when the
retry loop exhausts every attempt), not by renaming it to
_— done.actionlintruns clean on.github/workflows/— verified locally(
actionlintexit 0) and gated in CI going forward.actionlintwired into CI'sLintjob, pinned version — done(
ci.yml, "Install actionlint (pinned, checksum-verified)" +"Check workflow files (actionlint + shellcheck)").
release.ymlchanges proven by one real run, not by reading the YAML —see below.
What changed and why (root cause, not a band-aid)
ci.yml+release.ymlpostgres-setup step(byte-identical block in both files): the
cmd && break || sleep Nretryidiom is not just ambiguous shell (shellcheck's literal complaint) — it
silently swallows exhaustion. If all N attempts fail, the
forloop's lastexecuted statement is
sleep, which succeeds, so the loop's own exit statusis 0 and the real failure only surfaces later as an unrelated, confusing
error further down the step. Rewritten as explicit
if/then/breakwith theattempt counter now read (an echo on each failed attempt) and an explicit
exit 1with a message when a loop exhausts every attempt — matching thisrepo's own established retry-with-backoff-fail-loudly convention (used for
the HF/FlashRank model pre-download steps in
ci.yml). Verified with astandalone bash harness exercising both the success and full-exhaustion
paths under
set -euo pipefail.release.ymlchangelog step:${PREV_TAG}..HEADunquoted →quoted.
publish-ccplugins.yml:$UPSTREAMunquoted at three callsites → quoted.
publish-ccplugins.yml: unquoted$(date ...)embedded inecho manual-$(date ...)→ quoted.publish-ccplugins.yml+sync-ccplugins-fork.ymlSummarysteps: individual>> "$GITHUB_STEP_SUMMARY"redirects perecho→ one{ ...; } >> fileblock.Wiring (criterion 4)
ci.yml'sLintjob downloadsactionlint1.7.12 from its GitHub Release,verifies the download against the release's own linux_amd64 sha256 (recomputed
locally from the published
checksums.txt, not trusted blindly — see the# source:comment at the install step), then runsactionlint -color.Pinned by release tag + checksum rather than
go install @latestorcurl | bash, consistent with this repo's existing supply-chain-hardeningstance (
release.yml's attestation/SBOM/hash-pinning discipline).Verification (criterion 5)
The postgres-setup fix is identical in
ci.ymlandrelease.yml;ci.yml'stestjob runs it on every push/PR (this PR's own CI run proves it, acrossthe Python 3.10–3.13 matrix) — a real execution, not a YAML read.
release.yml's owntestjob only triggers on av*tag push, so this PRadds
workflow_dispatchpurely as a verification lane: everyrelease-producing job (
github-release,build,sbom,publish-pypi) isnow gated to
startsWith(github.ref, 'refs/tags/'), so a dispatched runexecutes
test(proving the fix) and stops there — it cannot cut a release,publish to PyPI, or trigger the downstream ccplugins-fork publish workflow.
I dispatched a run on this branch after opening this PR; see the Actions tab
for
release.yml/workflow_dispatchonfix-actionlint-wiring-247.Completion Ledger
ci.ymlpostgres retry: apt-get update loop, structured if/breaktestjob (4-way matrix)ci.ymlpostgres retry: apt-get install loop, structured if/breakci.ymlpostgres retry: pg_isready loop, structured if/breakexit 1arm (×3 loops, ×2 files)test_exhaustion_path— asserts non-empty$okguard triggers the message + exit 1 underset -euo pipefailci.ymlactionlint install + checksum verifysha256sum -cagainst the hardcoded checksum passes,tarextracts a valid linux/amd64 ELFci.ymlactionlint run stepactionlintexit 0 on the fixed tree (was exit 1, 15 findings, before this PR)release.ymlchangelog SC2086 fixTAG=manual-<date>— single well-formed token, regex-verifiedpublish-ccplugins.ymlSC2046/SC2086/SC2129 fixesactionlintclean; SC2129 redirect-block behavior verified with a standalone bash snippet (writes the same lines to a temp file)sync-ccplugins-fork.ymlSC2129 fixrelease.ymlworkflow_dispatch+ tag-only gates on 4 jobsactionlintclean (no expression/job-graph errors); dispatched run on this branch (see Actions tab) —testruns, the 4 gated jobs reportskippedBoy-scout check
No other defects were seen in the touched files beyond the 15 actionlint
findings themselves, which are exactly what this PR closes.