Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .code-review-graphignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# BEGIN AI-HUB CRG GLOBAL POLICY
build/**
.worktrees/**
worktrees/**
.agents/worktrees/**
.code-review-graph/wiki/**
*.db
*.db-shm
*.db-wal
*.sqlite
*.sqlite3
*.min.js
*.min.css
coverage/**
.coverage/**
.pytest_cache/**
.ruff_cache/**
.mypy_cache/**
.tox/**
.cache/**
tmp/**
temp/**
.claude/worktrees/**
.codex/worktrees/**
.gemini/worktrees/**
.kimi-code/worktrees/**
.cursor/worktrees/**
.config/worktrees/**
.vscode/worktrees/**
.aider/worktrees/**
# END AI-HUB CRG GLOBAL POLICY
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export RUST_2024_LINTS := -D unsafe_op_in_unsafe_fn -D rust_2024_compatibility -
gate = [ "$(APPLY)" = "Y" ] || { printf "DRY-RUN: would %s; set APPLY=Y to execute\n" "$(1)" >&2; exit 0; }

# --- WHATS_<verb> phase SSOT (drives sub-help + error arms) -------------------
WHATS_check := fmt lint validate audit udeps coverage qlty all
WHATS_check := fmt lint staged validate audit udeps coverage qlty hooks guard all
WHATS_fix := fmt lint docs all
WHATS_dev := run docker-up docker-down docker-logs docker-test
WHATS_docs := build serve lint validate sync rust check setup adr adr-new diagrams
Expand Down
11 changes: 7 additions & 4 deletions makefiles/dispatch.mk
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,14 @@ define DISPATCH_CHECK
@case "$(WHAT)" in \
fmt) cargo fmt --all -- --check ;; \
lint) cargo fmt --all -- --check && cargo clippy --all-targets -- -D warnings ;; \
staged) bash $(MCB_SH) check-staged ;; \
validate) bash $(MCB_SH) validate $(if $(filter 1,$(QUICK)),quick,full) ;; \
audit) cargo audit $(foreach i,$(MCB_AUDIT_IGNORES),--ignore $(i)) && $(MAKE) check WHAT=udeps ;; \
udeps) command -v cargo-udeps >/dev/null 2>&1 || cargo install cargo-udeps; cargo +nightly udeps --workspace ;; \
coverage) cargo tarpaulin --out Lcov --output-dir coverage --exclude-files 'crates/*/tests/integration/*' --exclude-files 'crates/*/tests/admin/*' --timeout 300 ;; \
qlty) mkdir -p docs/reports; ./scripts/analyze_qlty.py --scan --check --summary --markdown docs/reports/qlty-check-REPORTS.md; ./scripts/analyze_qlty.py --scan --smells --summary --markdown docs/reports/qlty-smells-REPORTS.md ;; \
hooks) bash scripts/lib/tests/test-hooks.sh ;; \
guard) bash $(MCB_SH) guard ;; \
""|all) cargo fmt --all -- --check && $(MAKE) lint-impl && $(MAKE) test && bash $(MCB_SH) validate $(if $(filter 1,$(QUICK)),quick,full) ;; \
*) printf "ERRO: WHAT '%s' invalido. Validos: $(WHATS_check)\n" "$(WHAT)" >&2; exit 2 ;; \
esac
Expand Down Expand Up @@ -202,7 +205,7 @@ define DISPATCH_GIT
log) git log --oneline -$(or $(LOG_N),10) ;; \
show) git show --stat $(or $(REF),HEAD) ;; \
add) bash $(MCB_SH) files-safe "$(FILES)"; $(call require_var,FILES); git add $(FILES) ;; \
commit) $(call require_var,MSG); bash $(MCB_SH) files-safe "$(FILES)"; [ -n "$(FILES)" ] && git add $(FILES) || true; $(call gate,commit); git commit -m "$(MSG)" ;; \
commit) $(call require_var,MSG); bash $(MCB_SH) files-safe "$(FILES)"; $(call gate,commit); [ -n "$(FILES)" ] && git add $(FILES) || true; git commit -m "$(MSG)" ;; \
push) $(call gate,push $(BRANCH)); git push origin $(BRANCH) ;; \
pull) git pull origin $(BRANCH) ;; \
branch) [ -z "$(REF)" ] && git branch -a || git branch $(REF) $(BASE) ;; \
Expand Down Expand Up @@ -235,7 +238,7 @@ endef
define DISPATCH_SUB
@case "$(WHAT)" in \
""|status) git submodule status ;; \
sync) git submodule sync --recursive; git submodule update --init --recursive ;; \
sync) bash $(MCB_SH) sync-submodules ;; \
diff) git submodule foreach --quiet 'D=$$(git diff); [ -n "$$D" ] && { echo "=== $$name ==="; git diff; } || true' ;; \
commit) $(call require_var,SUB); $(call require_var,MSG); $(call gate,commit in submodule $(SUB)); (cd third-party/$(SUB) && git add -A && git commit -m "$(MSG)") ;; \
push) $(call require_var,SUB); $(call gate,push submodule $(SUB)); (cd third-party/$(SUB) && git push) ;; \
Expand All @@ -247,10 +250,10 @@ endef
# --- setup -------------------------------------------------------------------
define DISPATCH_SETUP
@case "$(WHAT)" in \
hooks) cp scripts/hooks/pre-commit .git/hooks/pre-commit; chmod +x .git/hooks/pre-commit; echo "✓ pre-commit hook installed" ;; \
hooks) bash $(MCB_SH) install-hooks ;; \
tools) cargo install cargo-udeps cargo-audit cargo-tarpaulin 2>/dev/null || true; echo "✓ tools installed" ;; \
adr) ./scripts/setup/install-adr-tools.sh ;; \
""|all) cp scripts/hooks/pre-commit .git/hooks/pre-commit; chmod +x .git/hooks/pre-commit; echo "✓ pre-commit hook installed"; cargo install cargo-udeps cargo-audit cargo-tarpaulin 2>/dev/null || true; ./scripts/setup/install-adr-tools.sh 2>/dev/null || true; echo "✓ setup complete" ;; \
""|all) bash $(MCB_SH) install-hooks; cargo install cargo-udeps cargo-audit cargo-tarpaulin 2>/dev/null || true; ./scripts/setup/install-adr-tools.sh 2>/dev/null || true; echo "✓ setup complete" ;; \
*) printf "ERRO: WHAT '%s' invalido. Validos: $(WHATS_setup)\n" "$(WHAT)" >&2; exit 2 ;; \
esac
endef
Expand Down
8 changes: 4 additions & 4 deletions scripts/hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/usr/bin/env bash
# Installed by `make setup WHAT=hooks`. Runs the same gates as CI, via the
# canonical monopoly. No bypass — fix the cause, not the gate (AGENTS.md §3).
# Installed by `make setup WHAT=hooks`. Runs the canonical commit gates without
# bypassing hooks or calling removed Make targets.
# guard runs in --staged mode so it blocks NEW violations in this commit, not
# the retroactive baseline; `make guard` (full tree) is the CI/manual scan.
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
[ -f scripts/lib/mcb.sh ] || exit 0
echo "→ guard (staged)…"; bash scripts/lib/mcb.sh guard --staged
echo "→ lint…"; make check WHAT=lint
echo "→ validate (quick)…"; make check WHAT=validate QUICK=1
echo "→ staged check…"; make check WHAT=staged
echo "✓ pre-commit passed"
10 changes: 10 additions & 0 deletions scripts/hooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Installed by `make setup WHAT=hooks`. Runs the canonical full gate before
# push, then preserves Beads hook processing when available.
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
[ -f scripts/lib/mcb.sh ] || exit 0
make check WHAT=all
if command -v bd >/dev/null 2>&1; then
exec bd hooks run pre-push "$@"
fi
99 changes: 94 additions & 5 deletions scripts/lib/mcb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,54 @@ mcb_retry() { local n="$1" s="$2"; shift 2; local t=1; while ! "$@"; do [ "$t" -
# --- SSOT readers ------------------------------------------------------------
mcb_version() { grep -m1 '^version =' "$MCB_ROOT/Cargo.toml" | sed 's/.*"\([^"]*\)".*/\1/'; }

