@bookedsolid/rea 0.37.0 → 0.38.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.
Files changed (35) hide show
  1. package/hooks/_lib/shim-runtime.sh +405 -0
  2. package/hooks/architecture-review-gate.sh +11 -103
  3. package/hooks/attribution-advisory.sh +38 -209
  4. package/hooks/blocked-paths-bash-gate.sh +32 -146
  5. package/hooks/blocked-paths-enforcer.sh +32 -137
  6. package/hooks/changeset-security-gate.sh +26 -119
  7. package/hooks/dangerous-bash-interceptor.sh +46 -170
  8. package/hooks/delegation-advisory.sh +26 -144
  9. package/hooks/delegation-capture.sh +33 -139
  10. package/hooks/dependency-audit-gate.sh +29 -121
  11. package/hooks/env-file-protection.sh +30 -141
  12. package/hooks/local-review-gate.sh +117 -352
  13. package/hooks/pr-issue-link-gate.sh +16 -118
  14. package/hooks/protected-paths-bash-gate.sh +53 -152
  15. package/hooks/secret-scanner.sh +90 -213
  16. package/hooks/security-disclosure-gate.sh +32 -155
  17. package/hooks/settings-protection.sh +56 -176
  18. package/package.json +1 -1
  19. package/templates/_lib_shim-runtime.dogfood-staged.sh +405 -0
  20. package/templates/architecture-review-gate.dogfood-staged.sh +11 -103
  21. package/templates/attribution-advisory.dogfood-staged.sh +38 -209
  22. package/templates/blocked-paths-bash-gate.dogfood-staged.sh +32 -146
  23. package/templates/blocked-paths-enforcer.dogfood-staged.sh +32 -137
  24. package/templates/changeset-security-gate.dogfood-staged.sh +26 -119
  25. package/templates/dangerous-bash-interceptor.dogfood-staged.sh +46 -170
  26. package/templates/delegation-advisory.dogfood-staged.sh +44 -0
  27. package/templates/delegation-capture.dogfood-staged.sh +52 -0
  28. package/templates/dependency-audit-gate.dogfood-staged.sh +29 -121
  29. package/templates/env-file-protection.dogfood-staged.sh +30 -141
  30. package/templates/local-review-gate.dogfood-staged.sh +117 -352
  31. package/templates/pr-issue-link-gate.dogfood-staged.sh +16 -118
  32. package/templates/protected-paths-bash-gate.dogfood-staged.sh +53 -152
  33. package/templates/secret-scanner.dogfood-staged.sh +90 -213
  34. package/templates/security-disclosure-gate.dogfood-staged.sh +32 -155
  35. package/templates/settings-protection.dogfood-staged.sh +56 -176
@@ -1,157 +1,46 @@
1
1
  #!/bin/bash
2
2
  # PreToolUse hook: env-file-protection.sh
3
3
  # 0.33.0+ — Node-binary shim for `rea hook env-file-protection`.
4
+ # 0.38.0+ — migrated to `_lib/shim-runtime.sh` (shared runtime).
4
5
  #
5
- # Pre-0.33.0 the gate's full body lived here as bash (124 LOC, the
6
- # segment splitter + `source`/`cp` anchor patterns + utility-vs-.env
7
- # co-occurrence check). The migration to the parser-backed Node binary
8
- # moves all of that into `src/hooks/env-file-protection/index.ts`. This
9
- # shim is the Claude Code dispatcher's view of the hook — it forwards
10
- # stdin to the CLI and exits with whatever the CLI returns.
6
+ # Blocking-tier: refuses Bash commands that source/cp/cat .env. Full
7
+ # segment splitter + utility-vs-.env co-occurrence logic in
8
+ # `src/hooks/env-file-protection/index.ts`.
11
9
  #
12
- # Behavioral contract is preserved byte-for-byte: exit 0 on
13
- # pass-through / no-match, exit 2 on HALT / .env access detected /
14
- # malformed payload (fail-closed).
10
+ # # Relevance pre-gate
15
11
  #
