feat(hooks): CHANGE GATE — prod remote ops require .crush/active-cr [#767]

Port of the PFVCluster gate to the global PreToolUse copy (all lanes):
prod-target remote.sh/remote-dns.sh invocations block without a filed
GLPI Change id (.crush/active-cr); dev-lane targets exempt; CR tooling
exempt. JSON error payload per house style. Functionally verified.

https://projects.knownelement.com/issues/767#note-4191
This commit is contained in:
2026-09-04 07:17:01 -05:00
parent 7e37745538
commit e7ed31b4e1
+34 -5
View File
@@ -37,6 +37,7 @@ if [ "$TOOL" = "bash" ]; then
*"check-rules"*|*"setup-hooks"*|*"shellcheck"*|*"run-tests"*|*"promote.sh"*) exit 0 ;;
*"tailscale status"*|*"access-matrix"*|*"docker ps"*|*"docker logs"*|*"docker inspect"*) exit 0 ;;
*active-ticket*) exit 0 ;;
*active-cr*|*"glpi-change"*) exit 0 ;;
esac
fi
@@ -52,10 +53,38 @@ TICKET_FILE="$REPO_ROOT/.crush/active-ticket"
if [ -f "$TICKET_FILE" ] && [ -s "$TICKET_FILE" ]; then
TICKET="$(tr -d '\n' < "$TICKET_FILE")"
printf '{"context":"Active ticket: %s"}\n' "$TICKET"
exit 0
fi
cat >&2 <<'EOF'
else
cat >&2 <<'EOF'
{"error":{"message":"TICKET GATE: no active ticket in this repo. Set one first: echo '#NNN' > .crush/active-ticket (create the ticket in Redmine first if none exists). Clear with: > .crush/active-ticket"}}
EOF
exit 2
exit 2
fi
# CHANGE GATE [#767] (t/325 §5 ladder; Q3 ruling 2026-09-04): prod-target
# remote operations additionally require a filed GLPI Change — its id in
# .crush/active-cr (clear when the CR closes: > .crush/active-cr)
# Dev-lane targets are exempt (sectestbed/preprod/test/sandbox = Tier 0/1).
# CR tooling: KNEL/inventory scripts/glpi-change.sh (create --agent).
if [ "$TOOL" = "bash" ]; then
case "$CMD" in
*"remote.sh vm-file"*|*"remote.sh prox-file"*|*"remote.sh vm-copy"*|*"remote.sh prox-copy"*|*"remote.sh vm"*|*"remote.sh prox"*|*"remote-dns.sh "*)
PROD=1
case "$CMD" in
*sectestbed*|*preprod*|*glpi-test*|*kali*|*tsys5*|*sandbox*) PROD=0 ;;
esac
if [ "$PROD" -eq 1 ]; then
CR_FILE="$REPO_ROOT/.crush/active-cr"
if [ -f "$CR_FILE" ] && [ -s "$CR_FILE" ]; then
printf '{"context":"Active CR: %s"}\n' "$(tr -d '\n' < "$CR_FILE")"
else
cat >&2 <<'EOF'
{"error":{"message":"CHANGE GATE: prod-target remote operation requires a filed GLPI Change. File one: echo 'what/why/where' | scripts/glpi-change.sh create --agent --title '[#NNN] summary' — then: echo '<change-id>' > .crush/active-cr. Dev-lane targets (sectestbed/preprod/test/tsys5) are exempt. Clear with: > .crush/active-cr"}}
EOF
exit 2
fi
fi
;;
esac
fi
exit 0