Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
name: Lint

# Lint GitHub Actions workflows with actionlint (embeds shellcheck for `run:`
# block bash). Catches GitHub Actions specific issues (deprecated actions,
# unsafe `${{ ... }}` interpolation, missing permissions, stale runner labels)
# plus shellcheck-detectable bash issues.
# Lint GitHub Actions workflows with actionlint (which embeds shellcheck for
# `run:` block bash). Coverage:
# - GitHub Actions specific issues (unknown event types, deprecated actions,
# missing required permissions, unsafe `${{ ... }}` interpolation in `run:`,
# stale runner labels, etc.)
# - Shellcheck rules on `run:` blocks (unquoted variables, glob misuse,
# suspicious arithmetic, command substitution mistakes, etc.)
#
# Known *not* caught (still requires reviewer / Copilot eye):
# - `set -euo pipefail` × `var=$(... | jq ...)` exit propagation when jq
# parse fails on malformed JSON. Shellcheck does not model this control-
# flow chain. We mitigate with `|| true` guards in the workflows that need
# it (see comments in copilot-clean-label.yml stuck-detector for the
# reference pattern).
#
# Scope: only runs when workflow files or actionlint config change. Cheap, and
# avoids noise on non-CI PRs.
#
# Note: composite actions (.github/actions/) are NOT linted by actionlint's
# default invocation. When composite actions are added, update actionlint_flags
# to pass those paths explicitly.

on:
pull_request:
paths:
- '.github/workflows/**'
- '.github/actions/**'
- '.github/actionlint.yaml'
push:
branches: [main]
paths:
- '.github/workflows/**'
- '.github/actions/**'
- '.github/actionlint.yaml'

permissions: {}

Expand All @@ -24,16 +41,29 @@ jobs:
timeout-minutes: 3
permissions:
contents: read
# `checks: write` is required for reviewdog's `github-pr-check` reporter
# to post annotations via the Checks API. Without it, findings only
# appear in the run log — not as inline annotations on the PR diff.
checks: write
pull-requests: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: actionlint
# Pinned to v1.72.0 SHA (released 2026-03-31). Bumps via dependabot.
# Pin to v1.72.0 SHA (released 2026-03-31). Update manually or add a
# `.github/dependabot.yml` entry for github-actions to automate bumps.
# Wraps `rhysd/actionlint` v1.7.x which is the upstream linter.
uses: reviewdog/action-actionlint@6fb7acc99f4a1008869fa8a0f09cfca740837d9d # v1.72.0
with:
# `github-pr-check` posts annotations on the PR diff via the Checks
# API (requires `checks: write`, granted above). `level=error` makes
# the check fail on any actionlint finding so the PR cannot merge
# with lint failures.
reporter: github-pr-check
level: error
fail_level: any
# Pass `-color` for nicer terminal output in run logs. The action's
# default rules are kept; project-specific suppressions go in
# `.github/actionlint.yaml` (created only if needed).
actionlint_flags: -color
Loading