From 4795930c7d367074fd3161d9c59ca9880962b221 Mon Sep 17 00:00:00 2001 From: Mike Odnis Date: Tue, 14 Apr 2026 05:51:42 -0400 Subject: [PATCH] =?UTF-8?q?ci:=20add=20hooks-sync=20workflow=20=E2=80=94?= =?UTF-8?q?=20shellcheck,=20bash-parse,=20drift=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New workflow runs on any change to scripts/git-hooks/** or scripts/install-hooks.sh: - shellcheck -S warning + bash -n every hook + the installer - Fetch canonical templates from resq-software/crates@master and fail the job if scripts/git-hooks/ differs from crates/resq-cli/templates/git-hooks/ This locks out silent drift between the two sources of truth. A symmetric workflow will land in resq-software/crates in a follow-up PR. Phase 1 of the hooks-hardening roadmap. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/hooks-sync.yml | 88 ++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .github/workflows/hooks-sync.yml diff --git a/.github/workflows/hooks-sync.yml b/.github/workflows/hooks-sync.yml new file mode 100644 index 0000000..072b5a4 --- /dev/null +++ b/.github/workflows/hooks-sync.yml @@ -0,0 +1,88 @@ +# Copyright 2026 ResQ Software +# SPDX-License-Identifier: Apache-2.0 +# +# Validate canonical git hooks shipped from this repo: +# - shellcheck + bash-parse every hook and the installer +# - diff scripts/git-hooks/ against the embedded templates in +# resq-software/crates (crates/resq-cli/templates/git-hooks/) at master +# +# The templates must be byte-identical — they are the single source of +# truth that installs into every ResQ repo. + +name: hooks-sync + +on: + push: + branches: [main] + paths: + - 'scripts/git-hooks/**' + - 'scripts/install-hooks.sh' + - '.github/workflows/hooks-sync.yml' + pull_request: + paths: + - 'scripts/git-hooks/**' + - 'scripts/install-hooks.sh' + - '.github/workflows/hooks-sync.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + lint: + name: shellcheck + parse + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install shellcheck + run: sudo apt-get update -y && sudo apt-get install -y shellcheck + + - name: Run shellcheck + run: | + shellcheck -S warning \ + scripts/install-hooks.sh \ + scripts/git-hooks/pre-commit \ + scripts/git-hooks/commit-msg \ + scripts/git-hooks/prepare-commit-msg \ + scripts/git-hooks/pre-push \ + scripts/git-hooks/post-checkout \ + scripts/git-hooks/post-merge + + - name: bash -n parse check + run: | + set -e + for f in scripts/install-hooks.sh scripts/git-hooks/pre-commit scripts/git-hooks/commit-msg scripts/git-hooks/prepare-commit-msg scripts/git-hooks/pre-push scripts/git-hooks/post-checkout scripts/git-hooks/post-merge; do + bash -n "$f" + done + + drift-check: + name: drift vs crates templates + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Fetch canonical templates from resq-software/crates@main + run: | + mkdir -p /tmp/crates-templates + for h in pre-commit commit-msg prepare-commit-msg pre-push post-checkout post-merge; do + curl -fsSL \ + "https://raw.githubusercontent.com/resq-software/crates/master/crates/resq-cli/templates/git-hooks/$h" \ + -o "/tmp/crates-templates/$h" + done + + - name: Diff against scripts/git-hooks/ + run: | + rc=0 + for h in pre-commit commit-msg prepare-commit-msg pre-push post-checkout post-merge; do + if ! diff -u "scripts/git-hooks/$h" "/tmp/crates-templates/$h"; then + echo "::error file=scripts/git-hooks/$h::drifts from resq-software/crates@master:crates/resq-cli/templates/git-hooks/$h" + rc=1 + fi + done + if [ "$rc" -ne 0 ]; then + echo "::error::Canonical hook templates in dev/ and crates/ must be byte-identical." + echo "::error::Sync them in both repos or retire one copy (Phase 4 of the hardening plan)." + exit 1 + fi + echo "✅ All hook templates match crates/resq-cli/templates/git-hooks/"