16
- # # CLI-resolution trust boundary
17
- #
18
- # Mirrors the 0.32.0 final shim shape (round-8 of the codex iteration
19
- # on the three Phase 1 pilots). The resolved CLI MUST live INSIDE
20
- # realpath(CLAUDE_PROJECT_DIR) AND have an ancestor `package.json`
21
- # whose `name` is `@bookedsolid/rea`. Defends against symlink-out and
22
- # tarball-replacement attacks on the resolved CLI.
23
- #
24
- # # Fail-closed posture
25
- #
26
- # env-file-protection is a BLOCKING-tier gate — the pre-0.33.0 bash
27
- # body refused on .env access without a compiled CLI. The early-exit
28
- # branches (CLI missing, node missing, sandbox failed, version skew)
29
- # fail closed AFTER the relevance pre-gate passes. Irrelevant Bash
30
- # calls exit 0 regardless of CLI state.
12
+ # 2026-05-15 codex round-2 P2 fix: scan `tool_input.command` ONLY, not
13
+ # the raw JSON payload — otherwise `git commit -m "stop reading .env"`
14
+ # (where `.env` appears inside the commit message ARG) hits fail-closed
15
+ # on a fresh checkout.
31
16
 
32
17
  set -uo pipefail
33
18
 
34
- # 1. HALT check.
35
19
  # shellcheck source=_lib/halt-check.sh
36
20
  source "$(dirname "$0")/_lib/halt-check.sh"
37
21
  check_halt
38
22
  REA_ROOT=$(rea_root)
39
23
 
40
- proj="${CLAUDE_PROJECT_DIR:-$REA_ROOT}"
41
-
42
- # 2. Relevance pre-gate. Capture stdin + check for `.env` substring
43
- # BEFORE any CLI/sandbox/probe work so unrelated Bash calls
44
- # (`ls`, `pnpm test`, `git status`, …) exit 0 even when the CLI
45
- # is missing/stale/sandboxed-out.
46
- #
47
- # 2026-05-15 codex round-2 P2 fix: the substring scan MUST run
48
- # against `tool_input.command` ONLY, not the raw JSON payload —
49
- # otherwise a benign `git commit -m "stop reading .env"` (where
50
- # `.env` appears inside the commit message ARG, NOT as a file
51
- # target) would hit the fail-closed branch on a fresh checkout
52
- # where the CLI is unbuilt. Pre-fix the raw scan saw the substring
53
- # inside the payload's "command" string-quoted body and refused.
54
- #
55
- # Strategy: extract `tool_input.command` via `jq` (already required
56
- # by 5 other hooks; trust assumption is consistent). When `jq` is
57
- # not installed, fall back to scanning the raw payload — the cost
58
- # is the same over-trigger the bash original had, NOT a new
59
- # regression. When `jq` IS installed (the common case), the
60
- # pre-gate is field-scoped.
61
- INPUT=$(cat)
62
- RELEVANT=0
63
- PROBE=""
64
- if command -v jq >/dev/null 2>&1; then
65
- PROBE=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null || true)
66
- if printf '%s' "$PROBE" | grep -qE '\.env'; then
67
- RELEVANT=1
68
- fi
69
- else
70
- # jq-less fallback — match the pre-0.33.0 over-trigger posture.
71
- if printf '%s' "$INPUT" | grep -qE '\.env'; then
72
- RELEVANT=1
24
+ SHIM_NAME="env-file-protection"
25
+ SHIM_INTRODUCED_IN="0.33.0"
26
+ SHIM_FAIL_OPEN=0
27
+ SHIM_REFUSAL_NOUN=".env protection"
28
+
29
+ shim_is_relevant() {
30
+ local probe
31
+ if command -v jq >/dev/null 2>&1; then
32
+ probe=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null || true)
33
+ if printf '%s' "$probe" | grep -qE '\.env'; then
34
+ return 0
35
+ fi
36
+ else
37
+ if printf '%s' "$INPUT" | grep -qE '\.env'; then
38
+ return 0
39
+ fi
73
40
  fi
