@bookedsolid/rea 0.30.1 → 0.32.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 (51) hide show
  1. package/.husky/prepare-commit-msg +80 -6
  2. package/MIGRATING.md +24 -15
  3. package/dist/cli/audit-specialists.d.ts +106 -24
  4. package/dist/cli/audit-specialists.js +239 -64
  5. package/dist/cli/delegation-advisory.d.ts +161 -0
  6. package/dist/cli/delegation-advisory.js +433 -0
  7. package/dist/cli/doctor.d.ts +110 -39
  8. package/dist/cli/doctor.js +302 -90
  9. package/dist/cli/hook.d.ts +6 -0
  10. package/dist/cli/hook.js +45 -22
  11. package/dist/cli/index.js +1 -1
  12. package/dist/cli/install/settings-merge.js +25 -0
  13. package/dist/cli/roster.d.ts +119 -0
  14. package/dist/cli/roster.js +141 -0
  15. package/dist/hooks/_lib/halt-check.d.ts +78 -0
  16. package/dist/hooks/_lib/halt-check.js +106 -0
  17. package/dist/hooks/_lib/payload.d.ts +86 -0
  18. package/dist/hooks/_lib/payload.js +166 -0
  19. package/dist/hooks/_lib/segments.d.ts +100 -0
  20. package/dist/hooks/_lib/segments.js +444 -0
  21. package/dist/hooks/attribution-advisory/index.d.ts +72 -0
  22. package/dist/hooks/attribution-advisory/index.js +233 -0
  23. package/dist/hooks/bash-scanner/protected-scan.js +14 -2
  24. package/dist/hooks/pr-issue-link-gate/index.d.ts +91 -0
  25. package/dist/hooks/pr-issue-link-gate/index.js +127 -0
  26. package/dist/hooks/security-disclosure-gate/index.d.ts +91 -0
  27. package/dist/hooks/security-disclosure-gate/index.js +502 -0
  28. package/dist/policy/loader.d.ts +23 -0
  29. package/dist/policy/loader.js +46 -0
  30. package/dist/policy/profiles.d.ts +23 -0
  31. package/dist/policy/profiles.js +16 -0
  32. package/dist/policy/types.d.ts +61 -0
  33. package/hooks/_lib/protected-paths.sh +10 -3
  34. package/hooks/attribution-advisory.sh +139 -131
  35. package/hooks/delegation-advisory.sh +162 -0
  36. package/hooks/pr-issue-link-gate.sh +114 -45
  37. package/hooks/security-disclosure-gate.sh +148 -316
  38. package/hooks/settings-protection.sh +13 -9
  39. package/package.json +1 -1
  40. package/profiles/bst-internal-no-codex.yaml +12 -0
  41. package/profiles/bst-internal.yaml +13 -0
  42. package/profiles/client-engagement.yaml +11 -0
  43. package/profiles/lit-wc.yaml +10 -0
  44. package/profiles/minimal.yaml +11 -0
  45. package/profiles/open-source-no-codex.yaml +11 -0
  46. package/profiles/open-source.yaml +11 -0
  47. package/templates/attribution-advisory.dogfood-staged.sh +170 -0
  48. package/templates/pr-issue-link-gate.dogfood-staged.sh +134 -0
  49. package/templates/prepare-commit-msg.husky.sh +80 -6
  50. package/templates/security-disclosure-gate.dogfood-staged.sh +171 -0
  51. package/templates/settings-protection.dogfood.patch +58 -0
@@ -1,65 +1,134 @@
1
- #!/usr/bin/env bash
2
- # pr-issue-link-gate.sh — PreToolUse: Bash
1
+ #!/bin/bash
2
+ # PreToolUse hook: pr-issue-link-gate.sh
3
+ # 0.32.0+ — Node-binary shim for `rea hook pr-issue-link-gate`.
3
4
  #
4
- # Ensures every `gh pr create` command references at least one GitHub issue
5
- # via closes/fixes/resolves #N syntax in the PR body. When the magic keyword
6
- # is present, GitHub automatically closes the linked issue when the PR merges
7
- # to the default branch and creates a cross-reference in the issue timeline.
5
+ # Pre-0.32.0 the gate's full body lived here as bash; the migration to
6
+ # the parser-backed Node binary moves the matching + advisory logic
7
+ # into `src/hooks/pr-issue-link-gate/index.ts`. This shim is the
8
+ # Claude Code dispatcher's view of the hook it forwards stdin to the
9
+ # CLI and exits with whatever the CLI returns.
8
10
  #
