@bookedsolid/rea 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,94 @@
1
+ #!/bin/bash
2
+ # Native git `.husky/pre-push` adapter for the REA push-review gate.
3
+ # Fires BEFORE `git push` via husky. Runs a full diff analysis against the
4
+ # target branch and requests security + code review before allowing the push.
5
+ #
6
+ # Exit codes:
7
+ # 0 = allow (no meaningful diff, cached review pass, or escape hatch
8
+ # invoked with successful audit-append)
9
+ # 2 = block (review required — protected-path gate OR general push-review
10
+ # gate — or escape hatch invoked but audit-append failed)
11
+ #
12
+ # ── Install ───────────────────────────────────────────────────────────────────
13
+ # This adapter is the recommended entry point for husky-driven pushes. Point
14
+ # `.husky/pre-push` at this file:
15
+ #
16
+ # #!/bin/sh
17
+ # REA_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
18
+ # exec "$REA_ROOT/.claude/hooks/push-review-gate-git.sh" "$@"
19
+ #
20
+ # `REA_ROOT` is resolved inside `.husky/pre-push` itself because neither git
21
+ # nor husky provides that env var — a bare `"$REA_ROOT/..."` would expand to
22
+ # `/.claude/...` and exit 126. See rea's own `.husky/pre-push` for the
23
+ # reference implementation.
24
+ #
25
+ # Git's native pre-push contract is:
26
+ # - stdin: one line per ref being pushed, `<local_ref> <local_sha> <remote_ref> <remote_sha>`
27
+ # - argv: `<remote_name> <remote_url>`
28
+ #
29
+ # ── Architecture ──────────────────────────────────────────────────────────────
30
+ # This file is a thin ADAPTER. All logic lives in
31
+ # `hooks/_lib/push-review-core.sh` (see `pr_core_run`). The core ships a
32
+ # `pr_parse_prepush_stdin` helper that recognises git's native refspec stdin
33
+ # and synthesises an equivalent `git push <remote>` CMD for the downstream
34
+ # protected-path detection.
35
+ #
36
+ # Two adapters share the core:
37
+ # - push-review-gate.sh ← Claude Code PreToolUse stdin (JSON `.tool_input.command`)
38
+ # - push-review-gate-git.sh ← this file, native `.husky/pre-push` stdin
39
+ #
40
+ # The core's BUG-008 stdin sniff makes either shape work from either adapter,
41
+ # so a consumer CAN wire `push-review-gate.sh` into `.husky/pre-push` and it
42
+ # just works. The git-native adapter exists so `.husky/pre-push` expresses
43
+ # its install intent clearly and so future git-only behaviour (e.g. remote-
44
+ # URL-scoped policy overrides) has a natural home that does not bloat the
45
+ # generic Claude Code adapter.
46
+ #
47
+ # ── Escape hatches ────────────────────────────────────────────────────────────
48
+ # REA_SKIP_CODEX_REVIEW=<reason> — Codex-only waiver. Since 0.8.0 (#85)
49
+ # this ONLY satisfies the protected-path
50
+ # Codex-audit requirement. HALT, cross-
51
+ # repo guard, ref-resolution, and the
52
+ # push-review cache still run. See the
53
+ # authoritative docstring in
54
+ # `push-review-gate.sh` for the full
55
+ # scope description. Audit record
56
+ # `tool_name: "codex.review.skipped"`.
57
+ # REA_SKIP_PUSH_REVIEW=<reason> — bypass the WHOLE gate for this push.
58
+ # Audit record
59
+ # `tool_name: "push.review.skipped"`.
60
+ #
61
+ # Both hatches are value-carrying: the env value IS the reason recorded in
62
+ # the audit receipt. An empty value (`REA_SKIP_...=`) is treated as unset.
63
+ # The hatches sit behind `.rea/HALT` — HALT always wins.
64
+ #
65
+ # Fail-closed contract:
66
+ # - `dist/audit/append.js` missing → exit 2 (build rea first)
67
+ # - Node invocation failure → exit 2
68
+ # - Unable to resolve actor from git config → exit 2
69
+
70
+ set -uo pipefail
71
+
72
+ # Read ALL stdin immediately. For husky-driven pushes this is git's refspec
73
+ # list; for any other caller it is whatever they hand us. The core's sniff
74
+ # decides.
75
+ INPUT=$(cat)
76
+
77
+ # Resolve the core library from this adapter's own on-disk location. Using
78
+ # BASH_SOURCE (not argv $0) so invocations from `.husky/pre-push`, from a
79
+ # consumer's `.claude/hooks/`, or from a direct `bash hooks/push-review-gate-git.sh`
80
+ # all find `_lib/` next to the adapter. Consistent with the BUG-012
81
+ # script-anchor rationale in core.
82
+ _adapter_script="${BASH_SOURCE[0]:-$0}"
83
+ _adapter_dir="$(cd -- "$(dirname -- "$_adapter_script")" && pwd -P 2>/dev/null)"
84
+ _core_lib="${_adapter_dir}/_lib/push-review-core.sh"
85
+ if [[ ! -f "$_core_lib" ]]; then
86
+ printf 'rea-hook: push-review-core.sh not found next to %s\n' \
87
+ "$_adapter_script" >&2
88
+ printf 'rea-hook: expected at %s\n' "$_core_lib" >&2
89
+ exit 2
90
+ fi
91
+ # shellcheck source=_lib/push-review-core.sh
92
+ source "$_core_lib"
93
+
94
+ pr_core_run "$_adapter_script" "$INPUT" "$@"