mcb_git_hooks_dir() {
local repo="${1:-$MCB_ROOT}"
local common_dir
common_dir="$(git -C "$repo" rev-parse --path-format=absolute --git-common-dir)" \
|| mcb_die "$EX_PREREQ" "nao foi possivel resolver o diretorio Git comum de '$repo'"
printf '%s/hooks\n' "$common_dir"
}

mcb_install_hooks() {
local repo="${1:-$MCB_ROOT}"
local hooks_dir
hooks_dir="$(mcb_git_hooks_dir "$repo")"
mkdir -p "$hooks_dir"
cp "$MCB_ROOT/scripts/hooks/pre-commit" "$MCB_ROOT/scripts/hooks/pre-push" "$hooks_dir/"
chmod +x "$hooks_dir/pre-commit" "$hooks_dir/pre-push"
mcb_ok "pre-commit and pre-push hooks installed at $hooks_dir"
}

mcb_sync_submodules() {
local repo="${1:-$MCB_ROOT}"
local materialized

git -C "$repo" submodule sync --recursive
git -C "$repo" submodule update --init --recursive

while :; do
materialized="$(git -C "$repo" submodule foreach --quiet --recursive '
present="$(git ls-files -z | while IFS= read -r -d "" path; do
if [ -e "$path" ] || [ -L "$path" ]; then
printf 1
break
fi
done)"
[ -n "$present" ] && exit 0
tracked="$(git ls-files | wc -l)"
if [ "$tracked" -eq 0 ]; then
git read-tree HEAD
tracked="$(git ls-files | wc -l)"
fi
[ "$tracked" -eq 0 ] && exit 0
git checkout-index --all
printf "%s\n" "$sm_path"
')"
[ -z "$materialized" ] && break
git -C "$repo" submodule update --init --recursive
done
}

