feat(hooks): CHANGE GATE — prod remote ops require .crush/active-cr [#767]
Q3 ruling 2026-09-04: Tier 2 of the t/325 ladder is mechanical. Prod- target remote.sh/remote-dns.sh invocations block without a filed GLPI Change id; dev lanes (sectestbed/preprod/test/tsys5/sandbox/kali) exempt; CR tooling exempt (chicken-and-egg). 7-case matrix green, shellcheck clean. https://projects.knownelement.com/issues/767#note-4191
This commit is contained in:
+49
-5
@@ -41,6 +41,10 @@ if [ "$TOOL" = "bash" ]; then
|
|||||||
case "$CMD" in
|
case "$CMD" in
|
||||||
*active-ticket*) exit 0 ;;
|
*active-ticket*) exit 0 ;;
|
||||||
esac
|
esac
|
||||||
|
# Filing/managing GLPI CRs (chicken-and-egg: CR tooling must always run)
|
||||||
|
case "$CMD" in
|
||||||
|
*active-cr*|*"glpi-change"*) exit 0 ;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For edit/write: exempt policy/hook files (these ARE the policy)
|
# For edit/write: exempt policy/hook files (these ARE the policy)
|
||||||
@@ -64,10 +68,8 @@ for f in "$CRUSH_PROJECT_DIR"/.crush/active-ticket*; do
|
|||||||
GATE_OK=1
|
GATE_OK=1
|
||||||
printf '{"context":"Active ticket(s): %s -> %s"}\n' "$(basename "$f")" "$(cat "$f")"
|
printf '{"context":"Active ticket(s): %s -> %s"}\n' "$(basename "$f")" "$(cat "$f")"
|
||||||
done
|
done
|
||||||
[ "$GATE_OK" -eq 1 ] && exit 0
|
if [ "$GATE_OK" -ne 1 ]; then
|
||||||
|
cat >&2 <<'MSG'
|
||||||
# No active ticket — block
|
|
||||||
cat >&2 <<'MSG'
|
|
||||||
TICKET GATE: No active ticket set.
|
TICKET GATE: No active ticket set.
|
||||||
|
|
||||||
This project requires ticket-governed work (AGENTS.md Agent Authority).
|
This project requires ticket-governed work (AGENTS.md Agent Authority).
|
||||||
@@ -80,4 +82,46 @@ Clear the ticket when work is complete:
|
|||||||
|
|
||||||
> .crush/active-ticket
|
> .crush/active-ticket
|
||||||
MSG
|
MSG
|
||||||
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 is closed: > .crush/active-cr)
|
||||||
|
# Dev-lane targets are exempt (sectestbed/preprod/test/sandbox = Tier 0/1).
|
||||||
|
# File a CR in one line (tooling lives in KNEL/inventory):
|
||||||
|
# echo "why/what/where" | scripts/glpi-change.sh create --agent --title "[#NNN] summary"
|
||||||
|
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_OK=0
|
||||||
|
for f in "$CRUSH_PROJECT_DIR"/.crush/active-cr*; do
|
||||||
|
[ -f "$f" ] && [ -s "$f" ] || continue
|
||||||
|
CR_OK=1
|
||||||
|
printf '{"context":"Active CR: %s -> %s"}\n' "$(basename "$f")" "$(cat "$f")"
|
||||||
|
done
|
||||||
|
if [ "$CR_OK" -ne 1 ]; then
|
||||||
|
cat >&2 <<'MSG'
|
||||||
|
CHANGE GATE: prod-target remote operation requires a filed GLPI Change.
|
||||||
|
|
||||||
|
File one, then set its id (Tier 2 of the t/325 escalation ladder):
|
||||||
|
|
||||||
|
echo "what/why/where" | scripts/glpi-change.sh create --agent --title "[#NNN] summary"
|
||||||
|
echo '<change-id>' > .crush/active-cr
|
||||||
|
|
||||||
|
Dev-lane targets (sectestbed/preprod/test/tsys5) are exempt.
|
||||||
|
Clear when the CR closes: > .crush/active-cr
|
||||||
|
MSG
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user