fix(ci): move linter workflow into .github so GitHub actually runs it - #87
Merged
Conversation
The linter workflow landed at `github/workflows/linter.yml` — no leading dot — which created a stray top-level `github/` directory alongside the real `.github/`. GitHub only reads workflows from `.github/workflows/`, so the workflow never ran. Its job is named `run-lint`, which is the context the "Protect Main Branch" ruleset requires. With the file unreachable, that required check could never report and every pull request sat at BLOCKED indefinitely — the entire #72-#86 backlog had to be merged with admin bypass. Moving the file to `.github/workflows/linter.yml` lets the job run and lets the required check resolve on its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Moving the workflow into .github/ made run-lint report for the first time
— and it failed immediately, on a pull request whose only change was the
rename itself.
Super-linter runs every validator it can detect unless at least one
VALIDATE_* is set to true. Three of those defaults are wrong here:
- JSCPD uses a 0% duplicate threshold and found 9.53% across 41 clones.
Most of those are the .cjs/.js module twins (canvas-crawler,
parser-helper, dossier-compiler, evidence-base, prompts,
renderer-helper) that CLAUDE.md mandates so the modules stay both
node-testable and browser-loadable. The validator flags the
architecture as a defect.
- CHECKOV failed CKV2_GHA_1 on linter.yml and test.yml for not
declaring top-level permissions.
- YAML_PRETTIER failed on linter.yml's own formatting.
Naming a validator switches super-linter to opt-in, so this pins the set
to the three that pass on this repo and are worth gating on: actionlint
(the class of bug that caused this), gitleaks (the extension handles API
keys), and yamllint.
Bash is deliberately excluded. shellcheck reports 52 findings across the
29 shell files — 4 errors, 5 warnings, 43 notes, 14 of them SC2086. That
is worth fixing, but as its own change, not as a gate that blocks every
pull request from day one.
Also adds the least-privilege permissions block, which resolves the
"Failed to call GitHub Status API: 403" errors in the run log, and
cleans up the formatting yamllint warned about.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
savvides
added a commit
that referenced
this pull request
Aug 30, 2026
…ase.yml (#88) #87 turned on VALIDATE_GITHUB_ACTIONS, which runs actionlint over every workflow. release.yml does not currently pass it. actionlint feeds `run:` blocks to shellcheck, substituting each `${{ }}` expression with an underscore placeholder of equal length first. At 22 characters, `${{ github.ref_name }}` became: if [ "v$VER" != "______________________" ]; then The left operand starts with a literal `v` and the right operand cannot, so shellcheck reports SC2193 — "the arguments to this comparison can never be equal" — and actionlint exits 1. Binding the expression to an env var and comparing against `$TAG_NAME` removes the placeholder from the compared text, so the check passes. Verified locally: the placeholder form exits 1 on SC2193, the env form exits 0. This is also the pattern GitHub recommends for reaching context values from a run block, since interpolating `${{ }}` straight into a shell script is the script-injection shape. Not exploitable here — the trigger is restricted to `v*` tags — but the safe form is two lines. No behaviour change: same comparison, message, and exit code. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
4b96052added the linting workflow atgithub/workflows/linter.yml— missing the leading dot — which left a stray top-levelgithub/directory sitting next to the real.github/:GitHub only reads workflows from
.github/workflows/, so the workflow never ran.Why it mattered
The job is correctly named
run-lint, which is exactly the context the Protect Main Branch ruleset requires:{ "type": "required_status_checks", "parameters": { "required_status_checks": [ { "context": "run-lint" } ] } }A required check that can never report blocks merging forever. That is why the entire #72–#86 backlog sat at
BLOCKEDsince Aug 22 and had to be merged with admin bypass.Fix
git mv github/workflows/linter.yml .github/workflows/linter.yml, and remove the now-empty stray directory. The workflow content is unchanged — this is a pure rename.Heads-up on what this turns on
Worth knowing before this lands, because it changes CI behaviour repo-wide:
VALIDATE_ALL_CODEBASE: falselints only files changed in a PR. So this PR only exercises the YAML validator on the renamed file — it passing does not prove future PRs pass.VALIDATE_*variable is set totrue, which means super-linter enables every validator it can detect, rather than an opt-in subset.package.json,.eslintrc,.shellcheckrc,.markdownlint.json,pyproject.toml, or.editorconfig.The practical effect is that the first PR to touch a shell script or a JS file gets linted by shellcheck/eslint defaults with no project config to soften them. If that turns out to be noisy, the fix is to pin the validator set explicitly (
VALIDATE_GITHUB_ACTIONS: true,VALIDATE_JSON: true, …) rather than to unpin the required check again.🤖 Generated with Claude Code