# Binary lookup chain: PATH > target/release > target/debug > cargo run
mcb_bin() {
command -v mcb 2>/dev/null && return 0
Expand All @@ -77,6 +125,38 @@ mcb_validate() { # $1 = "quick" | "full"
# FILES word-split safety (ported from cosmos Makefile:80): refuse shell metachars.
mcb_files_safe() { printf '%s' "${1:-}" | grep -qE '[;|&`$()<>]' && mcb_die "$EX_PREREQ" "FILES contem metacaractere de shell perigoso; liste apenas caminhos"; return 0; }

mcb_check_staged() {
local crate_dir deadline=60 manifest package packages=""
local staged

mcb_require_cmd timeout
staged="$(git -C "$MCB_ROOT" diff --cached --name-only --diff-filter=ACMR)"
[ -n "$staged" ] || { mcb_ok "staged check: no staged paths"; return 0; }

if printf '%s\n' "$staged" | grep -qE '^Cargo\.(toml|lock)$'; then
packages="--workspace"
else
while IFS= read -r path; do
case "$path" in
crates/*/src/*.rs)
crate_dir="$(printf '%s\n' "$path" | cut -d/ -f1-2)"
manifest="$crate_dir/Cargo.toml"
[ -f "$MCB_ROOT/$manifest" ] || continue
package="$(sed -n '/^\[package\]/,/^\[/s/^name = "\([^"]*\)"/\1/p' "$MCB_ROOT/$manifest" | head -1)"
[ -n "$package" ] || mcb_die "$EX_PREREQ" "package name ausente em '$manifest'"
case " $packages " in *" -p $package "*) ;; *) packages="$packages -p $package" ;; esac
;;
esac
done <<< "$staged"
fi

[ -n "$packages" ] || { mcb_ok "staged check: no Rust package affected"; return 0; }
mcb_log "staged check: cargo fmt/clippy scope:$packages (deadline ${deadline}s each)"
timeout --signal=TERM --kill-after=5s "${deadline}s" cargo fmt $packages -- --check
timeout --signal=TERM --kill-after=5s "${deadline}s" cargo clippy $packages --all-targets -- -D warnings
mcb_ok "staged check: clean"
}

# --- banned-pattern guard ----------------------------------------------------
# Scans first-party crates/ for the constructs AGENTS.md forbids in prod paths.
# Excludes: tests, #[cfg(test)] modules, target/. Fails EX_GUARD.
Expand All @@ -94,15 +174,20 @@ mcb_guard() {
[ -z "$src" ] && { mcb_warn "guard: no source files found under crates/"; return 0; }
fi
# 1. unwrap/expect/panic/todo/unimplemented in non-test .rs
hits=$(grep -rnE '\b(unwrap|expect)\(|\bpanic!|\btodo!|\bunimplemented!' $src 2>/dev/null \
| grep -vE '//.*(unwrap|expect)|#\[cfg\(test\)\]' || true)
hits=$(grep -rnE '\.(unwrap|expect)\(|\b(panic|todo|unimplemented)!\(' $src 2>/dev/null \
| grep -vE ':[[:space:]]*(//|///|//!)|#\[cfg\(test\)\]|pub const .*: &str = |\.message\("|message = "|suggestion = "|r".*(unwrap|expect|panic|todo|unimplemented)|line\.contains\("todo!"\)' || true)
[ -n "$hits" ] && { mcb_warn "prod unwrap/expect/panic/todo:"; printf '%s\n' "$hits" >&2; rc=$EX_GUARD; }
# 2. TODO/FIXME markers
hits=$(grep -rnE '\b(TODO|FIXME)\b' $src 2>/dev/null || true)
[ -n "$hits" ] && { mcb_warn "TODO/FIXME markers:"; printf '%s\n' "$hits" >&2; rc=$EX_GUARD; }
# 3. unjustified suppression directives (#[allow(...)] with no trailing // Why:)
hits=$(grep -rnE '#\[allow\(' $src 2>/dev/null | grep -vE '//\s*Why:' || true)
[ -n "$hits" ] && { mcb_warn "#[allow] without // Why: justification:"; printf '%s\n' "$hits" >&2; rc=$EX_GUARD; }
if [ "$staged" = "1" ]; then
hits=$(git -C "$MCB_ROOT" diff --cached --unified=0 -- crates 2>/dev/null \
| grep -E '^\+[^+].*#\[allow\(' | grep -vE '#\[allow\([^]]+\)\][[:space:]]*//[[:space:]]*[^[:space:]]' || true)
else
hits=$(git -C "$MCB_ROOT" diff origin/main...HEAD --unified=0 -- crates 2>/dev/null \
| grep -E '^\+[^+].*#\[allow\(' | grep -vE '#\[allow\([^]]+\)\][[:space:]]*//[[:space:]]*[^[:space:]]' || true)
fi
[ -n "$hits" ] && { mcb_warn "new #[allow] without a trailing rationale:"; printf '%s\n' "$hits" >&2; rc=$EX_GUARD; }
[ "$rc" -eq 0 ] && mcb_ok "guard: clean"
return "$rc"
}
Expand All @@ -127,7 +212,11 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
version) mcb_version ;;
bin) mcb_bin ;;
ignores) printf '%s\n' "${MCB_AUDIT_IGNORES[*]}" ;;
git-hooks-dir) mcb_git_hooks_dir "${2:-$MCB_ROOT}" ;;
install-hooks) mcb_install_hooks "${2:-$MCB_ROOT}" ;;
sync-submodules) mcb_sync_submodules "${2:-$MCB_ROOT}" ;;
validate) mcb_validate "${2:-full}" ;;
check-staged) mcb_check_staged ;;
guard) shift; mcb_guard "$@" ;;
guard-bash) mcb_guard_bash ;;
files-safe) mcb_files_safe "${2:-}" ;;
Expand Down
130 changes: 130 additions & 0 deletions scripts/lib/tests/test-hooks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
FIXTURE="$(mktemp -d)"
trap 'rm -rf "$FIXTURE"' EXIT

