@bookedsolid/rea 0.10.0 → 0.10.2
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/dist/audit/append.d.ts +35 -1
- package/dist/audit/append.js +79 -11
- package/dist/cli/audit.js +130 -34
- package/dist/cli/doctor.js +1 -1
- package/dist/cli/index.js +18 -0
- package/dist/cli/tofu.d.ts +57 -0
- package/dist/cli/tofu.js +134 -0
- package/dist/gateway/audit/rotator.js +4 -0
- package/dist/gateway/middleware/audit-types.d.ts +35 -0
- package/dist/gateway/middleware/audit.js +6 -0
- package/dist/hooks/review-gate/args.d.ts +126 -0
- package/dist/hooks/review-gate/args.js +315 -0
- package/dist/hooks/review-gate/banner.d.ts +97 -0
- package/dist/hooks/review-gate/banner.js +172 -0
- package/dist/hooks/review-gate/cache-key.d.ts +55 -0
- package/dist/hooks/review-gate/cache-key.js +41 -0
- package/dist/hooks/review-gate/constants.d.ts +26 -0
- package/dist/hooks/review-gate/constants.js +34 -0
- package/dist/hooks/review-gate/errors.d.ts +72 -0
- package/dist/hooks/review-gate/errors.js +100 -0
- package/dist/hooks/review-gate/hash.d.ts +43 -0
- package/dist/hooks/review-gate/hash.js +46 -0
- package/dist/hooks/review-gate/index.d.ts +21 -0
- package/dist/hooks/review-gate/index.js +21 -0
- package/dist/hooks/review-gate/metadata.d.ts +98 -0
- package/dist/hooks/review-gate/metadata.js +158 -0
- package/dist/hooks/review-gate/policy.d.ts +55 -0
- package/dist/hooks/review-gate/policy.js +71 -0
- package/dist/hooks/review-gate/protected-paths.d.ts +46 -0
- package/dist/hooks/review-gate/protected-paths.js +76 -0
- package/dist/registry/tofu-gate.js +4 -1
- package/hooks/_lib/push-review-core.sh +121 -25
- package/package.json +1 -1
|
@@ -719,12 +719,20 @@ pr_core_run() {
|
|
|
719
719
|
# fail-closed and require an explicit review.
|
|
720
720
|
local SOURCE_SHA="" MERGE_BASE="" TARGET_BRANCH="" SOURCE_REF=""
|
|
721
721
|
local HAS_DELETE=0 BEST_COUNT=0
|
|
722
|
-
local rec local_sha remote_sha local_ref remote_ref target mb mb_status count count_status
|
|
722
|
+
local rec local_sha remote_sha local_ref remote_ref target resolved_base mb mb_status count count_status
|
|
723
723
|
for rec in "${REFSPEC_RECORDS[@]}"; do
|
|
724
724
|
IFS='|' read -r local_sha remote_sha local_ref remote_ref <<<"$rec"
|
|
725
725
|
target="${remote_ref#refs/heads/}"
|
|
726
726
|
target="${target#refs/for/}"
|
|
727
727
|
[[ -z "$target" ]] && target="main"
|
|
728
|
+
# Defect N: track the SEMANTIC base (the ref the diff was anchored on)
|
|
729
|
+
# distinctly from `target` (the pushed remote ref). For a tracked branch
|
|
730
|
+
# they coincide; for a new branch, `target` is the branch name being
|
|
731
|
+
# created — which is NOT what we reviewed against, so `Target:` must
|
|
732
|
+
# echo `resolved_base` instead. Default to `target` for the tracked
|
|
733
|
+
# case; the new-branch path overrides with the resolved default_ref
|
|
734
|
+
# short name below.
|
|
735
|
+
resolved_base="$target"
|
|
728
736
|
|
|
729
737
|
if [[ "$local_sha" == "$ZERO_SHA" ]]; then
|
|
730
738
|
HAS_DELETE=1
|
|
@@ -774,25 +782,81 @@ pr_core_run() {
|
|
|
774
782
|
#
|
|
775
783
|
# argv_remote is set from the adapter's argv (git passes the remote name
|
|
776
784
|
# as $1 on pre-push); defaults to "origin" when absent (BUG-008 sniff).
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
785
|
+
#
|
|
786
|
+
# Defect N (0.10.1): BEFORE falling back to the remote's default branch,
|
|
787
|
+
# consult per-branch config `branch.<source>.base`. A feature branch
|
|
788
|
+
# targeting `dev` in a main-as-production repo would otherwise resolve
|
|
789
|
+
# against `origin/main` silently, producing a diff that spans the entire
|
|
790
|
+
# dev→main history — reviewers see "Scope: 28690 lines" for a 4-file
|
|
791
|
+
# change. The git-config route uses local branch knowledge that is
|
|
792
|
+
# authoritative for this working copy (set via `git branch --set-upstream`,
|
|
793
|
+
# or by CI tooling that tracks the intended target). This is consulted
|
|
794
|
+
# BEFORE origin/HEAD because the latter is a server-default that may
|
|
795
|
+
# mis-represent the reviewer's actual intent for this specific branch.
|
|
796
|
+
local default_ref default_ref_status configured_base source_branch
|
|
797
|
+
source_branch="${local_ref#refs/heads/}"
|
|
798
|
+
default_ref=""
|
|
799
|
+
# Codex 0.10.1 finding #1: `local` is function-scoped, not loop-
|
|
800
|
+
# iteration-scoped — without an explicit reset, iteration N inherits
|
|
801
|
+
# iteration N-1's configured_base and falsely promotes resolved_base
|
|
802
|
+
# when the current refspec's local_ref does NOT begin with refs/heads/
|
|
803
|
+
# (tag push, gerrit-style refs/for/, etc.). Reset before every
|
|
804
|
+
# potential assignment so each iteration sees a clean slate.
|
|
805
|
+
configured_base=""
|
|
806
|
+
|
|
807
|
+
if [[ -n "$source_branch" && "$source_branch" != "HEAD" ]]; then
|
|
808
|
+
configured_base=$(cd "$REA_ROOT" && git config --get "branch.${source_branch}.base" 2>/dev/null || echo "")
|
|
809
|
+
if [[ -n "$configured_base" ]]; then
|
|
810
|
+
# Prefer the REMOTE-TRACKING form so the gate still anchors on a
|
|
811
|
+
# server-authoritative ref (see the local-ref hijack explanation
|
|
812
|
+
# above). Fall back to the local short ref only if the remote
|
|
813
|
+
# counterpart doesn't exist, with a visible WARN on stderr — the
|
|
814
|
+
# local ref is less trustworthy and the reviewer should know.
|
|
815
|
+
if cd "$REA_ROOT" && git rev-parse --verify --quiet "refs/remotes/${argv_remote}/${configured_base}" >/dev/null 2>&1; then
|
|
816
|
+
default_ref="refs/remotes/${argv_remote}/${configured_base}"
|
|
817
|
+
elif cd "$REA_ROOT" && git rev-parse --verify --quiet "refs/heads/${configured_base}" >/dev/null 2>&1; then
|
|
818
|
+
default_ref="refs/heads/${configured_base}"
|
|
819
|
+
printf 'WARN: branch.%s.base=%s resolved to local ref; remote counterpart %s/%s missing — reviewer-side diff may be stale\n' \
|
|
820
|
+
"$source_branch" "$configured_base" "$argv_remote" "$configured_base" >&2
|
|
821
|
+
fi
|
|
822
|
+
fi
|
|
823
|
+
fi
|
|
824
|
+
|
|
825
|
+
if [[ -z "$default_ref" ]]; then
|
|
826
|
+
default_ref=$(cd "$REA_ROOT" && git symbolic-ref "refs/remotes/${argv_remote}/HEAD" 2>/dev/null)
|
|
827
|
+
default_ref_status=$?
|
|
828
|
+
if [[ "$default_ref_status" -ne 0 || -z "$default_ref" ]]; then
|
|
829
|
+
# symbolic-ref failed (common on shallow or mirror clones where
|
|
830
|
+
# origin/HEAD was never set). Probe the common default-branch names in
|
|
831
|
+
# order: main, then master. Both are remote-tracking refs and still
|
|
832
|
+
# server-authoritative; the order matters only for projects that still
|
|
833
|
+
# default to `master` (older internal forks), where without this
|
|
834
|
+
# fallback the first push of a new branch would fail closed.
|
|
835
|
+
if cd "$REA_ROOT" && git rev-parse --verify --quiet "refs/remotes/${argv_remote}/main" >/dev/null 2>&1; then
|
|
836
|
+
default_ref="refs/remotes/${argv_remote}/main"
|
|
837
|
+
elif cd "$REA_ROOT" && git rev-parse --verify --quiet "refs/remotes/${argv_remote}/master" >/dev/null 2>&1; then
|
|
838
|
+
default_ref="refs/remotes/${argv_remote}/master"
|
|
839
|
+
else
|
|
840
|
+
default_ref=""
|
|
841
|
+
fi
|
|
793
842
|
fi
|
|
794
843
|
fi
|
|
795
844
|
if [[ -n "$default_ref" ]]; then
|
|
845
|
+
# Defect N: if operator-configured `branch.<source>.base` resolved the
|
|
846
|
+
# ref we're about to diff against, overwrite `resolved_base` with the
|
|
847
|
+
# short name so TARGET_BRANCH (and the Target: label) reflect the
|
|
848
|
+
# actual review anchor. Without an explicit config override, leave
|
|
849
|
+
# `resolved_base` at the refspec target — this preserves the cache
|
|
850
|
+
# contract for new-branch pushes where remote_ref is the same as the
|
|
851
|
+
# source branch (the common case) and for bare pushes that
|
|
852
|
+
# argv-resolve via `@{upstream}`. Only operators who opted into a
|
|
853
|
+
# per-branch base get the label promoted, keeping the change
|
|
854
|
+
# backward-compatible for every other path.
|
|
855
|
+
if [[ -n "$configured_base" ]]; then
|
|
856
|
+
resolved_base="${default_ref#refs/remotes/${argv_remote}/}"
|
|
857
|
+
resolved_base="${resolved_base#refs/heads/}"
|
|
858
|
+
[[ -z "$resolved_base" ]] && resolved_base="$default_ref"
|
|
859
|
+
fi
|
|
796
860
|
mb=$(cd "$REA_ROOT" && git merge-base "$default_ref" "$local_sha" 2>/dev/null || echo "")
|
|
797
861
|
if [[ -z "$mb" ]]; then
|
|
798
862
|
# default_ref resolved but merge-base came back empty (unrelated
|
|
@@ -867,13 +931,40 @@ pr_core_run() {
|
|
|
867
931
|
if [[ "$CODEX_WAIVER_ACTIVE" == "1" ]]; then
|
|
868
932
|
_codex_ok=1
|
|
869
933
|
elif [[ -f "$_audit" ]]; then
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
934
|
+
# Defect P (0.10.1): require .emission_source == "rea-cli" or
|
|
935
|
+
# "codex-cli" so agents cannot forge a codex.review record by
|
|
936
|
+
# directly calling appendAuditRecord() from an ad-hoc .mjs script
|
|
937
|
+
# (the generic helper stamps "other"). Legacy records (pre-0.10.1)
|
|
938
|
+
# have no emission_source field and are rejected — the first push
|
|
939
|
+
# on an upgraded consumer requires a fresh `rea audit record
|
|
940
|
+
# codex-review` (or Codex CLI emission) which stamps "rea-cli".
|
|
941
|
+
#
|
|
942
|
+
# Defect T/U (0.10.2): read the audit file as raw lines and parse
|
|
943
|
+
# each with `fromjson?`. Before 0.10.2 this scan used
|
|
944
|
+
# `jq -e '<filter>' "$_audit"` which feeds the file as a single
|
|
945
|
+
# JSON stream — a single malformed line (literal backslash-u
|
|
946
|
+
# followed by non-hex characters inside a string, for example)
|
|
947
|
+
# makes jq bail on the stream with exit 2 and the `select` never
|
|
948
|
+
# runs against ANY record, including legitimate codex.review
|
|
949
|
+
# entries further down the file. The failure is total: every
|
|
950
|
+
# cached codex.review receipt becomes unreachable until the
|
|
951
|
+
# corrupt line is hand-edited out. `-R` flips jq into raw-input
|
|
952
|
+
# mode (one string per line), and `fromjson?` is the error-
|
|
953
|
+
# suppressing parser — malformed lines silently yield empty
|
|
954
|
+
# output. The `select` filter then inspects each successfully
|
|
955
|
+
# parsed record exactly as before, and `grep -q .` detects
|
|
956
|
+
# whether ANY record survived the filter. Lines 1107 and the
|
|
957
|
+
# earlier cache_result scans at :432/:612 operate on a single
|
|
958
|
+
# printf'd JSON string, not audit.jsonl, so they remain `jq -e`.
|
|
959
|
+
if jq -R --arg sha "$local_sha" '
|
|
960
|
+
fromjson?
|
|
961
|
+
| select(
|
|
962
|
+
.tool_name == "codex.review"
|
|
963
|
+
and .metadata.head_sha == $sha
|
|
964
|
+
and (.metadata.verdict == "pass" or .metadata.verdict == "concerns")
|
|
965
|
+
and (.emission_source == "rea-cli" or .emission_source == "codex-cli")
|
|
966
|
+
)
|
|
967
|
+
' "$_audit" 2>/dev/null | grep -q .; then
|
|
877
968
|
_codex_ok=1
|
|
878
969
|
fi
|
|
879
970
|
fi
|
|
@@ -918,7 +1009,12 @@ pr_core_run() {
|
|
|
918
1009
|
if [[ -z "$SOURCE_SHA" ]] || [[ "$count" -gt "$BEST_COUNT" ]]; then
|
|
919
1010
|
SOURCE_SHA="$local_sha"
|
|
920
1011
|
MERGE_BASE="$mb"
|
|
921
|
-
|
|
1012
|
+
# Defect N: use `resolved_base` (the actual merge-base anchor we
|
|
1013
|
+
# diffed against), not `target` (the pushed-ref name). For tracked
|
|
1014
|
+
# branches these are the same; for new branches without an upstream
|
|
1015
|
+
# the distinction is the difference between "Target: <source-branch>"
|
|
1016
|
+
# (misleading) and "Target: main" (or whichever base was resolved).
|
|
1017
|
+
TARGET_BRANCH="$resolved_base"
|
|
922
1018
|
SOURCE_REF="$local_ref"
|
|
923
1019
|
BEST_COUNT="$count"
|
|
924
1020
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bookedsolid/rea",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
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)",
|