Add actionlint check to PR CI #89

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

CI-side half of the dual-layer workflow linting plan. Sister to #88 (local hook).

The CI step catches the cases the local hook can't: a contributor without actionlint installed, git commit --no-verify, force-push to a long-lived branch — same threat model gitleaks' CI workflow was built to cover (ADR-0011).

Scope

  • Add a workflow-lint step. Two reasonable places:
    • Sibling step inside the existing static-analysis job in pr.yml — minimal cost, runs after Semgrep, reuses the same runner image. Recommended.
    • Or a dedicated tiny job. Only worth it if actionlint's install or output is meaningfully separate from Semgrep's.
  • Install actionlint by pinned version from the upstream release URL (same pattern as OSV_SCANNER_VERSION / TRIVY_VERSION in pr.yml's env: block). Renovate's github-actions manager covers Forgejo Actions but not arbitrary binary pins; add a small regexManagers entry in renovate.json if drift becomes painful.
  • Output should land in $GITHUB_STEP_SUMMARY so a failed run shows the findings inline — same pattern as scripts/ci/security-summary.mjs. May not need its own summarizer; actionlint exits non-zero with a readable text report.
  • Scope: lint every .forgejo/workflows/*.yml file in the repo, not just diff-touched files. The set is tiny (4 files today) and rule-pack changes can expose new findings on files no PR touched.

Acceptance criteria

  • A PR that introduces an invalid ${{ github.foo }} context expression in a workflow file fails CI with the actionlint finding visible.
  • A PR with clean workflow files passes the step in <30s.
  • The version pin lives in the workflow env: block alongside OSV_SCANNER_VERSION and friends, with a comment matching the existing tone.
  • The new step is named recognizably (e.g. "Lint workflows (actionlint)") so a failed run is greppable in the run UI.

Coordination

Should land alongside, or shortly after, #88 (local hook). ADR-0011's dual-layer rationale for gitleaks applies here too — local hook for fast feedback, CI step for enforcement against contributors who bypassed it.

Out of scope today: extending actionlint to lint composite actions in this repo (we don't ship any yet), or integrating shellcheck findings into the existing security summary (actionlint already calls shellcheck under the hood).

Part of epic #2.

CI-side half of the dual-layer workflow linting plan. Sister to #88 (local hook). The CI step catches the cases the local hook can't: a contributor without `actionlint` installed, `git commit --no-verify`, force-push to a long-lived branch — same threat model gitleaks' CI workflow was built to cover ([ADR-0011]). [ADR-0011]: docs/adr/0011-gitleaks-ci.md ## Scope - Add a workflow-lint step. Two reasonable places: - **Sibling step inside the existing `static-analysis` job in `pr.yml`** — minimal cost, runs after Semgrep, reuses the same runner image. Recommended. - Or a dedicated tiny job. Only worth it if `actionlint`'s install or output is meaningfully separate from Semgrep's. - Install `actionlint` by pinned version from the upstream release URL (same pattern as `OSV_SCANNER_VERSION` / `TRIVY_VERSION` in `pr.yml`'s `env:` block). Renovate's `github-actions` manager covers Forgejo Actions but not arbitrary binary pins; add a small `regexManagers` entry in `renovate.json` if drift becomes painful. - Output should land in `$GITHUB_STEP_SUMMARY` so a failed run shows the findings inline — same pattern as `scripts/ci/security-summary.mjs`. May not need its own summarizer; `actionlint` exits non-zero with a readable text report. - Scope: lint every `.forgejo/workflows/*.yml` file in the repo, not just diff-touched files. The set is tiny (4 files today) and rule-pack changes can expose new findings on files no PR touched. ## Acceptance criteria - [ ] A PR that introduces an invalid `${{ github.foo }}` context expression in a workflow file fails CI with the `actionlint` finding visible. - [ ] A PR with clean workflow files passes the step in <30s. - [ ] The version pin lives in the workflow `env:` block alongside `OSV_SCANNER_VERSION` and friends, with a comment matching the existing tone. - [ ] The new step is named recognizably (e.g. "Lint workflows (actionlint)") so a failed run is greppable in the run UI. ## Coordination Should land alongside, or shortly after, #88 (local hook). ADR-0011's dual-layer rationale for gitleaks applies here too — local hook for fast feedback, CI step for enforcement against contributors who bypassed it. Out of scope today: extending `actionlint` to lint composite actions in this repo (we don't ship any yet), or integrating shellcheck findings into the existing security summary (actionlint already calls shellcheck under the hood). Part of epic #2.
james closed this issue 2026-06-18 01:42:37 +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#89
No description provided.