PRIMARY="$FIXTURE/primary"
LINKED="$FIXTURE/linked"
SUB_SOURCE="$FIXTURE/sub-source"
SUB_ARCHIVE="$FIXTURE/sub-archive"
BIN="$FIXTURE/bin"
MAKE_LOG="$FIXTURE/make.log"
CARGO_LOG="$FIXTURE/cargo.log"

git init -q "$PRIMARY"
git -C "$PRIMARY" config user.email test@example.com
git -C "$PRIMARY" config user.name "MCB Test"
mkdir -p "$PRIMARY/scripts/hooks" "$PRIMARY/scripts/lib"
cp "$ROOT/scripts/hooks/pre-commit" "$PRIMARY/scripts/hooks/pre-commit"
cp "$ROOT/scripts/hooks/pre-push" "$PRIMARY/scripts/hooks/pre-push"
cp "$ROOT/scripts/lib/mcb.sh" "$PRIMARY/scripts/lib/mcb.sh"
git -C "$PRIMARY" add scripts
git -C "$PRIMARY" commit -q -m initial
git -C "$PRIMARY" worktree add -q -b linked-test "$LINKED"

NON_MCB="$FIXTURE/non-mcb"
git init -q "$NON_MCB"
git -C "$NON_MCB" config user.email test@example.com
git -C "$NON_MCB" config user.name "MCB Test"
git -C "$NON_MCB" commit --allow-empty -q -m initial

