Menu
Public repository / 8d41f1e10aceed387d425b43038f2070e399a349
AkurAI-Build / scripts/test-pre-receive.sh
Latest change cd8019fddc46769e797dc54194decfd9d4a98f2d - OLI-270: branch protection — rules per branch, pre-receive check, merge gate by Óli
#!/usr/bin/env bash
# The pre-receive hook asks the forge per ref and rejects what the forge rejects, fails closed
# when the forge is unreachable, and does nothing when it runs outside the forge (no env).
set -euo pipefail
here="$(cd "$(dirname "$0")/.." && pwd)"
tmp="$(mktemp -d)"; trap 'kill "${srv:-0}" 2>/dev/null || true; rm -rf "$tmp"' EXIT
fail() { echo "FAIL: $*" >&2; exit 1; }
repo="$tmp/repo"; git init -q "$repo"; git -C "$repo" config user.email t@x; git -C "$repo" config user.name t
git -C "$repo" commit -q --allow-empty -m one; a=$(git -C "$repo" rev-parse HEAD)
git -C "$repo" commit -q --allow-empty -m two; b=$(git -C "$repo" rev-parse HEAD)
hook="$here/deploy/hooks/pre-receive"
cat > "$tmp/forge.py" <<'PY'
import json, sys
from http.server import BaseHTTPRequestHandler, HTTPServer
class H(BaseHTTPRequestHandler):
def log_message(self, *a): pass
def do_POST(self):
n = int(self.headers.get("content-length", 0)); body = json.loads(self.rfile.read(n))
if self.headers.get("authorization") != "Bearer tok":
self.send_response(401); self.end_headers(); return
with open(sys.argv[2], "a") as f: f.write(json.dumps(body) + "\n")
if body["reference"] == "refs/heads/main" and not body["fast_forward"]:
out = {"allowed": False, "reason": "branch main is protected: force-push is not allowed"}
else:
out = {"allowed": True, "reason": "ok"}
data = json.dumps(out).encode()
self.send_response(200); self.send_header("content-type", "application/json"); self.send_header("content-length", str(len(data))); self.end_headers(); self.wfile.write(data)
HTTPServer(("127.0.0.1", int(sys.argv[1])), H).serve_forever()
PY
port=$((20000 + RANDOM % 20000))
python3 "$tmp/forge.py" "$port" "$tmp/seen" & srv=$!
sleep 1
env_ok=(AKURAI_FORGE_URL="http://127.0.0.1:$port" AKURAI_FORGE_TOKEN=tok AKURAI_FORGE_REPO=demo)
# fast-forward on main: allowed; the hook computed fast_forward=true with git
printf '%s %s refs/heads/main\n' "$a" "$b" | (cd "$repo" && env "${env_ok[@]}" "$hook") || fail "fast-forward rejected"
grep -q '"fast_forward": true' "$tmp/seen" || fail "fast_forward not reported true"
# non fast-forward (b -> a) on main: rejected with the forge's reason
out=$(printf '%s %s refs/heads/main\n' "$b" "$a" | (cd "$repo" && env "${env_ok[@]}" "$hook" 2>&1) && fail "force-push accepted" || true)
echo "$out" | grep -q 'force-push is not allowed' || fail "reason not shown: $out"
# other branches pass even when not fast-forward
printf '%s %s refs/heads/topic\n' "$b" "$a" | (cd "$repo" && env "${env_ok[@]}" "$hook") || fail "topic rejected"
# wrong token: fails closed
if printf '%s %s refs/heads/topic\n' "$a" "$b" | (cd "$repo" && env AKURAI_FORGE_URL="http://127.0.0.1:$port" AKURAI_FORGE_TOKEN=bad AKURAI_FORGE_REPO=demo "$hook" 2>/dev/null); then fail "bad token accepted"; fi
# forge down: fails closed
if printf '%s %s refs/heads/topic\n' "$a" "$b" | (cd "$repo" && env AKURAI_FORGE_URL="http://127.0.0.1:1" AKURAI_FORGE_TOKEN=tok AKURAI_FORGE_REPO=demo "$hook" 2>/dev/null); then fail "unreachable forge accepted"; fi
# no env (local push): nothing checked
printf '%s %s refs/heads/main\n' "$b" "$a" | (cd "$repo" && "$hook") || fail "local push blocked"
echo ok