phase 4.5: add pre-push-checks.sh opt-in hook + HOOKS doc
Per AGENTS.md 'Daily-upstream-safe workflow', drift between fork state and active patch system can only be caught at next-build time. This commit closes the gap by providing a pre-push hook that runs the 4 critical pre-flight checks BEFORE pushing to origin. The hook runs (in order): 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.py (no orphan patches) 4. verify-collision-detection.py (no config-vs-package conflicts) Per AGENTS.md 'absolutely NEVER DELETE, NEVER IGNORE' rule, the hook is OPT-IN: operators must explicitly install it via cp local/scripts/pre-push-checks.sh .git/hooks/pre-push chmod +x .git/hooks/pre-push The opt-in nature respects operator autonomy — local hooks do not propagate (each clone must re-install), and false positives would block legitimate pushes. HOOKS.md documents the available hooks + future work (pre-receive on server side for defense in depth; commit-msg hook for auto-phase prefix in commit messages). Default mode of the script: fail on any drift (exit 1). Use --soft flag or REDBEAR_SKIP_PRE_PUSH=1 to bypass.
This commit is contained in:
@@ -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-<release>/ 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.
|
||||
Executable
+91
@@ -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
|
||||
Reference in New Issue
Block a user