Two related fixes exposed when install.sh was first staged post-audit:
1. shellcheck invocation in setup-hooks.sh lacked -x, causing SC1091
(info) to fire for any .sh file that sources another, blocking the
pre-commit hook on legitimate scripts.
2. The shellcheck source= directive in install.sh pointed to
'deploy-manifest.sh' (bare filename). With -x, shellcheck resolves
this from CWD (repo root), where the file doesn't exist. Updated to
'scripts/deploy-manifest.sh' — the correct repo-root-relative path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv5iNACZxumtF2k6TsK18q
trap '...' RETURN inside a function is NOT local to that function in bash
— it persists in the calling scope and fires on every subsequent function
return. After install_shellcheck set the trap, it fired again when
ensure_tool returned with $tmp_dir unbound, causing nounset abort.
Fix: change install functions from {} to () (subshell bodies) and use
trap EXIT instead of RETURN. The trap is now scoped to the subshell and
cannot leak to callers.
Also fixes double _os() call in install_jq and removes redundant local
declarations (subshells don't need them).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TP4EGbBg3XMcyF28Lx78XJ
setup-hooks.sh now installs shellcheck, jq, and yq if absent rather
than warning and continuing. Follows the same install pattern as
setup-gitleaks.sh (curl + install to TOOL_INSTALL_DIR=/usr/local/bin,
OS/arch detection, pinned versions).
Pinned versions: shellcheck 0.10.0, jq 1.7.1, yq 4.44.3.
The deployed pre-commit hook retains its runtime fallbacks as a safety
net for environments where tools are removed after setup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TP4EGbBg3XMcyF28Lx78XJ
Two bugs in setup-hooks.sh:
1. awk+mv to replace a marker block created a 644 temp file, losing the
exec bit. chmod +x after every write_block call fixes this. Regression
test added to idempotency block.
2. set -euo pipefail in the deployed pre-commit hook caused grep to exit 1
when no files of a given type were staged, aborting the hook. Changed
all filter pipes to process substitution with || true so no-match is
handled gracefully.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TP4EGbBg3XMcyF28Lx78XJ
Adds setup-hooks.sh and check-manifests.sh as the deterministic
enforcement layer described in docs/research/governance_principles/CONTROLS.md.
- commit-msg: conventional commits pattern check (hard block)
- pre-commit: shellcheck on .sh, jq on .json, yq on .yaml/.yml,
SKILL.md frontmatter validation; optional tools degrade gracefully
- pre-push: full test suite + manifest cross-reference check
- check-manifests.sh: validates marketplace.json plugin sources,
plugin.json skill/hooks/mcpServers path references
- Marker-based blocks (idempotent, composable with gitleaks)
- 33 integration tests across two test scripts
Run scripts/setup-hooks.sh to install into any repo's .git/hooks/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TP4EGbBg3XMcyF28Lx78XJ