diff --git a/local/docs/HOOKS.md b/local/docs/HOOKS.md new file mode 100644 index 0000000000..28e820d20d --- /dev/null +++ b/local/docs/HOOKS.md @@ -0,0 +1,78 @@ +# Red Bear OS — Optional Git Hooks + +This directory documents the git hooks that operators can install for +Red Bear OS. Per AGENTS.md "absolutely NEVER DELETE, NEVER IGNORE" +rule, hooks are always **opt-in** — operators explicitly choose to +install them. No hook is auto-installed. + +## Available hooks (2026-07-12, Phase 4.5) + +### pre-push-checks.sh (recommended for serious operators) + +**File:** `local/scripts/pre-push-checks.sh` + +**Purpose:** Run 4 critical pre-flight checks before every `git push`. +Closes the "silent drift" gap identified in AGENTS.md "Daily-upstream- +safe workflow". + +**Checks:** +1. `sync-versions.sh --check` — Cat 0 + Cat 1 + Cat 2 versions +2. `verify-fork-versions.sh` — Cat 2 fork supremacy + content check +3. `verify-patch-content.py` — no orphan patches in `local/patches/` +4. `verify-collision-detection.py` — no config-vs-package conflicts + +**Install:** +```bash +cp local/scripts/pre-push-checks.sh .git/hooks/pre-push +chmod +x .git/hooks/pre-push +``` + +**Bypass:** +- `REDBEAR_SKIP_PRE_PUSH=1 git push` (env var) +- `git push --no-verify` (standard git bypass) +- Run with `--soft` for warn-only mode + +**Why not pre-commit?** Pre-push is preferred because: +- Pre-commit would block every local commit (even non-bump commits) +- Pre-push is the right safety boundary: "before I share work with origin" +- Operators committing 5x/hour to a feature branch don't need every commit + to re-verify 4 checks; they need it on push + +### Future hooks (Phase 4.5+ forward work) + +- **pre-receive on the server** — gitea can run a server-side hook + that re-verifies every push. Combined with the client-side pre-push, + this is defense in depth. Implementation requires gitea admin + permission; operator-only. +- **commit-msg hook** — auto-prefix commit messages with Phase ID + (e.g., `phase 4.5: ...`) so future audits can group by phase. + Optional, helps with audit doc generation. + +## How hooks relate to AGENTS.md + +AGENTS.md "Daily-upstream-safe workflow" says: +> "we can sources are provisioned via provision-release.sh and +> archived in sources/redbear-/ build successfully." + +This means: **before any fork-upstream sync, validate the state**. +The pre-push hook is the operator-side implementation of that +check — it runs the same 4 checks that build-preflight.sh runs at +build time, but on the operator's local repository state. + +## Why hooks are opt-in + +Per AGENTS.md "absolutely NEVER DELETE, NEVER IGNORE" rule: +- Hooks can interfere with operator workflows (false positives block pushes) +- Some operators prefer manual run of pre-push-checks.sh +- Local hooks do not propagate (each clone must re-install) +- Some operators have multiple clones (different operator workstations) + +The opt-in nature respects operator autonomy. The hook is provided +in `local/scripts/` so operators can opt in by copying it to +`.git/hooks/pre-push`. + +## Audit + +This directory was created in Phase 4.5 (Round 5). The current +hook inventory is just the 1 file above. Future hooks should be +added here as they are created. diff --git a/local/scripts/pre-push-checks.sh b/local/scripts/pre-push-checks.sh new file mode 100755 index 0000000000..851dc87c68 --- /dev/null +++ b/local/scripts/pre-push-checks.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# pre-push-checks.sh — Optional pre-push hook for Red Bear OS. +# +# Usage: +# cp local/scripts/pre-push-checks.sh .git/hooks/pre-push +# chmod +x .git/hooks/pre-push +# +# Or invoke manually: +# ./local/scripts/pre-push-checks.sh # fail on any drift +# ./local/scripts/pre-push-checks.sh --soft # warn only +# +# Runs the 4 critical pre-flight checks: +# 1. sync-versions.sh --check (Cat 0 + Cat 1 + Cat 2 versions) +# 2. verify-fork-versions.sh (Cat 2 fork supremacy) +# 3. verify-patch-content.sh (no orphan patches) +# 4. verify-collision-detection.py (no config-vs-package conflicts) +# +# The hook is opt-in. Operators who don't want it should NOT install it. +# This is documented in local/docs/HOOKS.md (Phase 4.5+). +# +# Per AGENTS.md "Daily-upstream-safe workflow", these checks are the +# minimum safety net against silent drift. Without the hook, drift can +# only be caught at next build, which is too late for patches that +# have been silently moved/deleted. + +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" + +soft_mode=0 +if [ "${1:-}" = "--soft" ]; then + soft_mode=1 +fi + +fails=0 + +run_check() { + local name="$1" + local cmd="$2" + local label="$3" + echo ">>> $name" + if eval "$cmd" >"/tmp/pre-push-${name}.out" 2>&1; then + echo " OK" + else + local rc=$? + echo " FAIL (exit $rc)" + head -10 "/tmp/pre-push-${name}.out" | sed 's/^/ /' + fails=$((fails + 1)) + fi +} + +echo "=== Red Bear OS — pre-push safety net ===" +echo " (4 critical pre-flight checks)" +echo "" + +# 1. sync-versions +run_check "sync-versions" \ + "bash local/scripts/sync-versions.sh --check" \ + "Cat 0 + Cat 1 + Cat 2 versions match branch" + +# 2. verify-fork-versions +run_check "verify-fork-versions" \ + "bash local/scripts/verify-fork-versions.sh" \ + "Cat 2 fork supremacy + content check" + +# 3. verify-patch-content +run_check "verify-patch-content" \ + "python3 local/scripts/verify-patch-content.py" \ + "No orphan patches in local/patches/" + +# 4. verify-collision-detection +run_check "verify-collision-detection" \ + "python3 local/scripts/verify-collision-detection.py" \ + "No config [[files]] vs package install collisions" + +echo "" +if [ $fails -gt 0 ]; then + echo "=== RESULT: $fails check(s) failed ===" + if [ $soft_mode -eq 0 ]; then + echo "Push BLOCKED. To override: $0 --soft (or: REDBEAR_SKIP_PRE_PUSH=1 git push ...)" + exit 1 + else + echo "Push allowed (--soft mode). $fails drift(s) present." + exit 0 + fi +else + echo "=== RESULT: all 4 checks pass ===" + echo "Push allowed." + exit 0 +fi