@bookedsolid/rea 0.6.1 → 0.7.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.
- package/.husky/pre-push +59 -4
- package/THREAT_MODEL.md +14 -0
- package/dist/cli/install/pre-push.js +3 -0
- package/dist/gateway/downstream.d.ts +16 -8
- package/dist/gateway/downstream.js +57 -11
- package/dist/gateway/meta/health.d.ts +77 -0
- package/dist/gateway/meta/health.js +160 -0
- package/dist/gateway/server.js +49 -8
- package/dist/policy/loader.d.ts +27 -0
- package/dist/policy/loader.js +15 -0
- package/dist/policy/types.d.ts +28 -0
- package/hooks/_lib/push-review-core.sh +1013 -0
- package/hooks/commit-review-gate.sh +51 -28
- package/hooks/push-review-gate-git.sh +92 -0
- package/hooks/push-review-gate.sh +47 -940
- package/package.json +1 -1
- package/scripts/dist-regression-gate.sh +220 -0
- package/scripts/tarball-smoke.sh +115 -0
|
@@ -16,37 +16,60 @@ set -uo pipefail
|
|
|
16
16
|
INPUT=$(cat)
|
|
17
17
|
|
|
18
18
|
# ── 1a. Cross-repo guard (must come FIRST — before any rea-scoped check) ──────
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
|
|
19
|
+
# BUG-012 (0.6.2) — mirror of push-review-gate.sh §1a. Script-location
|
|
20
|
+
# anchor (not CLAUDE_PROJECT_DIR) owns the trust decision. See the
|
|
21
|
+
# push-gate comment and THREAT_MODEL.md § CLAUDE_PROJECT_DIR for the full
|
|
22
|
+
# rationale. In short: CLAUDE_PROJECT_DIR is caller-controlled, cannot be
|
|
23
|
+
# trusted for authorization, and the hook's own filesystem location is the
|
|
24
|
+
# only forge-resistant anchor available to a bash script.
|
|
25
|
+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" && pwd -P 2>/dev/null)"
|
|
26
|
+
# Walk up from SCRIPT_DIR looking for `.rea/policy.yaml`. Matches every
|
|
27
|
+
# reasonable install topology (see push-review-gate.sh §1a for the full
|
|
28
|
+
# rationale). A hard-coded `../..` breaks the source-path invocation
|
|
29
|
+
# (`bash hooks/commit-review-gate.sh`) and silently reads .rea state from
|
|
30
|
+
# the WRONG directory.
|
|
31
|
+
REA_ROOT=""
|
|
32
|
+
_anchor_candidate="$SCRIPT_DIR"
|
|
33
|
+
for _ in 1 2 3 4; do
|
|
34
|
+
_anchor_candidate="$(cd -- "$_anchor_candidate/.." && pwd -P 2>/dev/null || true)"
|
|
35
|
+
if [[ -n "$_anchor_candidate" && -f "$_anchor_candidate/.rea/policy.yaml" ]]; then
|
|
36
|
+
REA_ROOT="$_anchor_candidate"
|
|
37
|
+
break
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
if [[ -z "$REA_ROOT" ]]; then
|
|
41
|
+
printf 'rea-hook: no .rea/policy.yaml found within 4 parents of %s\n' \
|
|
42
|
+
"$SCRIPT_DIR" >&2
|
|
43
|
+
printf 'rea-hook: is this an installed rea hook, or is `.rea/policy.yaml`\n' >&2
|
|
44
|
+
printf 'rea-hook: nested more than 4 directories above the hook script?\n' >&2
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
unset _anchor_candidate
|
|
48
|
+
|
|
31
49
|
if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]]; then
|
|
32
|
-
|
|
33
|
-
if
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
fi
|
|
50
|
+
CPD_REAL=$(cd -- "${CLAUDE_PROJECT_DIR}" 2>/dev/null && pwd -P 2>/dev/null || true)
|
|
51
|
+
if [[ -n "$CPD_REAL" && "$CPD_REAL" != "$REA_ROOT" ]]; then
|
|
52
|
+
printf 'rea-hook: ignoring CLAUDE_PROJECT_DIR=%s — anchoring to script location %s\n' \
|
|
53
|
+
"$CLAUDE_PROJECT_DIR" "$REA_ROOT" >&2
|
|
54
|
+
fi
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
CWD_REAL=$(pwd -P 2>/dev/null || pwd)
|
|
58
|
+
CWD_COMMON=$(git -C "$CWD_REAL" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)
|
|
59
|
+
REA_COMMON=$(git -C "$REA_ROOT" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)
|
|
60
|
+
if [[ -n "$CWD_COMMON" && -n "$REA_COMMON" ]]; then
|
|
61
|
+
CWD_COMMON_REAL=$(cd "$CWD_COMMON" 2>/dev/null && pwd -P 2>/dev/null || echo "$CWD_COMMON")
|
|
62
|
+
REA_COMMON_REAL=$(cd "$REA_COMMON" 2>/dev/null && pwd -P 2>/dev/null || echo "$REA_COMMON")
|
|
63
|
+
if [[ "$CWD_COMMON_REAL" != "$REA_COMMON_REAL" ]]; then
|
|
64
|
+
exit 0
|
|
48
65
|
fi
|
|
66
|
+
elif [[ -z "$CWD_COMMON" && -z "$REA_COMMON" ]]; then
|
|
67
|
+
case "$CWD_REAL/" in
|
|
68
|
+
"$REA_ROOT"/*|"$REA_ROOT"/) : ;; # inside rea — run the gate
|
|
69
|
+
*) exit 0 ;; # outside rea — not our gate
|
|
70
|
+
esac
|
|
49
71
|
fi
|
|
72
|
+
# Mixed state or probe error → fail CLOSED: run the gate.
|
|
50
73
|
|
|
51
74
|
# ── 2. Dependency check ──────────────────────────────────────────────────────
|
|
52
75
|
if ! command -v jq >/dev/null 2>&1; then
|
|
@@ -0,0 +1,92 @@
|
|
|
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> — bypass the Codex adversarial-review
|
|
49
|
+
# requirement for this push. Audit record
|
|
50
|
+
# `tool_name: "codex.review.skipped"`.
|
|
51
|
+
# Currently a whole-gate bypass (see
|
|
52
|
+
# task #85); the distinct audit tool_name
|
|
53
|
+
# keeps it from satisfying the Codex-
|
|
54
|
+
# review jq predicate.
|
|
55
|
+
# REA_SKIP_PUSH_REVIEW=<reason> — bypass the WHOLE gate for this push.
|
|
56
|
+
# Audit record
|
|
57
|
+
# `tool_name: "push.review.skipped"`.
|
|
58
|
+
#
|
|
59
|
+
# Both hatches are value-carrying: the env value IS the reason recorded in
|
|
60
|
+
# the audit receipt. An empty value (`REA_SKIP_...=`) is treated as unset.
|
|
61
|
+
# The hatches sit behind `.rea/HALT` — HALT always wins.
|
|
62
|
+
#
|
|
63
|
+
# Fail-closed contract:
|
|
64
|
+
# - `dist/audit/append.js` missing → exit 2 (build rea first)
|
|
65
|
+
# - Node invocation failure → exit 2
|
|
66
|
+
# - Unable to resolve actor from git config → exit 2
|
|
67
|
+
|
|
68
|
+
set -uo pipefail
|
|
69
|
+
|
|
70
|
+
# Read ALL stdin immediately. For husky-driven pushes this is git's refspec
|
|
71
|
+
# list; for any other caller it is whatever they hand us. The core's sniff
|
|
72
|
+
# decides.
|
|
73
|
+
INPUT=$(cat)
|
|
74
|
+
|
|
75
|
+
# Resolve the core library from this adapter's own on-disk location. Using
|
|
76
|
+
# BASH_SOURCE (not argv $0) so invocations from `.husky/pre-push`, from a
|
|
77
|
+
# consumer's `.claude/hooks/`, or from a direct `bash hooks/push-review-gate-git.sh`
|
|
78
|
+
# all find `_lib/` next to the adapter. Consistent with the BUG-012
|
|
79
|
+
# script-anchor rationale in core.
|
|
80
|
+
_adapter_script="${BASH_SOURCE[0]:-$0}"
|
|
81
|
+
_adapter_dir="$(cd -- "$(dirname -- "$_adapter_script")" && pwd -P 2>/dev/null)"
|
|
82
|
+
_core_lib="${_adapter_dir}/_lib/push-review-core.sh"
|
|
83
|
+
if [[ ! -f "$_core_lib" ]]; then
|
|
84
|
+
printf 'rea-hook: push-review-core.sh not found next to %s\n' \
|
|
85
|
+
"$_adapter_script" >&2
|
|
86
|
+
printf 'rea-hook: expected at %s\n' "$_core_lib" >&2
|
|
87
|
+
exit 2
|
|
88
|
+
fi
|
|
89
|
+
# shellcheck source=_lib/push-review-core.sh
|
|
90
|
+
source "$_core_lib"
|
|
91
|
+
|
|
92
|
+
pr_core_run "$_adapter_script" "$INPUT" "$@"
|