@bookedsolid/rea 0.16.0 → 0.16.1
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.
|
@@ -33,6 +33,8 @@ You may read additional files in the repo if needed for context, but do so read-
|
|
|
33
33
|
2. **Validate Codex availability** — if `/codex` is not installed, report and stop. Do not silently fall back to another reviewer.
|
|
34
34
|
3. **Prepare the Codex invocation** — construct the adversarial-review prompt with the diff, commit log, and any relevant context files.
|
|
35
35
|
4. **Invoke `/codex:adversarial-review`** — this call flows through the REA middleware chain (audit → kill-switch → tier → policy → redact → injection → execute → result-size-cap).
|
|
36
|
+
|
|
37
|
+
**Model pinning (0.16.1+):** when the codex plugin's adversarial-review supports model overrides, request `gpt-5.4` with `model_reasoning_effort: high` to match the push-gate's iron-gate defaults. Pre-0.16.1, in-session adversarial reviews ran on whatever the plugin defaulted to (likely `codex-auto-review` at medium reasoning) — meaningfully WEAKER than the push-gate's `gpt-5.4` + `high`. This caused a "in-session review passes, push-gate review fails" pattern reported by helix across 014 / 015 / 016. If the plugin call accepts model parameters, pass them. If it does not, fall back to invoking `codex exec review --base <ref> --json --ephemeral -c model="gpt-5.4" -c model_reasoning_effort="high"` directly via `Bash` — same shape the push-gate uses (see `src/hooks/push-gate/codex-runner.ts::runCodexReview`). The cost of the stronger model is small relative to the cost of shipping a release with a P1 bypass that gets caught at consumer push time.
|
|
36
38
|
5. **Parse the Codex output** — extract structured findings.
|
|
37
39
|
6. **Classify findings** by category: security, correctness, edge cases, test gaps, API design, performance.
|
|
38
40
|
7. **Assign verdict**: `pass` (no material findings), `concerns` (findings worth addressing but not blocking), `blocking` (findings that must be fixed before merge).
|
|
@@ -71,9 +71,17 @@ _rea_split_segments() {
|
|
|
71
71
|
# under any encoding we care about (any agent that intentionally
|
|
72
72
|
# included this string would already be obviously trying to confuse
|
|
73
73
|
# the splitter — and even then, the worst case is fail-closed).
|
|
74
|
+
# 0.16.1 helix-016 P1 fix: also split on single `&` (background-process
|
|
75
|
+
# operator). Pre-fix the splitter only broke on `&&|||;|`; a command like
|
|
76
|
+
# `sleep 1 & git push --force` was treated as ONE segment whose first
|
|
77
|
+
# token is `sleep`, and `any_segment_starts_with($CMD, 'git push')`
|
|
78
|
+
# missed the force-push entirely. Add `&` to the separator set, but
|
|
79
|
+
# AFTER `&&` is already swapped out so we don't break it apart.
|
|
74
80
|
printf '%s\n' "$cmd" \
|
|
75
81
|
| sed -E 's/>\|/__REA_GTPIPE_a8f2c1__/g' \
|
|
76
|
-
| sed -E 's/
|
|
82
|
+
| sed -E 's/&&/__REA_LOGAND_a8f2c1__/g' \
|
|
83
|
+
| sed -E 's/(\|\||;|\||&)/\n/g' \
|
|
84
|
+
| sed -E 's/__REA_LOGAND_a8f2c1__/\n/g' \
|
|
77
85
|
| sed -E 's/__REA_GTPIPE_a8f2c1__/>|/g'
|
|
78
86
|
}
|
|
79
87
|
|
|
@@ -151,6 +159,30 @@ any_segment_matches() {
|
|
|
151
159
|
return 1
|
|
152
160
|
}
|
|
153
161
|
|
|
162
|
+
# Return 0 if any segment of $1 (RAW — no prefix-stripping) matches the
|
|
163
|
+
# extended regex $2. Use this for checks where the prefix itself IS the
|
|
164
|
+
# signal — e.g. H10's `HUSKY=0 git commit` detection (the prefix-stripper
|
|
165
|
+
# would strip the `HUSKY=0` before any_segment_matches sees it). Also
|
|
166
|
+
# right for H15 (`REA_BYPASS=...`) and H16 (alias/function defs).
|
|
167
|
+
#
|
|
168
|
+
# 0.16.1 helix-016 sibling fix: H10 baseline corpus regressed from
|
|
169
|
+
# 0.15.0 because it migrated to `any_segment_matches` which strips
|
|
170
|
+
# env-var prefixes. The check needs the raw segment to fire.
|
|
171
|
+
any_segment_raw_matches() {
|
|
172
|
+
local cmd="$1"
|
|
173
|
+
local pattern="$2"
|
|
174
|
+
local segment
|
|
175
|
+
while IFS= read -r segment; do
|
|
176
|
+
# Trim leading whitespace for clean anchor matching, but otherwise
|
|
177
|
+
# leave the segment intact (env-var assignments preserved).
|
|
178
|
+
segment="${segment#"${segment%%[![:space:]]*}"}"
|
|
179
|
+
if printf '%s' "$segment" | grep -qiE "$pattern"; then
|
|
180
|
+
return 0
|
|
181
|
+
fi
|
|
182
|
+
done < <(_rea_split_segments "$cmd")
|
|
183
|
+
return 1
|
|
184
|
+
}
|
|
185
|
+
|
|
154
186
|
# Return 0 if any segment of $1 (after prefix-stripping) STARTS WITH
|
|
155
187
|
# the extended regex $2. Case-insensitive. Returns 1 if no segment
|
|
156
188
|
# starts with the pattern.
|
|
@@ -216,7 +216,7 @@ if any_segment_starts_with "$CMD" 'git[[:space:]]+commit.*--no-verify'; then
|
|
|
216
216
|
fi
|
|
217
217
|
|
|
218
218
|
# H10: HUSKY=0 bypass — suppresses all git hooks without --no-verify
|
|
219
|
-
if
|
|
219
|
+
if any_segment_raw_matches "$CMD" '^HUSKY=0[[:space:]]+git[[:space:]]+(commit|push|tag)'; then
|
|
220
220
|
add_high \
|
|
221
221
|
"HUSKY=0 — bypasses all husky git hooks" \
|
|
222
222
|
"Setting HUSKY=0 disables pre-commit, commit-msg, and pre-push safety gates without --no-verify." \
|
|
@@ -243,8 +243,15 @@ if any_segment_starts_with "$CMD" "rm[[:space:]]+-[a-zA-Z]*r[a-zA-Z]*f[[:space:]
|
|
|
243
243
|
"Alt: Move to a temp location first, or use 'rm -ri' for interactive deletion."
|
|
244
244
|
fi
|
|
245
245
|
|
|
246
|
-
# H12: curl/wget piped directly to shell (supply chain attack vector)
|
|
247
|
-
|
|
246
|
+
# H12: curl/wget piped directly to shell (supply chain attack vector).
|
|
247
|
+
# 0.16.1 helix-016 P1 fix: this check requires BOTH the curl/wget call
|
|
248
|
+
# AND the `| sh` to appear in the same shell pipeline. The 0.16.0
|
|
249
|
+
# refactor moved this into `any_segment_matches`, but the segmenter
|
|
250
|
+
# splits on `|` first — so `curl https://x | sh` decomposed into two
|
|
251
|
+
# segments (`curl https://x`, `sh`) and the regex (which requires both
|
|
252
|
+
# in one segment) never matched. Pipe-RCE is fundamentally a
|
|
253
|
+
# multi-segment property and must be checked against the raw command.
|
|
254
|
+
if printf '%s' "$CMD" | grep -qiE '(curl|wget)[^|]*\|[[:space:]]*(sudo[[:space:]]+)?(bash|sh|zsh|fish)'; then
|
|
248
255
|
add_high \
|
|
249
256
|
"curl/wget piped to shell — remote code execution" \
|
|
250
257
|
"Executing remote scripts without inspection is a major supply chain risk." \
|
|
@@ -268,7 +275,7 @@ if any_segment_starts_with "$CMD" 'git[[:space:]]+-c[[:space:]]+core\.hookspath'
|
|
|
268
275
|
fi
|
|
269
276
|
|
|
270
277
|
# H15: REA_BYPASS env var — attempted escape hatch
|
|
271
|
-
if
|
|
278
|
+
if any_segment_raw_matches "$CMD" '^REA_BYPASS[[:space:]]*='; then
|
|
272
279
|
add_high \
|
|
273
280
|
"REA_BYPASS env var — unauthorized bypass attempt" \
|
|
274
281
|
"Setting REA_BYPASS is not a supported escape mechanism and indicates a bypass attempt." \
|
|
@@ -276,7 +283,7 @@ if any_segment_matches "$CMD" '(^|[[:space:];]|&&|\|\|)REA_BYPASS[[:space:]]*=';
|
|
|
276
283
|
fi
|
|
277
284
|
|
|
278
285
|
# H16: alias/function definitions containing bypass strings
|
|
279
|
-
if
|
|
286
|
+
if any_segment_raw_matches "$CMD" '^(alias|function)[[:space:]]+[a-zA-Z_]+.*(--(no-verify|force)|HUSKY=0|core\.hookspath)'; then
|
|
280
287
|
add_high \
|
|
281
288
|
"Alias/function definition with bypass — circumventing safety gates" \
|
|
282
289
|
"Defining aliases or functions that embed bypass flags defeats safety hooks." \
|
|
@@ -73,15 +73,35 @@ extract_packages() {
|
|
|
73
73
|
# Anchor to start: only match when the install command is the FIRST
|
|
74
74
|
# thing on the segment, optionally preceded by `sudo` / `exec` /
|
|
75
75
|
# `time` / etc.
|
|
76
|
-
|
|
76
|
+
#
|
|
77
|
+
# 0.16.1 helix-016 P2 fix: also strip leading KEY=VALUE env-var
|
|
78
|
+
# assignments. Pre-fix the prefix allow-list only permitted
|
|
79
|
+
# sudo/exec/time, so `CI=1 pnpm add foo` and
|
|
80
|
+
# `NODE_ENV=development npm install bar` bypassed the audit
|
|
81
|
+
# entirely. POSIX shell allows any number of leading KEY=VALUE
|
|
82
|
+
# assignments before the command word; we strip them the same
|
|
83
|
+
# way the shell does.
|
|
84
|
+
local stripped_segment
|
|
85
|
+
stripped_segment=$(printf '%s' "$segment" | sed -E 's/^([[:space:]]*[A-Za-z_][A-Za-z0-9_]*=[^[:space:]]+[[:space:]]+)+//')
|
|
86
|
+
|
|
87
|
+
if printf '%s' "$stripped_segment" | grep -qiE '^(sudo[[:space:]]+|exec[[:space:]]+|time[[:space:]]+)*(npm[[:space:]]+(install|i|add)|pnpm[[:space:]]+(add|install|i)|yarn[[:space:]]+add)[[:space:]]+'; then
|
|
77
88
|
# Strip the leading prefix wrappers + install command, leaving args.
|
|
78
89
|
local after_cmd
|
|
79
|
-
after_cmd=$(printf '%s' "$
|
|
90
|
+
after_cmd=$(printf '%s' "$stripped_segment" | sed -E 's/^(sudo[[:space:]]+|exec[[:space:]]+|time[[:space:]]+)*(npm[[:space:]]+(install|i|add)|pnpm[[:space:]]+(add|install|i)|yarn[[:space:]]+add)[[:space:]]+//')
|
|
80
91
|
|
|
81
92
|
for token in $after_cmd; do
|
|
82
93
|
if [[ "$token" == -* ]]; then continue; fi
|
|
83
94
|
if [[ "$token" == ./* || "$token" == /* || "$token" == ../* ]]; then continue; fi
|
|
84
95
|
if [[ -z "$token" ]]; then continue; fi
|
|
96
|
+
# 0.16.1: tighten token classification (helix-016 sibling concern).
|
|
97
|
+
# A "package name" is something that doesn't contain shell
|
|
98
|
+
# metacharacters — `2>&1`, `$VAR`, etc. are never valid npm
|
|
99
|
+
# package names. Skip any token containing `=`, `>`, `<`, `&`,
|
|
100
|
+
# `|`, `;`, `$`, backtick, or quotes.
|
|
101
|
+
if [[ "$token" == *=* || "$token" == *">"* || "$token" == *"<"* ||
|
|
102
|
+
"$token" == *"&"* || "$token" == *"|"* || "$token" == *";"* ||
|
|
103
|
+
"$token" == *'$'* || "$token" == *'`'* ||
|
|
104
|
+
"$token" == *'"'* || "$token" == *"'"* ]]; then continue; fi
|
|
85
105
|
# `npm view` can't validate `@workspace:*` / `link:` / `file:`
|
|
86
106
|
# prefixes (workspace protocols). Skip them — they're never npm
|
|
87
107
|
# registry packages.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bookedsolid/rea",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Agentic governance layer for Claude Code — policy enforcement, hook-based safety gates, audit logging, and Codex-integrated adversarial review for AI-assisted projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Booked Solid Technology <oss@bookedsolid.tech> (https://bookedsolid.tech)",
|