@bookedsolid/rea 0.36.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/policy-reader.sh +948 -0
- package/hooks/_lib/shim-runtime.sh +405 -0
- package/hooks/architecture-review-gate.sh +11 -103
- package/hooks/attribution-advisory.sh +43 -155
- package/hooks/blocked-paths-bash-gate.sh +35 -149
- package/hooks/blocked-paths-enforcer.sh +35 -140
- 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 +191 -396
- package/hooks/pr-issue-link-gate.sh +16 -118
- package/hooks/protected-paths-bash-gate.sh +57 -160
- package/hooks/secret-scanner.sh +90 -213
- package/hooks/security-disclosure-gate.sh +32 -155
- package/hooks/settings-protection.sh +56 -179
- package/package.json +1 -1
- package/templates/_lib_policy-reader.dogfood-staged.sh +948 -0
- 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 +43 -155
- package/templates/blocked-paths-bash-gate.dogfood-staged.sh +35 -149
- package/templates/blocked-paths-enforcer.dogfood-staged.sh +35 -140
- 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 +191 -396
- package/templates/pr-issue-link-gate.dogfood-staged.sh +16 -118
- package/templates/protected-paths-bash-gate.dogfood-staged.sh +57 -160
- 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 -179
|
@@ -1,134 +1,32 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# PreToolUse hook: pr-issue-link-gate.sh
|
|
3
3
|
# 0.32.0+ — Node-binary shim for `rea hook pr-issue-link-gate`.
|
|
4
|
+
# 0.38.0+ — migrated to `_lib/shim-runtime.sh` (shared runtime).
|
|
4
5
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# CLI and exits with whatever the CLI returns.
|
|
10
|
-
#
|
|
11
|
-
# Behavioral contract is preserved byte-for-byte: ALWAYS exit 0 except
|
|
12
|
-
# under HALT (exit 2) or a malformed payload (exit 2, fail-closed).
|
|
6
|
+
# Advisory-tier: nudges operators to link an issue when running
|
|
7
|
+
# `gh pr create`. ALWAYS exit 0 except under HALT. The pre-port bash
|
|
8
|
+
# body lived here; the matching + advisory logic is now in
|
|
9
|
+
# `src/hooks/pr-issue-link-gate/index.ts`.
|
|
13
10
|
#
|
|
14
11
|
# # CLI-resolution trust boundary
|
|
15
12
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# `@bookedsolid/rea`. Pre-fix the shim executed
|
|
21
|
-
# `node_modules/@bookedsolid/rea/dist/cli/index.js` directly without
|
|
22
|
-
# realpathing the target, which would let an attacker who controlled
|
|
23
|
-
# `node_modules/@bookedsolid/rea` (symlink-out, postinstall script,
|
|
24
|
-
# tarball-replacement) ship forged review code that intercepts every
|
|
25
|
-
# Bash dispatch.
|
|
26
|
-
#
|
|
27
|
-
# Sandboxed resolution order (PATH is INTENTIONALLY OMITTED):
|
|
28
|
-
# 1. node_modules/@bookedsolid/rea/dist/cli/index.js (consumer-side)
|
|
29
|
-
# 2. dist/cli/index.js under CLAUDE_PROJECT_DIR (dogfood)
|
|
30
|
-
#
|
|
31
|
-
# When NO rea CLI is reachable through the sandboxed order, this hook
|
|
32
|
-
# falls through to allow (exit 0) — the advisory is a nudge, not a
|
|
33
|
-
# security claim. The bash-tier path gates fail-closed because they
|
|
34
|
-
# protect write surfaces; this gate only emits prose.
|
|
35
|
-
#
|
|
36
|
-
# # Version skew
|
|
37
|
-
#
|
|
38
|
-
# Codex round 1 P1 (2026-05-15): a fresh `rea init` against a stale
|
|
39
|
-
# `node_modules/@bookedsolid/rea` would deliver this 0.32.0 shim while
|
|
40
|
-
# the installed CLI lacks the `hook pr-issue-link-gate` subcommand —
|
|
41
|
-
# every Bash dispatch would then fail with `unknown command` (exit 1).
|
|
42
|
-
# Probe the subcommand's `--help` output before propagating the exit
|
|
43
|
-
# code; on probe failure, advise the operator to `pnpm install` and
|
|
44
|
-
# fall through silently so the workspace stays usable.
|
|
13
|
+
# The shared runtime enforces the 2-tier sandboxed CLI resolution
|
|
14
|
+
# (node_modules → dist/, PATH intentionally omitted) + the realpath
|
|
15
|
+
# sandbox check. See `hooks/_lib/shim-runtime.sh` for the canonical
|
|
16
|
+
# trust boundary documentation.
|
|
45
17
|
|
|
46
18
|
set -uo pipefail
|
|
47
19
|
|
|
48
|
-
# 1. HALT check. Even though the CLI re-checks for defense-in-depth,
|
|
49
|
-
# short-circuit here so we never spawn `node` while frozen.
|
|
50
20
|
# shellcheck source=_lib/halt-check.sh
|
|
51
21
|
source "$(dirname "$0")/_lib/halt-check.sh"
|
|
52
22
|
check_halt
|
|
53
23
|
REA_ROOT=$(rea_root)
|
|
54
24
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
RESOLVED_CLI_PATH=""
|
|
60
|
-
if [ -f "$proj/node_modules/@bookedsolid/rea/dist/cli/index.js" ]; then
|
|
61
|
-
REA_ARGV=(node "$proj/node_modules/@bookedsolid/rea/dist/cli/index.js")
|
|
62
|
-
RESOLVED_CLI_PATH="$proj/node_modules/@bookedsolid/rea/dist/cli/index.js"
|
|
63
|
-
elif [ -f "$proj/dist/cli/index.js" ]; then
|
|
64
|
-
REA_ARGV=(node "$proj/dist/cli/index.js")
|
|
65
|
-
RESOLVED_CLI_PATH="$proj/dist/cli/index.js"
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
if [ "${#REA_ARGV[@]}" -eq 0 ]; then
|
|
69
|
-
exit 0
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
# 3. Realpath sandbox check — mirrors delegation-advisory.sh §3.
|
|
73
|
-
if ! command -v node >/dev/null 2>&1; then
|
|
74
|
-
exit 0
|
|
75
|
-
fi
|
|
76
|
-
|
|
77
|
-
sandbox_check=$(node -e '
|
|
78
|
-
const fs = require("fs");
|
|
79
|
-
const path = require("path");
|
|
80
|
-
const cli = process.argv[1];
|
|
81
|
-
const projDir = process.argv[2];
|
|
82
|
-
let real, realProj;
|
|
83
|
-
try { real = fs.realpathSync(cli); } catch (e) {
|
|
84
|
-
process.stdout.write("bad:realpath"); process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
try { realProj = fs.realpathSync(projDir); } catch (e) {
|
|
87
|
-
process.stdout.write("bad:realpath-proj"); process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
const sep = path.sep;
|
|
90
|
-
const projWithSep = realProj.endsWith(sep) ? realProj : realProj + sep;
|
|
91
|
-
if (!(real === realProj || real.startsWith(projWithSep))) {
|
|
92
|
-
process.stdout.write("bad:cli-escapes-project"); process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
let cur = path.dirname(path.dirname(path.dirname(real)));
|
|
95
|
-
let found = false;
|
|
96
|
-
for (let i = 0; i < 20 && cur && cur !== path.dirname(cur); i += 1) {
|
|
97
|
-
const pj = path.join(cur, "package.json");
|
|
98
|
-
if (fs.existsSync(pj)) {
|
|
99
|
-
try {
|
|
100
|
-
const data = JSON.parse(fs.readFileSync(pj, "utf8"));
|
|
101
|
-
if (data && data.name === "@bookedsolid/rea") { found = true; break; }
|
|
102
|
-
} catch (e) { /* keep walking */ }
|
|
103
|
-
}
|
|
104
|
-
cur = path.dirname(cur);
|
|
105
|
-
}
|
|
106
|
-
if (!found) { process.stdout.write("bad:no-rea-pkg-json"); process.exit(1); }
|
|
107
|
-
process.stdout.write("ok");
|
|
108
|
-
' -- "$RESOLVED_CLI_PATH" "$proj" 2>/dev/null)
|
|
109
|
-
|
|
110
|
-
if [ "$sandbox_check" != "ok" ]; then
|
|
111
|
-
printf 'rea: pr-issue-link-gate skipped (sandbox check: %s)\n' "$sandbox_check" >&2
|
|
112
|
-
exit 0
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
# 4. Version-probe: confirm the resolved CLI implements the
|
|
116
|
-
# `hook pr-issue-link-gate` subcommand. A stale node_modules from
|
|
117
|
-
# a fresh `rea init` against an older installed version would
|
|
118
|
-
# otherwise turn every Bash dispatch into a hard failure.
|
|
119
|
-
probe_out=$("${REA_ARGV[@]}" hook pr-issue-link-gate --help 2>&1)
|
|
120
|
-
probe_status=$?
|
|
121
|
-
if [ "$probe_status" -ne 0 ] || ! printf '%s' "$probe_out" | grep -q -e 'pr-issue-link-gate'; then
|
|
122
|
-
printf 'rea: this shim requires the `rea hook pr-issue-link-gate` subcommand (introduced in 0.32.0).\n' >&2
|
|
123
|
-
printf 'The resolved CLI at %s does not implement it.\n' "$RESOLVED_CLI_PATH" >&2
|
|
124
|
-
printf 'Run `pnpm install` (or `npm install`) to sync the CLI to the version this shim expects.\n' >&2
|
|
125
|
-
exit 0
|
|
126
|
-
fi
|
|
25
|
+
SHIM_NAME="pr-issue-link-gate"
|
|
26
|
+
SHIM_INTRODUCED_IN="0.32.0"
|
|
27
|
+
SHIM_FAIL_OPEN=1
|
|
28
|
+
SHIM_REFUSAL_NOUN="the pr-issue-link advisory"
|
|
127
29
|
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
# or malformed payload).
|
|
132
|
-
INPUT=$(cat)
|
|
133
|
-
printf '%s' "$INPUT" | "${REA_ARGV[@]}" hook pr-issue-link-gate
|
|
134
|
-
exit $?
|
|
30
|
+
# shellcheck source=_lib/shim-runtime.sh
|
|
31
|
+
source "$(dirname "$0")/_lib/shim-runtime.sh"
|
|
32
|
+
shim_run
|
|
@@ -1,186 +1,83 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# PreToolUse hook: protected-paths-bash-gate.sh
|
|
3
3
|
# 0.35.0+ — Node-binary shim for `rea hook protected-paths-bash-gate`.
|
|
4
|
+
# 0.38.0+ — migrated to `_lib/shim-runtime.sh` (shared runtime).
|
|
4
5
|
#
|
|
5
|
-
#
|
|
6
|
-
# protected` (the parser-backed AST walker that replaces the 536-line
|
|
7
|
-
# pre-0.23.0 regex pipeline). The full bash body is preserved at
|
|
6
|
+
# Blocking-tier Bash gate. Full bash body preserved at
|
|
8
7
|
# `__tests__/hooks/parity/baselines/protected-paths-bash-gate.sh.pre-0.35.0`.
|
|
8
|
+
# Migration lives in `src/hooks/protected-paths-bash-gate/index.ts`.
|
|
9
9
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
10
|
+
# SHIM_ENFORCE_CLI_SHAPE=1: codex round-1 P1 from 0.35.0 — enforce that
|
|
11
|
+
# the resolved CLI's realpath ends in dist/cli/index.js so an attacker
|
|
12
|
+
# who repoints node_modules/@bookedsolid/rea at an arbitrary in-project
|
|
13
|
+
# JS file cannot execute it as the trusted gate CLI.
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
# exit 2 on HALT / verdict block / malformed payload / sandbox fail.
|
|
15
|
+
# # Relevance pre-gate (CLI-missing only)
|
|
17
16
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# protected-paths-bash-gate is a Tier-1 security gate. The pre-0.35.0
|
|
25
|
-
# bash body refused on uncertainty. Early-exit branches fail closed
|
|
26
|
-
# AFTER the relevance pre-gate passes. Irrelevant Bash calls exit 0
|
|
27
|
-
# regardless of CLI state.
|
|
28
|
-
#
|
|
29
|
-
# # Relevance pre-gate
|
|
30
|
-
#
|
|
31
|
-
# Substring scan over the extracted command for any of the protected-
|
|
32
|
-
# path markers: .claude/, .husky/, .rea/policy.yaml, .rea/HALT, the
|
|
33
|
-
# verdict cache paths. When the CLI is missing AND none of these
|
|
34
|
-
# substrings appear, exit 0 (the pre-0.35.0 bash body would have
|
|
35
|
-
# allowed). When the CLI is missing AND a marker DOES match, preserve
|
|
36
|
-
# fail-closed.
|
|
17
|
+
# Substring scan over the extracted command for protected-path markers
|
|
18
|
+
# AND any policy.protected_writes entry. When the CLI is reachable, the
|
|
19
|
+
# Node body does the precise evaluation; the shim's relevance scan is
|
|
20
|
+
# only consulted on fresh/unbuilt installs to preserve the pre-port
|
|
21
|
+
# bash body's allow-on-no-match posture.
|
|
37
22
|
|
|
38
23
|
set -uo pipefail
|
|
39
24
|
|
|
40
|
-
# 1. HALT check.
|
|
41
25
|
# shellcheck source=_lib/halt-check.sh
|
|
42
26
|
source "$(dirname "$0")/_lib/halt-check.sh"
|
|
43
27
|
check_halt
|
|
44
28
|
REA_ROOT=$(rea_root)
|
|
45
29
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
30
|
+
SHIM_NAME="protected-paths-bash-gate"
|
|
31
|
+
SHIM_INTRODUCED_IN="0.35.0"
|
|
32
|
+
SHIM_FAIL_OPEN=0
|
|
33
|
+
SHIM_ENFORCE_CLI_SHAPE=1
|
|
34
|
+
SHIM_REFUSAL_NOUN="protected-path refusal"
|
|
50
35
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
RESOLVED_CLI_PATH=""
|
|
54
|
-
if [ -f "$proj/node_modules/@bookedsolid/rea/dist/cli/index.js" ]; then
|
|
55
|
-
REA_ARGV=(node "$proj/node_modules/@bookedsolid/rea/dist/cli/index.js")
|
|
56
|
-
RESOLVED_CLI_PATH="$proj/node_modules/@bookedsolid/rea/dist/cli/index.js"
|
|
57
|
-
elif [ -f "$proj/dist/cli/index.js" ]; then
|
|
58
|
-
REA_ARGV=(node "$proj/dist/cli/index.js")
|
|
59
|
-
RESOLVED_CLI_PATH="$proj/dist/cli/index.js"
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
# 3b. Relevance pre-gate. Only used when the CLI is missing.
|
|
63
|
-
if [ "${#REA_ARGV[@]}" -eq 0 ]; then
|
|
64
|
-
CLI_MISSING_CMD=""
|
|
36
|
+
shim_cli_missing_relevant() {
|
|
37
|
+
local cli_missing_cmd=""
|
|
65
38
|
if command -v jq >/dev/null 2>&1; then
|
|
66
|
-
|
|
39
|
+
cli_missing_cmd=$(printf '%s' "$INPUT" | jq -r '
|
|
67
40
|
(.tool_input.command // "") | tostring
|
|
68
41
|
' 2>/dev/null || true)
|
|
69
42
|
else
|
|
70
|
-
|
|
43
|
+
cli_missing_cmd="$INPUT"
|
|
71
44
|
fi
|
|
72
|
-
if [ -z "$
|
|
73
|
-
|
|
45
|
+
if [ -z "$cli_missing_cmd" ]; then
|
|
46
|
+
return 1
|
|
74
47
|
fi
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*".
|
|
78
|
-
*".
|
|
79
|
-
*".rea/
|
|
80
|
-
*".rea/
|
|
81
|
-
*".rea
|
|
82
|
-
*".claude\\"*|*".husky\\"*|*".rea\\"*) CLI_MISSING_RELEVANT=1 ;;
|
|
48
|
+
case "$cli_missing_cmd" in
|
|
49
|
+
*".claude/"*) return 0 ;;
|
|
50
|
+
*".husky/"*) return 0 ;;
|
|
51
|
+
*".rea/policy.yaml"*) return 0 ;;
|
|
52
|
+
*".rea/HALT"*) return 0 ;;
|
|
53
|
+
*".rea/last-review"*) return 0 ;;
|
|
54
|
+
*".claude\\"*|*".husky\\"*|*".rea\\"*) return 0 ;;
|
|
83
55
|
esac
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
gsub(/^["'\'']/, "")
|
|
106
|
-
gsub(/["'\'']$/, "")
|
|
107
|
-
print
|
|
108
|
-
next
|
|
109
|
-
}
|
|
110
|
-
in_block && /^[^[:space:]-]/ { in_block=0 }
|
|
111
|
-
' "$POLICY_FILE" 2>/dev/null)
|
|
112
|
-
fi
|
|
113
|
-
fi
|
|
114
|
-
if [ "$CLI_MISSING_RELEVANT" -eq 0 ]; then
|
|
115
|
-
exit 0
|
|
56
|
+
# 0.37.0: route protected_writes reads through the unified
|
|
57
|
+
# policy-reader (Tier 1 CLI → Tier 2 python3 → Tier 3 awk
|
|
58
|
+
# block-form). Pre-0.37.0 the inline awk parser missed flow-form
|
|
59
|
+
# arrays (`protected_writes: [path/a, path/b]`) on CLI-missing
|
|
60
|
+
# installs.
|
|
61
|
+
local policy_file="${REA_ROOT}/.rea/policy.yaml"
|
|
62
|
+
if [ -f "$policy_file" ]; then
|
|
63
|
+
# shellcheck source=_lib/policy-reader.sh
|
|
64
|
+
source "$(dirname "$0")/_lib/policy-reader.sh"
|
|
65
|
+
local entry base
|
|
66
|
+
while IFS= read -r entry; do
|
|
67
|
+
[ -z "$entry" ] && continue
|
|
68
|
+
base="$entry"
|
|
69
|
+
case "$base" in
|
|
70
|
+
*/) base="${base%/}" ;;
|
|
71
|
+
esac
|
|
72
|
+
[ -z "$base" ] && continue
|
|
73
|
+
case "$cli_missing_cmd" in
|
|
74
|
+
*"$base"*) return 0 ;;
|
|
75
|
+
esac
|
|
76
|
+
done < <(policy_reader_get_list protected_writes 2>/dev/null)
|
|
116
77
|
fi
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
printf 'This shim fails closed because the pre-0.35.0 bash body enforced protected-path refusal without a CLI.\n' >&2
|
|
120
|
-
exit 2
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
# 4. Realpath sandbox check.
|
|
124
|
-
if ! command -v node >/dev/null 2>&1; then
|
|
125
|
-
printf 'rea: protected-paths-bash-gate cannot run — `node` is not on PATH.\n' >&2
|
|
126
|
-
printf 'Install Node 22+ (engines.node) to restore protected-path refusal.\n' >&2
|
|
127
|
-
exit 2
|
|
128
|
-
fi
|
|
129
|
-
|
|
130
|
-
sandbox_check=$(node -e '
|
|
131
|
-
const fs = require("fs");
|
|
132
|
-
const path = require("path");
|
|
133
|
-
const cli = process.argv[1];
|
|
134
|
-
const projDir = process.argv[2];
|
|
135
|
-
let real, realProj;
|
|
136
|
-
try { real = fs.realpathSync(cli); } catch (e) {
|
|
137
|
-
process.stdout.write("bad:realpath"); process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
try { realProj = fs.realpathSync(projDir); } catch (e) {
|
|
140
|
-
process.stdout.write("bad:realpath-proj"); process.exit(1);
|
|
141
|
-
}
|
|
142
|
-
const sep = path.sep;
|
|
143
|
-
const projWithSep = realProj.endsWith(sep) ? realProj : realProj + sep;
|
|
144
|
-
if (!(real === realProj || real.startsWith(projWithSep))) {
|
|
145
|
-
process.stdout.write("bad:cli-escapes-project"); process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
// Codex round-1 P1 fix: enforce dist/cli/index.js shape (see
|
|
148
|
-
// settings-protection.sh).
|
|
149
|
-
const expectedEnd = path.join("dist", "cli", "index.js");
|
|
150
|
-
if (!real.endsWith(path.sep + expectedEnd) && real !== "/" + expectedEnd) {
|
|
151
|
-
process.stdout.write("bad:cli-shape"); process.exit(1);
|
|
152
|
-
}
|
|
153
|
-
let cur = path.dirname(path.dirname(path.dirname(real)));
|
|
154
|
-
let found = false;
|
|
155
|
-
for (let i = 0; i < 20 && cur && cur !== path.dirname(cur); i += 1) {
|
|
156
|
-
const pj = path.join(cur, "package.json");
|
|
157
|
-
if (fs.existsSync(pj)) {
|
|
158
|
-
try {
|
|
159
|
-
const data = JSON.parse(fs.readFileSync(pj, "utf8"));
|
|
160
|
-
if (data && data.name === "@bookedsolid/rea") { found = true; break; }
|
|
161
|
-
} catch (e) { /* keep walking */ }
|
|
162
|
-
}
|
|
163
|
-
cur = path.dirname(cur);
|
|
164
|
-
}
|
|
165
|
-
if (!found) { process.stdout.write("bad:no-rea-pkg-json"); process.exit(1); }
|
|
166
|
-
process.stdout.write("ok");
|
|
167
|
-
' -- "$RESOLVED_CLI_PATH" "$proj" 2>/dev/null)
|
|
168
|
-
|
|
169
|
-
if [ "$sandbox_check" != "ok" ]; then
|
|
170
|
-
printf 'rea: protected-paths-bash-gate FAILED sandbox check (%s) — refusing.\n' "$sandbox_check" >&2
|
|
171
|
-
exit 2
|
|
172
|
-
fi
|
|
173
|
-
|
|
174
|
-
# 5. Version-probe.
|
|
175
|
-
probe_out=$("${REA_ARGV[@]}" hook protected-paths-bash-gate --help 2>&1)
|
|
176
|
-
probe_status=$?
|
|
177
|
-
if [ "$probe_status" -ne 0 ] || ! printf '%s' "$probe_out" | grep -q -e 'protected-paths-bash-gate'; then
|
|
178
|
-
printf 'rea: this shim requires the `rea hook protected-paths-bash-gate` subcommand (introduced in 0.35.0).\n' >&2
|
|
179
|
-
printf 'The resolved CLI at %s does not implement it.\n' "$RESOLVED_CLI_PATH" >&2
|
|
180
|
-
printf 'Run `pnpm install` (or `npm install`) to sync the CLI; refusing in the meantime to preserve enforcement.\n' >&2
|
|
181
|
-
exit 2
|
|
182
|
-
fi
|
|
78
|
+
return 1
|
|
79
|
+
}
|
|
183
80
|
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
81
|
+
# shellcheck source=_lib/shim-runtime.sh
|
|
82
|
+
source "$(dirname "$0")/_lib/shim-runtime.sh"
|
|
83
|
+
shim_run
|