74
- fi
75
- if [ "$RELEVANT" -eq 0 ]; then
76
- exit 0
77
- fi
78
-
79
- # 3. Resolve the rea CLI through the fixed 2-tier sandboxed order.
80
- REA_ARGV=()
81
- RESOLVED_CLI_PATH=""
82
- if [ -f "$proj/node_modules/@bookedsolid/rea/dist/cli/index.js" ]; then
83
- REA_ARGV=(node "$proj/node_modules/@bookedsolid/rea/dist/cli/index.js")
84
- RESOLVED_CLI_PATH="$proj/node_modules/@bookedsolid/rea/dist/cli/index.js"
85
- elif [ -f "$proj/dist/cli/index.js" ]; then
86
- REA_ARGV=(node "$proj/dist/cli/index.js")
87
- RESOLVED_CLI_PATH="$proj/dist/cli/index.js"
88
- fi
89
-
90
- if [ "${#REA_ARGV[@]}" -eq 0 ]; then
91
- # Blocking-tier: fail closed. The pre-0.33.0 bash body enforced
92
- # .env protection without a CLI. Refuse and tell the operator how
93
- # to restore protection.
94
- printf 'rea: env-file-protection cannot run — the rea CLI is not built.\n' >&2
95
- printf 'Run `pnpm install && pnpm build` (or `npm install` for a consumer install) to restore protection.\n' >&2
96
- printf 'This shim fails closed because the pre-0.33.0 bash body enforced .env protection without a CLI.\n' >&2
97
- exit 2
98
- fi
99
-
100
- # 4. Realpath sandbox check.
101
- if ! command -v node >/dev/null 2>&1; then
102
- printf 'rea: env-file-protection cannot run — `node` is not on PATH.\n' >&2
103
- printf 'Install Node 22+ (engines.node) to restore .env protection.\n' >&2
104
- exit 2
105
- fi
106
-
107
- sandbox_check=$(node -e '
108
- const fs = require("fs");
109
- const path = require("path");
110
- const cli = process.argv[1];
111
- const projDir = process.argv[2];
112
- let real, realProj;
113
- try { real = fs.realpathSync(cli); } catch (e) {
114
- process.stdout.write("bad:realpath"); process.exit(1);
115
- }
116
- try { realProj = fs.realpathSync(projDir); } catch (e) {
117
- process.stdout.write("bad:realpath-proj"); process.exit(1);
118
- }
119
- const sep = path.sep;
120
- const projWithSep = realProj.endsWith(sep) ? realProj : realProj + sep;
121
- if (!(real === realProj || real.startsWith(projWithSep))) {
122
- process.stdout.write("bad:cli-escapes-project"); process.exit(1);
123
- }
124
- let cur = path.dirname(path.dirname(path.dirname(real)));
125
- let found = false;
126
- for (let i = 0; i < 20 && cur && cur !== path.dirname(cur); i += 1) {
127
- const pj = path.join(cur, "package.json");
128
- if (fs.existsSync(pj)) {
129
- try {
130
- const data = JSON.parse(fs.readFileSync(pj, "utf8"));
131
- if (data && data.name === "@bookedsolid/rea") { found = true; break; }
132
- } catch (e) { /* keep walking */ }
133
- }
134
- cur = path.dirname(cur);
135
- }
136
- if (!found) { process.stdout.write("bad:no-rea-pkg-json"); process.exit(1); }
137
- process.stdout.write("ok");
138
- ' -- "$RESOLVED_CLI_PATH" "$proj" 2>/dev/null)
139
-
140
- if [ "$sandbox_check" != "ok" ]; then
141
- printf 'rea: env-file-protection FAILED sandbox check (%s) — refusing.\n' "$sandbox_check" >&2
142
- exit 2
143
- fi
144
-
145
- # 5. Version-probe.
146
- probe_out=$("${REA_ARGV[@]}" hook env-file-protection --help 2>&1)
147
- probe_status=$?
148
- if [ "$probe_status" -ne 0 ] || ! printf '%s' "$probe_out" | grep -q -e 'env-file-protection'; then
149
- printf 'rea: this shim requires the `rea hook env-file-protection` subcommand (introduced in 0.33.0).\n' >&2
150
- printf 'The resolved CLI at %s does not implement it.\n' "$RESOLVED_CLI_PATH" >&2
151
- printf 'Run `pnpm install` (or `npm install`) to sync the CLI; refusing in the meantime to preserve enforcement.\n' >&2
152
- exit 2
153
- fi
41
+ return 1
42
+ }
154
43
 
155
- # 6. Forward stdin (already captured up-front for the relevance gate).
156
- printf '%s' "$INPUT" | "${REA_ARGV[@]}" hook env-file-protection
157
- exit $?
44
+ # shellcheck source=_lib/shim-runtime.sh
45
+ source "$(dirname "$0")/_lib/shim-runtime.sh"
46
+ shim_run