Skip to content

fix(ci): move linter workflow into .github so GitHub actually runs it - #87

Merged
savvides merged 2 commits into
mainfrom
fix/linter-workflow-path
Aug 30, 2026
Merged

fix(ci): move linter workflow into .github so GitHub actually runs it#87
savvides merged 2 commits into
mainfrom
fix/linter-workflow-path

Conversation

@savvides

Copy link
Copy Markdown
Owner

Problem

4b96052 added the linting workflow at github/workflows/linter.yml — missing the leading dot — which left a stray top-level github/ directory sitting next to the real .github/:

$ git ls-tree main --name-only | grep -i github
.github
github          <-- this one

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 BLOCKED since 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: false lints 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.
  • No VALIDATE_* variable is set to true, which means super-linter enables every validator it can detect, rather than an opt-in subset.
  • This repo has no linter config anywhere — no 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

savvides and others added 2 commits August 30, 2026 07:04
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
savvides merged commit f4be3b9 into main Aug 30, 2026
12 checks passed
@savvides
savvides deleted the fix/linter-workflow-path branch August 30, 2026 14:25
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>
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