Add actionlint pre-commit hook for .forgejo/workflows/ #88

Closed
opened 2026-06-18 01:01:07 +00:00 by james · 0 comments
Owner

Local-side half of the dual-layer workflow linting plan. Sister to #89 (CI side).

The ad-hoc python3 -c 'import yaml; yaml.safe_load(...)' checks scattered through recent PRs only catch parse errors. actionlint validates against the GitHub-Actions schema (which Forgejo's act_runner mirrors closely) and catches the issues that actually bite us:

  • Invalid step keys (e.g. id: vs name: typos)
  • Undefined ${{ github.* }} / ${{ steps.*.outputs.* }} references
  • Shell-injection patterns (overlaps with the Semgrep rule that hit us in #16)
  • Unreachable if: conditions, deprecated set-output, missing required fields
  • shellcheck-quality findings on every run: block (since actionlint shells out to shellcheck)

Scope

  • Add a pre-commit entry to lefthook.yml that runs actionlint on staged .forgejo/workflows/*.yml files. Mirror the gitleaks hook's shape: small wrapper, clear failure message, supports the existing LEFTHOOK_EXCLUDE=<name> skip pattern.
  • Document the runtime requirement in the project README "Requirements" section, same place gitleaks is mentioned. actionlint is a single Go binary; brew install actionlint works on macOS/Linux. Don't add it as an npm dep.
  • Adjust the existing lavamoat.allowScripts only if actionlint installation somehow pulls in a new dev npm dep (it shouldn't — it's a standalone binary).

Acceptance criteria

  • git commit touching a .forgejo/workflows/*.yml triggers the hook.
  • A workflow with an ${{ github.foo }} (invalid context) fails the hook with a actionlint finding cited.
  • A workflow with no issues passes silently.
  • LEFTHOOK_EXCLUDE=actionlint git commit ... skips the check for one commit; --no-verify stays the last resort.

Coordination

Should land alongside, or shortly after, #89 (CI side) so local skipped/missing checks don't silently pass through CI. ADR-0011 captured the dual-layer rationale for gitleaks — same pattern applies.

Part of epic #2.

Local-side half of the dual-layer workflow linting plan. Sister to #89 (CI side). The ad-hoc `python3 -c 'import yaml; yaml.safe_load(...)'` checks scattered through recent PRs only catch parse errors. [`actionlint`](https://github.com/rhysd/actionlint) validates against the GitHub-Actions schema (which Forgejo's `act_runner` mirrors closely) and catches the issues that actually bite us: - Invalid step keys (e.g. `id:` vs `name:` typos) - Undefined `${{ github.* }}` / `${{ steps.*.outputs.* }}` references - Shell-injection patterns (overlaps with the Semgrep rule that hit us in #16) - Unreachable `if:` conditions, deprecated `set-output`, missing required fields - shellcheck-quality findings on every `run:` block (since `actionlint` shells out to shellcheck) ## Scope - Add a `pre-commit` entry to `lefthook.yml` that runs `actionlint` on staged `.forgejo/workflows/*.yml` files. Mirror the gitleaks hook's shape: small wrapper, clear failure message, supports the existing `LEFTHOOK_EXCLUDE=<name>` skip pattern. - Document the runtime requirement in the project README "Requirements" section, same place gitleaks is mentioned. `actionlint` is a single Go binary; `brew install actionlint` works on macOS/Linux. Don't add it as an npm dep. - Adjust the existing `lavamoat.allowScripts` only if `actionlint` installation somehow pulls in a new dev npm dep (it shouldn't — it's a standalone binary). ## Acceptance criteria - [ ] `git commit` touching a `.forgejo/workflows/*.yml` triggers the hook. - [ ] A workflow with an `${{ github.foo }}` (invalid context) fails the hook with a `actionlint` finding cited. - [ ] A workflow with no issues passes silently. - [ ] `LEFTHOOK_EXCLUDE=actionlint git commit ...` skips the check for one commit; `--no-verify` stays the last resort. ## Coordination Should land alongside, or shortly after, #89 (CI side) so local skipped/missing checks don't silently pass through CI. ADR-0011 captured the dual-layer rationale for gitleaks — same pattern applies. Part of epic #2.
james closed this issue 2026-06-18 01:29:45 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#88
No description provided.