@bookedsolid/rea 0.48.1 → 0.49.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/THREAT_MODEL.md +70 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +241 -0
- package/dist/cli/init.d.ts +12 -0
- package/dist/cli/init.js +161 -0
- package/dist/cli/install/self-pin.d.ts +440 -0
- package/dist/cli/install/self-pin.js +853 -0
- package/dist/cli/upgrade.js +134 -0
- package/dist/policy/loader.d.ts +13 -0
- package/dist/policy/loader.js +36 -0
- package/dist/policy/profiles.d.ts +13 -0
- package/dist/policy/profiles.js +12 -0
- package/dist/policy/types.d.ts +38 -0
- package/hooks/_lib/bootstrap-allowlist.sh +1075 -0
- package/hooks/blocked-paths-bash-gate.sh +35 -12
- package/hooks/protected-paths-bash-gate.sh +30 -12
- package/package.json +3 -1
- package/profiles/bst-internal-no-codex.yaml +4 -0
- package/profiles/bst-internal.yaml +28 -0
- package/profiles/client-engagement.yaml +9 -0
- package/profiles/lit-wc.yaml +6 -0
- package/profiles/minimal.yaml +11 -0
- package/profiles/open-source-no-codex.yaml +4 -0
- package/profiles/open-source.yaml +11 -0
|
@@ -41,21 +41,44 @@ shim_cli_missing_relevant() {
|
|
|
41
41
|
if [ -z "$cli_missing_cmd" ]; then
|
|
42
42
|
return 1
|
|
43
43
|
fi
|
|
44
|
+
|
|
45
|
+
# R5-P1: substring scan DETERMINES refusal; allowlist OPENS gates
|
|
46
|
+
# only. R7-P1: PM-route can ALSO return 2 (audit-integrity fail)
|
|
47
|
+
# which MUST refuse via banner regardless of substring scan.
|
|
48
|
+
local matched_blocked=0
|
|
44
49
|
local policy_file="${REA_ROOT}/.rea/policy.yaml"
|
|
45
|
-
if [
|
|
50
|
+
if [ -f "$policy_file" ]; then
|
|
51
|
+
# shellcheck source=_lib/policy-reader.sh
|
|
52
|
+
source "$(dirname "$0")/_lib/policy-reader.sh"
|
|
53
|
+
local entry
|
|
54
|
+
while IFS= read -r entry; do
|
|
55
|
+
[ -z "$entry" ] && continue
|
|
56
|
+
case "$cli_missing_cmd" in
|
|
57
|
+
*"$entry"*) matched_blocked=1; break ;;
|
|
58
|
+
esac
|
|
59
|
+
done < <(policy_reader_get_list blocked_paths 2>/dev/null)
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# shellcheck source=_lib/bootstrap-allowlist.sh
|
|
63
|
+
source "$(dirname "$0")/_lib/bootstrap-allowlist.sh"
|
|
64
|
+
|
|
65
|
+
# R7-P1 (codex round 7): 3-state PM-route return.
|
|
66
|
+
# 0 = auditable allow → exit 0 immediately.
|
|
67
|
+
# 2 = refuse-HARD (audit-integrity fail) → banner regardless
|
|
68
|
+
# of substring scan (the helper printed an explainer to
|
|
69
|
+
# stderr; we must NOT silently allow a payload whose audit
|
|
70
|
+
# record could not be written).
|
|
71
|
+
# * = refuse-fallthrough → defer to substring-scan verdict.
|
|
72
|
+
_bootstrap_shim_pm_route "blocked-paths-bash-gate" "$cli_missing_cmd" "$REA_ROOT"
|
|
73
|
+
case "$?" in
|
|
74
|
+
0) exit 0 ;;
|
|
75
|
+
2) return 0 ;;
|
|
76
|
+
esac
|
|
77
|
+
|
|
78
|
+
if [ "$matched_blocked" -eq 0 ]; then
|
|
46
79
|
return 1
|
|
47
80
|
fi
|
|
48
|
-
|
|
49
|
-
# shellcheck source=_lib/policy-reader.sh
|
|
50
|
-
source "$(dirname "$0")/_lib/policy-reader.sh"
|
|
51
|
-
local entry
|
|
52
|
-
while IFS= read -r entry; do
|
|
53
|
-
[ -z "$entry" ] && continue
|
|
54
|
-
case "$cli_missing_cmd" in
|
|
55
|
-
*"$entry"*) return 0 ;;
|
|
56
|
-
esac
|
|
57
|
-
done < <(policy_reader_get_list blocked_paths 2>/dev/null)
|
|
58
|
-
return 1
|
|
81
|
+
return 0
|
|
59
82
|
}
|
|
60
83
|
|
|
61
84
|
# shellcheck source=_lib/shim-runtime.sh
|
|
@@ -45,21 +45,24 @@ shim_cli_missing_relevant() {
|
|
|
45
45
|
if [ -z "$cli_missing_cmd" ]; then
|
|
46
46
|
return 1
|
|
47
47
|
fi
|
|
48
|
+
|
|
49
|
+
# R5-P1 (codex round 5): substring scan is DETERMINATIVE for
|
|
50
|
+
# refusal. Allowlist opens an audited-allow gate but never closes
|
|
51
|
+
# one.
|
|
52
|
+
local matched_protected=0
|
|
48
53
|
case "$cli_missing_cmd" in
|
|
49
|
-
*".claude/"*)
|
|
50
|
-
*".husky/"*)
|
|
51
|
-
*".rea/policy.yaml"*)
|
|
52
|
-
*".rea/HALT"*)
|
|
53
|
-
*".rea/last-review"*)
|
|
54
|
-
*".claude\\"*|*".husky\\"*|*".rea\\"*)
|
|
54
|
+
*".claude/"*) matched_protected=1 ;;
|
|
55
|
+
*".husky/"*) matched_protected=1 ;;
|
|
56
|
+
*".rea/policy.yaml"*) matched_protected=1 ;;
|
|
57
|
+
*".rea/HALT"*) matched_protected=1 ;;
|
|
58
|
+
*".rea/last-review"*) matched_protected=1 ;;
|
|
59
|
+
*".claude\\"*|*".husky\\"*|*".rea\\"*) matched_protected=1 ;;
|
|
55
60
|
esac
|
|
56
61
|
# 0.37.0: route protected_writes reads through the unified
|
|
57
62
|
# policy-reader (Tier 1 CLI → Tier 2 python3 → Tier 3 awk
|
|
58
|
-
# block-form).
|
|
59
|
-
# arrays (`protected_writes: [path/a, path/b]`) on CLI-missing
|
|
60
|
-
# installs.
|
|
63
|
+
# block-form).
|
|
61
64
|
local policy_file="${REA_ROOT}/.rea/policy.yaml"
|
|
62
|
-
if [ -f "$policy_file" ]; then
|
|
65
|
+
if [ "$matched_protected" -eq 0 ] && [ -f "$policy_file" ]; then
|
|
63
66
|
# shellcheck source=_lib/policy-reader.sh
|
|
64
67
|
source "$(dirname "$0")/_lib/policy-reader.sh"
|
|
65
68
|
local entry base
|
|
@@ -71,11 +74,26 @@ shim_cli_missing_relevant() {
|
|
|
71
74
|
esac
|
|
72
75
|
[ -z "$base" ] && continue
|
|
73
76
|
case "$cli_missing_cmd" in
|
|
74
|
-
*"$base"*)
|
|
77
|
+
*"$base"*) matched_protected=1; break ;;
|
|
75
78
|
esac
|
|
76
79
|
done < <(policy_reader_get_list protected_writes 2>/dev/null)
|
|
77
80
|
fi
|
|
78
|
-
|
|
81
|
+
|
|
82
|
+
# shellcheck source=_lib/bootstrap-allowlist.sh
|
|
83
|
+
source "$(dirname "$0")/_lib/bootstrap-allowlist.sh"
|
|
84
|
+
|
|
85
|
+
# R7-P1 (codex round 7): 3-state PM-route return. See the
|
|
86
|
+
# blocked-paths shim for the contract.
|
|
87
|
+
_bootstrap_shim_pm_route "protected-paths-bash-gate" "$cli_missing_cmd" "$REA_ROOT"
|
|
88
|
+
case "$?" in
|
|
89
|
+
0) exit 0 ;;
|
|
90
|
+
2) return 0 ;;
|
|
91
|
+
esac
|
|
92
|
+
|
|
93
|
+
if [ "$matched_protected" -eq 0 ]; then
|
|
94
|
+
return 1
|
|
95
|
+
fi
|
|
96
|
+
return 0
|
|
79
97
|
}
|
|
80
98
|
|
|
81
99
|
# shellcheck source=_lib/shim-runtime.sh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bookedsolid/rea",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
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)",
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"mvdan-sh": "0.10.1",
|
|
76
76
|
"proper-lockfile": "^4.1.2",
|
|
77
77
|
"safe-regex": "^2.1.1",
|
|
78
|
+
"semver": "^7.7.4",
|
|
78
79
|
"yaml": "^2.7.0",
|
|
79
80
|
"zod": "^3.23.0"
|
|
80
81
|
},
|
|
@@ -83,6 +84,7 @@
|
|
|
83
84
|
"@types/node": "^25.5.2",
|
|
84
85
|
"@types/proper-lockfile": "^4.1.4",
|
|
85
86
|
"@types/safe-regex": "^1.1.6",
|
|
87
|
+
"@types/semver": "^7.7.1",
|
|
86
88
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
87
89
|
"@typescript-eslint/parser": "^8.0.0",
|
|
88
90
|
"@vitest/coverage-v8": "^3.2.4",
|
|
@@ -31,6 +31,10 @@ blocked_paths:
|
|
|
31
31
|
- .github/workflows/release.yml
|
|
32
32
|
- SECURITY.md
|
|
33
33
|
- THREAT_MODEL.md
|
|
34
|
+
# 0.49.0 — gates Write/Edit tool calls targeting `package.json`.
|
|
35
|
+
# See `bst-internal.yaml` for the rationale and explicit
|
|
36
|
+
# out-of-scope statement on PM-induced writes.
|
|
37
|
+
- package.json
|
|
34
38
|
notification_channel: ''
|
|
35
39
|
# G9: Booked-internal consumers retain the stricter 0.2.x posture — a single
|
|
36
40
|
# literal injection match at write/destructive tier denies (does not merely
|
|
@@ -14,6 +14,21 @@ blocked_paths:
|
|
|
14
14
|
- .github/workflows/release.yml
|
|
15
15
|
- SECURITY.md
|
|
16
16
|
- THREAT_MODEL.md
|
|
17
|
+
# 0.49.0 — gates Write/Edit/MultiEdit/NotebookEdit tool calls
|
|
18
|
+
# targeting `package.json`. The bootstrap allowlist passes a
|
|
19
|
+
# CLI-missing PM payload through ONLY when `package.json` already
|
|
20
|
+
# declares `@bookedsolid/rea`, so blocking AGENT edits to the
|
|
21
|
+
# manifest narrows the Edit/Write-tier forge surface (an attacker
|
|
22
|
+
# can no longer add the declaration via Edit then invoke the
|
|
23
|
+
# allowed PM command). PM-induced writes to the manifest are
|
|
24
|
+
# explicitly out of scope (see THREAT_MODEL.md §5.23 "Out of
|
|
25
|
+
# scope"): a path-based blocklist cannot distinguish agent edits
|
|
26
|
+
# from PM-tool writes. The static manifest-write detector that
|
|
27
|
+
# would close that gap was deliberately removed in R17;
|
|
28
|
+
# defending against agent-initiated PM mutations needs a
|
|
29
|
+
# different abstraction (process-tree-aware policy / per-tool
|
|
30
|
+
# capability tokens) — not shipped in 0.49.0.
|
|
31
|
+
- package.json
|
|
17
32
|
notification_channel: ''
|
|
18
33
|
# G9: Booked-internal consumers retain the stricter 0.2.x posture — a single
|
|
19
34
|
# literal injection match at write/destructive tier denies (does not merely
|
|
@@ -80,3 +95,16 @@ attribution:
|
|
|
80
95
|
delegation_advisory:
|
|
81
96
|
enabled: true
|
|
82
97
|
threshold: 25
|
|
98
|
+
# 0.49.0 bootstrap allowlist (P3-1) — explicit declaration for parity
|
|
99
|
+
# with the dogfood `.rea/policy.yaml`. The other five shipped profiles
|
|
100
|
+
# (open-source*, client-engagement, lit-wc, minimal) inherit the zod
|
|
101
|
+
# schema default (`enabled: true`), so they need no entry here. The
|
|
102
|
+
# bst-internal profile pins it so the operator-visible policy file
|
|
103
|
+
# clearly states the position rather than relying on schema defaults.
|
|
104
|
+
# The allowlist passes a single-segment pnpm install / npm ci / yarn /
|
|
105
|
+
# corepack invocation through when (a) the rea CLI is unreachable, (b)
|
|
106
|
+
# the consumer's package.json declares `@bookedsolid/rea`, and (c)
|
|
107
|
+
# every other precondition (single-segment payload, exact argv shape,
|
|
108
|
+
# audit emission OK) holds. See hooks/_lib/bootstrap-allowlist.sh.
|
|
109
|
+
bootstrap_allowlist:
|
|
110
|
+
enabled: true
|
|
@@ -15,6 +15,15 @@ blocked_paths:
|
|
|
15
15
|
- THREAT_MODEL.md
|
|
16
16
|
- secrets/
|
|
17
17
|
- credentials/
|
|
18
|
+
# 0.49.0 — gates Write/Edit tool calls targeting `package.json`.
|
|
19
|
+
# Pairs with the always-on `bootstrap_allowlist` (schema default):
|
|
20
|
+
# the allowlist trusts a CLI-missing PM command only when
|
|
21
|
+
# `package.json` declares `@bookedsolid/rea`, so blocking AGENT
|
|
22
|
+
# edits to the manifest narrows the Edit/Write-tier forge surface.
|
|
23
|
+
# PM-induced writes are explicitly out of scope (see
|
|
24
|
+
# THREAT_MODEL.md §5.23 "Out of scope") — a path-based blocklist
|
|
25
|
+
# cannot distinguish agent edits from PM-tool writes.
|
|
26
|
+
- package.json
|
|
18
27
|
notification_channel: ''
|
|
19
28
|
context_protection:
|
|
20
29
|
delegate_to_subagent:
|
package/profiles/lit-wc.yaml
CHANGED
|
@@ -14,6 +14,12 @@ blocked_paths:
|
|
|
14
14
|
- .github/workflows/release.yml
|
|
15
15
|
- .github/workflows/publish.yml
|
|
16
16
|
- tokens/
|
|
17
|
+
# 0.49.0 — gates Write/Edit tool calls targeting `package.json`.
|
|
18
|
+
# Pairs with the always-on `bootstrap_allowlist` so the
|
|
19
|
+
# "consumer declares @bookedsolid/rea" precondition is meaningful.
|
|
20
|
+
# PM-induced writes are explicitly out of scope (THREAT_MODEL.md
|
|
21
|
+
# §5.23 "Out of scope").
|
|
22
|
+
- package.json
|
|
17
23
|
notification_channel: ''
|
|
18
24
|
# 0.30.0 attribution augmenter — opt-in.
|
|
19
25
|
# Husky prepare-commit-msg hook appends a Co-Authored-By trailer to
|
package/profiles/minimal.yaml
CHANGED
|
@@ -8,6 +8,17 @@ block_ai_attribution: true
|
|
|
8
8
|
blocked_paths:
|
|
9
9
|
- .env
|
|
10
10
|
- .env.*
|
|
11
|
+
# 0.49.0 — gates Write/Edit tool calls targeting `package.json`.
|
|
12
|
+
# The always-on `bootstrap_allowlist` (schema default) trusts a
|
|
13
|
+
# CLI-missing PM payload only when `package.json` declares
|
|
14
|
+
# `@bookedsolid/rea`; without an Edit/Write gate on the manifest,
|
|
15
|
+
# an agent could ADD that declaration first and then route an
|
|
16
|
+
# otherwise-disallowed PM command through the allowlist. PM-
|
|
17
|
+
# induced writes are explicitly out of scope (THREAT_MODEL.md
|
|
18
|
+
# §5.23 "Out of scope"). Operators who deliberately want agent
|
|
19
|
+
# freedom to edit `package.json` should remove this entry AND
|
|
20
|
+
# set `bootstrap_allowlist.enabled: false` in tandem.
|
|
21
|
+
- package.json
|
|
11
22
|
notification_channel: ''
|
|
12
23
|
# 0.30.0 attribution augmenter — opt-in.
|
|
13
24
|
# When enabled: true, the husky prepare-commit-msg hook appends a
|
|
@@ -30,6 +30,10 @@ blocked_paths:
|
|
|
30
30
|
- SECURITY.md
|
|
31
31
|
- .github/workflows/release.yml
|
|
32
32
|
- .github/workflows/publish.yml
|
|
33
|
+
# 0.49.0 — gates Write/Edit tool calls targeting `package.json`.
|
|
34
|
+
# See `open-source.yaml` for the rationale; this variant inherits
|
|
35
|
+
# the same posture sans Codex review.
|
|
36
|
+
- package.json
|
|
33
37
|
notification_channel: ''
|
|
34
38
|
# 0.30.0 attribution augmenter — opt-in.
|
|
35
39
|
# Husky prepare-commit-msg hook appends a Co-Authored-By trailer to
|
|
@@ -15,6 +15,17 @@ blocked_paths:
|
|
|
15
15
|
- SECURITY.md
|
|
16
16
|
- .github/workflows/release.yml
|
|
17
17
|
- .github/workflows/publish.yml
|
|
18
|
+
# 0.49.0 — gates Write/Edit tool calls targeting `package.json`.
|
|
19
|
+
# The always-on `bootstrap_allowlist` (schema default) trusts a
|
|
20
|
+
# CLI-missing PM payload only when `package.json` declares
|
|
21
|
+
# `@bookedsolid/rea`. Without an Edit/Write-tier gate on the
|
|
22
|
+
# manifest, an agent could ADD that declaration first and then
|
|
23
|
+
# invoke the allowed PM command, defeating the precondition.
|
|
24
|
+
# PM-induced writes are explicitly out of scope (THREAT_MODEL.md
|
|
25
|
+
# §5.23 "Out of scope"). Operators who need agent freedom to edit
|
|
26
|
+
# package.json should remove this entry in `.rea/policy.yaml`
|
|
27
|
+
# AND set `bootstrap_allowlist.enabled: false` in tandem.
|
|
28
|
+
- package.json
|
|
18
29
|
notification_channel: ''
|
|
19
30
|
# 0.30.0 attribution augmenter — opt-in.
|
|
20
31
|
# Husky prepare-commit-msg hook appends a Co-Authored-By trailer to
|