@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.
- package/hooks/_lib/shim-runtime.sh +405 -0
- package/hooks/architecture-review-gate.sh +11 -103
- package/hooks/attribution-advisory.sh +38 -209
- package/hooks/blocked-paths-bash-gate.sh +32 -146
- package/hooks/blocked-paths-enforcer.sh +32 -137
- package/hooks/changeset-security-gate.sh +26 -119
- package/hooks/dangerous-bash-interceptor.sh +46 -170
- package/hooks/delegation-advisory.sh +26 -144
- package/hooks/delegation-capture.sh +33 -139
- package/hooks/dependency-audit-gate.sh +29 -121
- package/hooks/env-file-protection.sh +30 -141
- package/hooks/local-review-gate.sh +117 -352
- package/hooks/pr-issue-link-gate.sh +16 -118
- package/hooks/protected-paths-bash-gate.sh +53 -152
- package/hooks/secret-scanner.sh +90 -213
- package/hooks/security-disclosure-gate.sh +32 -155
- package/hooks/settings-protection.sh +56 -176
- package/package.json +1 -1
- package/templates/_lib_shim-runtime.dogfood-staged.sh +405 -0
- package/templates/architecture-review-gate.dogfood-staged.sh +11 -103
- package/templates/attribution-advisory.dogfood-staged.sh +38 -209
- package/templates/blocked-paths-bash-gate.dogfood-staged.sh +32 -146
- package/templates/blocked-paths-enforcer.dogfood-staged.sh +32 -137
- package/templates/changeset-security-gate.dogfood-staged.sh +26 -119
- package/templates/dangerous-bash-interceptor.dogfood-staged.sh +46 -170
- package/templates/delegation-advisory.dogfood-staged.sh +44 -0
- package/templates/delegation-capture.dogfood-staged.sh +52 -0
- package/templates/dependency-audit-gate.dogfood-staged.sh +29 -121
- package/templates/env-file-protection.dogfood-staged.sh +30 -141
- package/templates/local-review-gate.dogfood-staged.sh +117 -352
- package/templates/pr-issue-link-gate.dogfood-staged.sh +16 -118
- package/templates/protected-paths-bash-gate.dogfood-staged.sh +53 -152
- package/templates/secret-scanner.dogfood-staged.sh +90 -213
- package/templates/security-disclosure-gate.dogfood-staged.sh +32 -155
- 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
|
-
#
|
|
6
|
-
# segment splitter +
|
|
7
|
-
#
|
|
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
|
-
#
|
|
13
|
-
# pass-through / no-match, exit 2 on HALT / .env access detected /
|
|
14
|
-
# malformed payload (fail-closed).
|
|
10
|
+
# # Relevance pre-gate
|
|
15
11
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# on
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
-
#
|
|
156
|
-
|
|
157
|
-
|
|
44
|
+
# shellcheck source=_lib/shim-runtime.sh
|
|
45
|
+
source "$(dirname "$0")/_lib/shim-runtime.sh"
|
|
46
|
+
shim_run
|