From 4c8766c99bea299af991a6089d4d041e82b86077 Mon Sep 17 00:00:00 2001 From: rldyourmnd Date: Tue, 4 Aug 2026 15:54:52 +0500 Subject: [PATCH] feat: extend actionlint with optional shellcheck support Signed-off-by: rldyourmnd --- .github/workflows/actionlint.yml | 53 ++++++++++++++++++++++++++++++++ CHANGELOG.md | 8 +++++ catalog/capabilities.yml | 3 +- catalog/runtime-coverage.yml | 8 ++--- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index 6d1cf54..1253e12 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -26,6 +26,18 @@ on: description: 'Optional extra static check after actionlint, e.g. a repository-local pin validator.' type: string default: '' + enable_shellcheck: + description: 'When true, also downloads (checksum-verified) and runs shellcheck on shell scripts after actionlint.' + type: boolean + default: false + shellcheck_version: + description: 'shellcheck release version to download (without a leading v).' + type: string + default: '0.11.0' + shellcheck_sha256: + description: 'SHA256 of shellcheck-v.linux.x86_64.tar.xz from the upstream checksums. Required when enable_shellcheck is true.' + type: string + default: '' permissions: {} @@ -91,6 +103,47 @@ jobs: - name: Run actionlint run: actionlint -color + - name: Download shellcheck (pinned + checksum-verified) + if: ${{ inputs.enable_shellcheck }} + env: + SHELLCHECK_VERSION: ${{ inputs.shellcheck_version }} + SHELLCHECK_SHA256: ${{ inputs.shellcheck_sha256 }} + run: | + set -euo pipefail + if [ -z "$SHELLCHECK_SHA256" ]; then + echo "enable_shellcheck is true but shellcheck_sha256 is empty; a SHA256 of shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz is required" >&2 + exit 1 + fi + curl -fsSL -o /tmp/shellcheck.tar.xz \ + "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" + echo "${SHELLCHECK_SHA256} /tmp/shellcheck.tar.xz" | sha256sum -c - + tar -xJf /tmp/shellcheck.tar.xz -C /tmp "shellcheck-v${SHELLCHECK_VERSION}/shellcheck" + # Install into a runner-writable directory (consistent with the + # actionlint binary above): GitHub-hosted runners let the job user + # write there, correctly isolated self-hosted runners must not need to. + mkdir -p "${RUNNER_TEMP}/bin" + install -m 0755 "/tmp/shellcheck-v${SHELLCHECK_VERSION}/shellcheck" "${RUNNER_TEMP}/bin/shellcheck" + echo "${RUNNER_TEMP}/bin" >> "$GITHUB_PATH" + "${RUNNER_TEMP}/bin/shellcheck" --version + + - name: Run shellcheck + if: ${{ inputs.enable_shellcheck }} + run: | + set -euo pipefail + # Recursive: glob every shell script under the checkout. `mapfile` + # tolerates spaces/quotes in paths; `git grep` scopes to tracked + # files only, which avoids scanning vendored/ignored noise. + if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + mapfile -t scripts < <(git grep -Il '' -- '*.sh') + else + mapfile -t scripts < <(find . -type f -name '*.sh') + fi + if [ "${#scripts[@]}" -eq 0 ]; then + echo "no shell scripts found; nothing to check" + exit 0 + fi + shellcheck --check-sourced --external-sources "${scripts[@]}" + - name: Run post-actionlint command if: ${{ inputs.post_command != '' }} env: diff --git a/CHANGELOG.md b/CHANGELOG.md index ecb4019..12f0dc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,14 @@ ### Added +- **`actionlint.yml` grew optional shellcheck support.** Three new inputs — + `enable_shellcheck` (boolean, default false), `shellcheck_version` (default + `0.11.0`), and `shellcheck_sha256` (SHA256 of + `shellcheck-v.linux.x86_64.tar.xz`, required when enabled). When + `enable_shellcheck` is true, the workflow downloads the checksum-verified + shellcheck tarball (verifying with sha256sum) and runs it on tracked `*.sh` + files after actionlint. Off by default, so existing callers are unaffected. + - **`pr-hygiene.yml` grew pr-title and stale options.** The `pr-title` job now accepts `pr_title_types` (comma-separated conventional-commit types, converted to the newline-delimited `types:` the action expects; empty keeps the action diff --git a/catalog/capabilities.yml b/catalog/capabilities.yml index 572e007..ca378c8 100644 --- a/catalog/capabilities.yml +++ b/catalog/capabilities.yml @@ -199,8 +199,9 @@ capabilities: risks: - "Downloaded tarball is checksum-verified; bumping the version requires updating the SHA256" - "A first-step guard rejects non-Linux-X64 runners before the download instead of failing mid-install" + - "Optional shellcheck (enable_shellcheck, default off) downloads the linux_x86_64 tarball and verifies it with sha256; it runs on tracked *.sh files only and needs shellcheck_sha256 set when enabled" deprecations: null - last_verified: "2026-07-11" + last_verified: "2026-08-04" sources: - "https://github.com/rhysd/actionlint" diff --git a/catalog/runtime-coverage.yml b/catalog/runtime-coverage.yml index 937928b..69563aa 100644 --- a/catalog/runtime-coverage.yml +++ b/catalog/runtime-coverage.yml @@ -13,10 +13,10 @@ repository: NDDev-it-com/ci-workflows baseline_ref: 218f63feb6be020e71ff8ac8e18146a12fa23a38 entries: - workflow: .github/workflows/actionlint.yml - status: runtime-proven - evidence: "Called by this repo's ci.yml on every run; Linux X64 default-input lane executed live." - last_run: https://github.com/NDDev-it-com/ci-workflows/actions/runs/30701697106 - proven_digest: f946862cfe522cb62920aa104716b331b9f35210a9181ce5954879ccb48ce1df + status: static-only + validator: scripts/check_actionlint_contract.py + evidence: "Was runtime-proven at the prior digest; extended with optional shellcheck inputs/steps, so downgraded to static-only (check_actionlint_contract.py still enforces the first-step Linux X64 runner guard) until a fresh observed workflow_call run re-proves it." + last_run: null waiver: null - workflow: .github/workflows/benchmark-compare.yml status: static-only