55 lines
3.1 KiB
Bash
55 lines
3.1 KiB
Bash
#!/bin/bash
|
|||
|
|
# Claude Code PreToolUse hook for Bash (wired in via claude-settings.json):
|
||
|
|
# commands that destroy things (containers, VMs, pools, disks, root-level
|
||
|
|
# folders, cluster members…) get permissionDecision "ask", so Claude has to get
|
||
|
|
# your OK even in auto mode (devdesk#27). It never blocks and never allows on
|
||
|
|
# its own; anything else passes through untouched.
|
||
|
|
#
|
||
|
|
# DEVDESK_GUARD=0 in /etc/devdesk/env.local turns it off. Extra rules go in
|
||
|
|
# /etc/devdesk/guard.local, one per line: an extended regex, a tab, a reason.
|
||
|
|
|
||
|
|
# shellcheck source=libexec/devdesk-lib.sh
|
||
|
|
. "${DEVDESK_LIBEXEC:-/usr/lib/devdesk}/devdesk-lib.sh" 2>/dev/null || exit 0
|
||
|
|
[ "${DEVDESK_GUARD:-1}" != 0 ] || exit 0
|
||
|
|
|
||
|
|
command=$(jq -rM '.tool_input.command // empty' 2>/dev/null) || exit 0
|
||
|
|
[ -n "$command" ] || exit 0
|
||
|
|
|
||
|
|
# Built-in rules: extended regex <TAB> reason.
|
||
|
|
rules=$(
|
||
|
|
cat <<'RULES'
|
||
|
|
\bpct[[:space:]]+destroy\b destroys a Proxmox container
|
||
|
|
\bqm[[:space:]]+destroy\b destroys a Proxmox VM
|
||
|
|
\bpvecm[[:space:]]+delnode\b removes a node from the Proxmox cluster
|
||
|
|
\bpveceph[[:space:]]+(osd|pool|mon|mgr|mds|fs)[[:space:]]+destroy\b destroys Ceph components
|
||
|
|
\bceph[[:space:]]+osd[[:space:]]+(purge|destroy|rm|out)\b removes or takes out a Ceph OSD
|
||
|
|
\bceph[[:space:]]+osd[[:space:]]+pool[[:space:]]+(delete|rm)\b deletes a Ceph pool
|
||
|
|
\bceph[[:space:]]+(fs[[:space:]]+rm|mon[[:space:]]+remove|auth[[:space:]]+del)\b removes Ceph components
|
||
|
|
\brbd[[:space:]]+(rm|remove|purge)\b deletes RBD images
|
||
|
|
\bzfs[[:space:]]+destroy\b destroys a ZFS dataset or snapshot
|
||
|
|
\bzpool[[:space:]]+(destroy|labelclear)\b destroys a ZFS pool
|
||
|
|
\b(lvremove|vgremove|pvremove|wipefs|shred)\b wipes volumes or disks
|
||
|
|
\bmkfs(\.[a-z0-9]+)?\b formats a filesystem
|
||
|
|
\bsgdisk[[:space:]]+(-[a-zA-Z]*Z|--zap) wipes a partition table
|
||
|
|
\bdd\b[^|;&]*\bof=/dev/ writes raw to a device
|
||
|
|
\brm[[:space:]]+(-[^[:space:]]*[[:space:]]+)*-[^[:space:]]*[rR][^[:space:]]*[[:space:]]+(-[^[:space:]]*[[:space:]]+)*['"]?/([a-z0-9_.*-]+/?)?['"]?([[:space:];&|)]|$) recursively deletes / or a top-level folder
|
||
|
|
\bgit[[:space:]]+push\b[^|;&]*([[:space:]]-f\b|--force) force-pushes (rewrites remote history)
|
||
|
|
\b(DROP[[:space:]]+(DATABASE|SCHEMA|TABLE)|TRUNCATE[[:space:]]+TABLE)\b drops database objects
|
||
|
|
\bsystemctl[[:space:]]+(stop|restart|kill|disable|mask)[[:space:]]+devdesk-tmux ends every DevDesk session
|
||
|
|
(^|[;&|][[:space:]]*|\bssh[[:space:]]+[^[:space:]]+[[:space:]]+['"]?|\bsystemctl[[:space:]]+)(reboot|poweroff|halt|shutdown)\b reboots or shuts down a machine
|
||
|
|
\bkubectl[[:space:]]+delete\b deletes Kubernetes resources
|
||
|
|
\bdocker[[:space:]]+(system[[:space:]]+prune|volume[[:space:]]+(rm|prune))\b deletes Docker data
|
||
|
|
RULES
|
||
|
|
cat "${DEVDESK_GUARD_LOCAL:-/etc/devdesk/guard.local}" 2>/dev/null
|
||
|
|
)
|
||
|
|
|
||
|
|
while IFS=$'\t' read -r pattern reason; do
|
||
|
|
if [ -z "$pattern" ] || [ "${pattern:0:1}" = "#" ]; then continue; fi
|
||
|
|
if grep -Eiq -- "$pattern" <<<"$command" 2>/dev/null; then
|
||
|
|
jq -cMn --arg r "DevDesk guard: this command ${reason:-matches a rule in guard.local}. Confirm before it runs." \
|
||
|
|
'{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "ask", permissionDecisionReason: $r}}'
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
done <<<"$rules"
|
||
|
|
exit 0
|