PRIMARY_HOOKS="$(bash "$ROOT/scripts/lib/mcb.sh" git-hooks-dir "$PRIMARY")"
LINKED_HOOKS="$(bash "$ROOT/scripts/lib/mcb.sh" git-hooks-dir "$LINKED")"
EXPECTED_HOOKS="$(git -C "$PRIMARY" rev-parse --path-format=absolute --git-common-dir)/hooks"
PRIMARY_GIT_DIR="$(git -C "$PRIMARY" rev-parse --path-format=absolute --git-dir)"
LINKED_GIT_DIR="$(git -C "$LINKED" rev-parse --path-format=absolute --git-dir)"

test "$PRIMARY_HOOKS" = "$EXPECTED_HOOKS"
test "$LINKED_HOOKS" = "$EXPECTED_HOOKS"
test "$PRIMARY_GIT_DIR" != "$LINKED_GIT_DIR"
test -f "$LINKED/.git"

bash "$PRIMARY/scripts/lib/mcb.sh" install-hooks "$LINKED"
cmp "$ROOT/scripts/hooks/pre-commit" "$EXPECTED_HOOKS/pre-commit"
cmp "$ROOT/scripts/hooks/pre-push" "$EXPECTED_HOOKS/pre-push"
test -x "$EXPECTED_HOOKS/pre-commit"
test -x "$EXPECTED_HOOKS/pre-push"
if grep -q 'make boot' "$EXPECTED_HOOKS/pre-commit"; then
printf 'installed pre-commit references removed make boot target\n' >&2
exit 1
fi

mkdir -p "$BIN"
cat > "$BIN/make" <<EOF
#!/usr/bin/env bash
printf '%s|%s\n' "\$PWD" "\$*" >> "$MAKE_LOG"
EOF
chmod +x "$BIN/make"

