chore(ci): add actionlint + prettier check on PRs#12
Conversation
ci-workflows hosts reusable workflows that other projects pull in via `uses:`. A typo here (bad expression syntax, deprecated runner, undefined `steps.X` output ref) silently breaks every downstream consumer. CI gate prevents that. Why not husky/lint-staged: this repo has no package.json. Pulling in a JS toolchain to format three files isn't worth the dependency footprint. CI-only enforcement is the right shape for a YAML+Markdown repo — actionlint covers the GHA-specific bugs prettier can't see, and prettier covers the README. Bundled in the same PR (small fixes that would otherwise immediately fail the new lint job): - `pr-classify.yml`: shellcheck inline disable for SC2001 on the intentional `sed 's/^/ /'` multiline indent. sed is clearer than the bash parameter-expansion alternative for this case. - `README.md`: prettier --write to clean up pre-existing drift. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
|
||
| - name: Download actionlint | ||
| id: get_actionlint | ||
| run: bash <(curl -s https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) |
There was a problem hiding this comment.
Supply-chain risk: unpinned main-branch curl | bash
This fetches and executes a script from rhysd/actionlint's main branch with no integrity check. Any commit to that branch — including a compromise — lands immediately in this repo's CI with no review gate.
This is especially risky here because ci-workflows is a shared-reusable-workflow host: a poisoned actionlint binary could exfiltrate secrets injected by downstream callers.
Safer alternatives (in order of preference):
- Pin to a specific version tag using the official action:
| run: bash <(curl -s https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) | |
| uses: rhysd/actionlint@v1.7.7 |
(replace with the current release; pinning to a SHA gives the strongest guarantee)
- Or, if you must use the download script, pin to a commit SHA:
run: bash <(curl -s https://raw.githubusercontent.com/rhysd/actionlint/<COMMIT_SHA>/scripts/download-actionlint.bash)
|
Flagged 1 issue inline — unpinned |
Adds workflow_call trigger so other repos can call this via
uses: topcoder1/ci-workflows/.github/workflows/lint.yml@main
Existing pull_request + push: main triggers stay so the workflow
self-tests on this repo. Inputs (all optional, sensible defaults):
- markdown_glob (default '**/*.md')
- run_actionlint (default true)
- run_prettier (default true)
Per-job `if:` guards skip jobs when called with the corresponding
input set to false; for non-workflow_call invocations both jobs
always run.
Companion change: ~/.claude/templates/ci-workflows/{callers,scripts}/
gains lint.yml caller template + install-lint.sh installer (mirrors
install-pr-review.sh shape).
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
|
||
| - name: Download actionlint | ||
| id: get_actionlint | ||
| run: bash <(curl -s https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) |
There was a problem hiding this comment.
Supply chain risk: fetching from unpinned main branch
This curl | bash pulls from rhysd/actionlint@main with no version pin and no checksum verification. If that branch is ever compromised, the malicious script runs immediately in every subsequent CI run — and because this is a reusable workflow, all downstream consumers are exposed too.
Pin to a specific release tag so the content is immutable:
| run: bash <(curl -s https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) | |
| run: bash <(curl -s https://raw.githubusercontent.com/rhysd/actionlint/v1.7.7/scripts/download-actionlint.bash) |
Or use the official action pinned to a SHA for stronger guarantees:
- uses: rhysd/actionlint@11f75d9775d0829b8fdc43df25c96a6e4ba40de1 # v1.7.7(No id: / outputs.executable step needed with the action form.)
|
Flagged 1 issue inline — unpinned curl-pipe-bash for actionlint download is a supply chain risk given this repo serves reusable workflows to downstream consumers. |
Summary
ci-workflows hosts reusable workflows that other projects pull in via
uses:. A typo here (bad expression syntax, deprecated runner version, undefinedsteps.X.outputs.Yreference) silently breaks every downstream consumer. This adds a CI gate to catch those before they merge.Companion to whois-api-llc/wxa-jake-ai#178 and qwibitai/nanoclaw#2171, which wired husky+lint-staged on JS repos. ci-workflows gets a different shape because it has no
package.json— pulling in a JS toolchain to format three files isn't worth the dependency footprint. CI-only enforcement is the right call for a YAML+Markdown repo.What's in this PR
1.
.github/workflows/lint.yml— newactionlintjob: downloads the official binary and runs it onpull_request+ push to main. Catches GHA-specific bugs prettier can't see (and includes embedded shellcheck forrun:blocks).prettierjob: runsprettier --check **/*.md. Just the README today; future-proof for any docs added later.2.
pr-classify.yml— shellcheck inline disable for SC2001The intentional
echo "$changed" | sed 's/^/ /'indents multiline output. shellcheck suggested${var//.../...}but for "prepend N spaces to each line" sed is clearer than bash parameter expansion gymnastics. Documented inline.3.
README.md— prettier --writeCleaning up pre-existing drift so the new check starts green.
Pre-flight done locally
actionlint -color→ clean (was flagging SC2001 before the inline disable)npx prettier@3 --check "**/*.md"→ clean (was flagging README before --write)What this does NOT add
.shscripts (no scripts in repo today; revisit if any get added)🤖 Generated with Claude Code