9
- # This gate is ADVISORY (exit 0) — it warns but does not block. Some PRs
10
- # legitimately have no linked issue (chores, hotfixes, release PRs). The
11
- # advisory gives the agent an opportunity to add the link before proceeding.
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).
12
13
  #
13
- # Only active for Bash tool calls containing `gh pr create`.
14
- # JSONL-only projects (no GitHub) are unaffected — gh is unavailable there.
14
+ # # CLI-resolution trust boundary
15
15
  #
16
- # Triggered by: PreToolUse Bash tool
17
-
18
- set -euo pipefail
16
+ # Codex round 1 P1 (2026-05-15): mirrors the realpath sandbox check
17
+ # from `delegation-advisory.sh` §3 and `protected-paths-bash-gate.sh`
18
+ # §6. The resolved CLI MUST live INSIDE realpath(CLAUDE_PROJECT_DIR)
19
+ # AND have an ancestor `package.json` whose `name` is
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.
19
45
 
20
- # shellcheck source=_lib/common.sh
21
- source "$(dirname "$0")/_lib/common.sh"
46
+ set -uo pipefail
22
47
 
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
+ # shellcheck source=_lib/halt-check.sh
51
+ source "$(dirname "$0")/_lib/halt-check.sh"
23
52
  check_halt
53
+ REA_ROOT=$(rea_root)
24
54
 
25
- INPUT="$(cat)"
26
- TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""')
55
+ proj="${CLAUDE_PROJECT_DIR:-$REA_ROOT}"
27
56
 
28
- if [[ "$TOOL_NAME" != "Bash" ]]; then
29
- exit 0
57
+ # 2. Resolve the rea CLI through the fixed 2-tier sandboxed order.
58
+ REA_ARGV=()
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"
30
66
  fi
31
67
 
32
- COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
68
+ if [ "${#REA_ARGV[@]}" -eq 0 ]; then
69
+ exit 0
70
+ fi
33
71
 
34
- # Only intercept gh pr create
35
- if ! echo "$COMMAND" | grep -qE 'gh\s+pr\s+create'; then
72
+ # 3. Realpath sandbox check — mirrors delegation-advisory.sh §3.
73
+ if ! command -v node >/dev/null 2>&1; then
36
74
  exit 0
37
75
  fi
38
76
 
39
- require_jq
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)
40
109
 
41
- # Check for closing keywords followed by an issue number
42
- # Accepted: closes #N, fixes #N, resolves #N (case-insensitive, any spacing)
43
- if echo "$COMMAND" | grep -qiE '(closes|fixes|resolves)\s+#[0-9]+'; then
110
+ if [ "$sandbox_check" != "ok" ]; then
111
+ printf 'rea: pr-issue-link-gate skipped (sandbox check: %s)\n' "$sandbox_check" >&2
44
112
  exit 0
45
113
  fi
46
114
 
47
- # Advisory warn but do not block.
48
- # Chore PRs, release PRs, and hotfixes may legitimately have no linked issue.
49
- printf 'PR ISSUE LINK ADVISORY: This PR does not reference a GitHub issue.\n' >&2
50
- printf '\n' >&2
51
- printf 'When a PR body includes a closing reference, GitHub automatically:\n' >&2
52
- printf ' - Closes the issue when the PR merges to the default branch\n' >&2
53
- printf ' - Creates a cross-reference in the issue timeline\n' >&2
54
- printf ' - Links the PR in the CHANGELOG context\n' >&2
55
- printf '\n' >&2
56
- printf 'Add to the --body:\n' >&2
57
- printf ' closes #N closes one issue\n' >&2
58
- printf ' fixes #N same effect\n' >&2
59
- printf ' resolves #N same effect\n' >&2
60
- printf ' closes #N, closes #M closes multiple issues\n' >&2
61
- printf '\n' >&2
62
- printf 'If this is a chore, release, or hotfix PR with no upstream issue, you may proceed.\n' >&2
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
63
127
 
64
- # Exit 0 advisory only, does not block the PR creation
65
- exit 0
128
+ # 5. Forward stdin to the CLI synchronously. The advisory text must
129
+ # reach the operator's stderr before this hook returns; the CLI's
130
+ # own exit code is the hook's exit code (0 normally, 2 under HALT
131
+ # or malformed payload).
132
+ INPUT=$(cat)
133
+ printf '%s' "$INPUT" | "${REA_ARGV[@]}" hook pr-issue-link-gate
134
+ exit $?