cat > "$BIN/cargo" <<EOF
#!/usr/bin/env bash
printf '%s\n' "\$*" >> "$CARGO_LOG"
EOF
chmod +x "$BIN/cargo"

cat > "$BIN/timeout" <<'EOF'
#!/usr/bin/env bash
while [ "$#" -gt 0 ]; do
case "$1" in
--signal=*|--kill-after=*|*[smhd]) shift ;;
*) break ;;
esac
done
exec "$@"
EOF
chmod +x "$BIN/timeout"

(cd "$PRIMARY" && PATH="$BIN:$PATH" "$EXPECTED_HOOKS/pre-commit")
(cd "$LINKED" && PATH="$BIN:$PATH" "$EXPECTED_HOOKS/pre-commit")
test "$(grep -c 'check WHAT=staged' "$MAKE_LOG")" -eq 2
if grep -qE 'check WHAT=(lint|validate)' "$MAKE_LOG"; then
printf 'pre-commit invoked an unrelated full-workspace gate\n' >&2
exit 1
fi
grep -q "^$PRIMARY|check WHAT=staged$" "$MAKE_LOG"
grep -q "^$LINKED|check WHAT=staged$" "$MAKE_LOG"

: > "$MAKE_LOG"
(cd "$PRIMARY" && PATH="$BIN:$PATH" "$EXPECTED_HOOKS/pre-push")
grep -q "^$PRIMARY|check WHAT=all$" "$MAKE_LOG"

mkdir -p "$PRIMARY/crates/sample/src"
cat > "$PRIMARY/crates/sample/Cargo.toml" <<'EOF'
[package]
name = "sample"
version = "0.1.0"
EOF
printf 'pub fn staged() {}\n' > "$PRIMARY/crates/sample/src/lib.rs"
git -C "$PRIMARY" add crates/sample
(cd "$PRIMARY" && PATH="$BIN:$PATH" bash scripts/lib/mcb.sh check-staged)
grep -q '^fmt -p sample -- --check$' "$CARGO_LOG"
grep -q '^clippy -p sample --all-targets -- -D warnings$' "$CARGO_LOG"
if grep -q -- '--workspace' "$CARGO_LOG"; then
printf 'staged crate check expanded to unrelated workspace scope\n' >&2
exit 1
fi

git init -q "$SUB_SOURCE"
git -C "$SUB_SOURCE" config user.email test@example.com
git -C "$SUB_SOURCE" config user.name "MCB Test"
printf '[package]\nname = "fixture"\nversion = "0.1.0"\n' > "$SUB_SOURCE/Cargo.toml"
git -C "$SUB_SOURCE" add Cargo.toml
git -C "$SUB_SOURCE" commit -q -m initial
git -C "$PRIMARY" -c protocol.file.allow=always submodule add -q "$SUB_SOURCE" vendor/sample
PATH="$BIN:$PATH" git -C "$PRIMARY" commit -q -am 'add fixture submodule'

mkdir -p "$SUB_ARCHIVE"
mv "$PRIMARY/vendor/sample/Cargo.toml" "$SUB_ARCHIVE/Cargo.toml"
git -C "$PRIMARY/vendor/sample" read-tree --empty
test ! -f "$PRIMARY/vendor/sample/Cargo.toml"
test "$(git -C "$PRIMARY/vendor/sample" ls-files | wc -l)" -eq 0
bash "$PRIMARY/scripts/lib/mcb.sh" sync-submodules "$PRIMARY"
test -f "$PRIMARY/vendor/sample/Cargo.toml"

printf 'preserved local content\n' > "$PRIMARY/vendor/sample/Cargo.toml"
bash "$PRIMARY/scripts/lib/mcb.sh" sync-submodules "$PRIMARY"
grep -q '^preserved local content$' "$PRIMARY/vendor/sample/Cargo.toml"

printf 'hook fixtures: primary and linked worktree install and commit gates passed via %s\n' "$EXPECTED_HOOKS"
Loading