agent-relay-plugin 0.4.12 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hooks/hooks.json +0 -22
- package/package.json +1 -1
- package/hooks/approval-gate.sh +0 -131
package/hooks/hooks.json
CHANGED
|
@@ -1,27 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
|
-
"PreToolUse": [
|
|
4
|
-
{
|
|
5
|
-
"hooks": [
|
|
6
|
-
{
|
|
7
|
-
"type": "command",
|
|
8
|
-
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/approval-gate.sh\"",
|
|
9
|
-
"timeout": 5
|
|
10
|
-
}
|
|
11
|
-
]
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
"PermissionDenied": [
|
|
15
|
-
{
|
|
16
|
-
"hooks": [
|
|
17
|
-
{
|
|
18
|
-
"type": "command",
|
|
19
|
-
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/approval-gate.sh\"",
|
|
20
|
-
"timeout": 5
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
3
|
"UserPromptSubmit": [
|
|
26
4
|
{
|
|
27
5
|
"hooks": [
|
package/package.json
CHANGED
package/hooks/approval-gate.sh
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Agent Relay plugin — approval gate for PreToolUse and PermissionDenied hooks.
|
|
3
|
-
# Enforces AGENT_RELAY_APPROVAL policy: open (default), guarded, read-only.
|
|
4
|
-
|
|
5
|
-
MODE="${AGENT_RELAY_APPROVAL:-open}"
|
|
6
|
-
[ "$MODE" = "open" ] && exit 0
|
|
7
|
-
|
|
8
|
-
input=$(cat)
|
|
9
|
-
event=$(printf '%s' "$input" | jq -r '.hook_event_name')
|
|
10
|
-
|
|
11
|
-
# --- PermissionDenied: allow retry so the model adapts ---
|
|
12
|
-
if [ "$event" = "PermissionDenied" ]; then
|
|
13
|
-
jq -n '{hookSpecificOutput:{hookEventName:"PermissionDenied",retry:true}}'
|
|
14
|
-
exit 0
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
tool=$(printf '%s' "$input" | jq -r '.tool_name')
|
|
18
|
-
|
|
19
|
-
# --- Always allowed: read-only and orchestration tools ---
|
|
20
|
-
case "$tool" in
|
|
21
|
-
Read|Grep|Glob|WebFetch|WebSearch|Agent|Monitor|ToolSearch|AskUserQuestion|Skill|ScheduleWakeup|CronList|EnterPlanMode|ExitPlanMode)
|
|
22
|
-
exit 0 ;;
|
|
23
|
-
Task*|*McpResource*)
|
|
24
|
-
exit 0 ;;
|
|
25
|
-
mcp__*)
|
|
26
|
-
exit 0 ;;
|
|
27
|
-
esac
|
|
28
|
-
|
|
29
|
-
deny() {
|
|
30
|
-
jq -n --arg r "$1" '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}'
|
|
31
|
-
exit 0
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
# --- read-only: deny mutation tools ---
|
|
35
|
-
if [ "$MODE" = "read-only" ]; then
|
|
36
|
-
case "$tool" in
|
|
37
|
-
Write|Edit|NotebookEdit|CronCreate|CronDelete|PushNotification|RemoteTrigger|EnterWorktree|ExitWorktree)
|
|
38
|
-
deny "${tool} blocked by read-only policy" ;;
|
|
39
|
-
esac
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
# --- Bash command analysis ---
|
|
43
|
-
if [ "$tool" = "Bash" ]; then
|
|
44
|
-
cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // ""')
|
|
45
|
-
|
|
46
|
-
if [ "$MODE" = "guarded" ]; then
|
|
47
|
-
# Denylist: block destructive patterns anywhere in the command
|
|
48
|
-
if printf '%s' "$cmd" | grep -qE '(^|[;&|]\s*)\s*(rm|rmdir)\b'; then
|
|
49
|
-
deny "rm/rmdir blocked by guarded policy"
|
|
50
|
-
fi
|
|
51
|
-
if printf '%s' "$cmd" | grep -qE '(^|[;&|]\s*)\s*mv\b'; then
|
|
52
|
-
deny "mv blocked by guarded policy (use cp instead)"
|
|
53
|
-
fi
|
|
54
|
-
if printf '%s' "$cmd" | grep -qE '(^|[;&|]\s*)\s*(chmod|chown|chattr)\b'; then
|
|
55
|
-
deny "Permission change blocked by guarded policy"
|
|
56
|
-
fi
|
|
57
|
-
if printf '%s' "$cmd" | grep -qE '(^|[;&|]\s*)\s*(kill|pkill|killall)\b'; then
|
|
58
|
-
deny "Process signal blocked by guarded policy"
|
|
59
|
-
fi
|
|
60
|
-
if printf '%s' "$cmd" | grep -qE '(^|[;&|]\s*)\s*(dd|mkfs|truncate|shred)\b'; then
|
|
61
|
-
deny "Destructive command blocked by guarded policy"
|
|
62
|
-
fi
|
|
63
|
-
if printf '%s' "$cmd" | grep -qE '(^|[;&|]\s*)\s*sudo\b'; then
|
|
64
|
-
deny "sudo blocked by guarded policy"
|
|
65
|
-
fi
|
|
66
|
-
if printf '%s' "$cmd" | grep -qE 'git\s+(reset\s+--hard|push\s+.*(-f\b|--force)|clean\s+-[a-z]*f)'; then
|
|
67
|
-
deny "Destructive git operation blocked by guarded policy"
|
|
68
|
-
fi
|
|
69
|
-
exit 0
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
if [ "$MODE" = "read-only" ]; then
|
|
73
|
-
# Check for file-writing redirects (allow >/dev/null and fd redirects like 2>&1)
|
|
74
|
-
redirect_cleaned=$(printf '%s' "$cmd" | sed 's|[0-9]*>/dev/null||g; s|[0-9]*>&[0-9]*||g')
|
|
75
|
-
if printf '%s' "$redirect_cleaned" | grep -qE '>>|[^a-zA-Z0-9_]>|^>'; then
|
|
76
|
-
deny "Output redirection blocked by read-only policy"
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
# Allowlist: check first command word
|
|
80
|
-
first_word=$(printf '%s' "$cmd" | sed 's/^[[:space:]]*//' | awk '{print $1}')
|
|
81
|
-
|
|
82
|
-
case "$first_word" in
|
|
83
|
-
# Filesystem reads
|
|
84
|
-
ls|cat|head|tail|less|more|file|stat|tree|du|df|readlink|realpath|basename|dirname)
|
|
85
|
-
exit 0 ;;
|
|
86
|
-
# Text processing
|
|
87
|
-
wc|sort|uniq|diff|comm|tr|cut|paste|column|fmt|fold|tac|rev|nl|seq|xargs)
|
|
88
|
-
exit 0 ;;
|
|
89
|
-
# Search
|
|
90
|
-
find|fd|grep|egrep|fgrep|rg|ag|ast-grep)
|
|
91
|
-
exit 0 ;;
|
|
92
|
-
# Shell builtins / info
|
|
93
|
-
echo|printf|pwd|which|whoami|date|env|printenv|uname|id|hostname|type|true|false|test|\[)
|
|
94
|
-
exit 0 ;;
|
|
95
|
-
# System info
|
|
96
|
-
ps|top|htop|uptime|free|lsof|netstat|ss|ip|ifconfig)
|
|
97
|
-
exit 0 ;;
|
|
98
|
-
# Data processing
|
|
99
|
-
jq|yq|bc|expr|base64|xxd|hexdump|od|strings|md5sum|sha256sum|sha1sum|shasum)
|
|
100
|
-
exit 0 ;;
|
|
101
|
-
# Network reads
|
|
102
|
-
curl|wget|dig|nslookup|ping|traceroute|ssh)
|
|
103
|
-
exit 0 ;;
|
|
104
|
-
# Git — subcommand check
|
|
105
|
-
git)
|
|
106
|
-
git_sub=$(printf '%s' "$cmd" | sed 's/^[[:space:]]*git[[:space:]]*//' | awk '{print $1}')
|
|
107
|
-
case "$git_sub" in
|
|
108
|
-
status|log|diff|show|branch|remote|tag|rev-parse|config|shortlog|reflog|blame|describe|ls-files|ls-tree|cat-file|rev-list|for-each-ref|name-rev|merge-base|version)
|
|
109
|
-
exit 0 ;;
|
|
110
|
-
stash)
|
|
111
|
-
stash_action=$(printf '%s' "$cmd" | sed 's/.*stash[[:space:]]*//' | awk '{print $1}')
|
|
112
|
-
case "$stash_action" in
|
|
113
|
-
list|show|"") exit 0 ;;
|
|
114
|
-
*) deny "git stash ${stash_action} blocked by read-only policy" ;;
|
|
115
|
-
esac ;;
|
|
116
|
-
*)
|
|
117
|
-
deny "git ${git_sub} blocked by read-only policy" ;;
|
|
118
|
-
esac ;;
|
|
119
|
-
# Everything else denied
|
|
120
|
-
*)
|
|
121
|
-
deny "Command '${first_word}' not in read-only allowlist" ;;
|
|
122
|
-
esac
|
|
123
|
-
fi
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
# Unknown tools: guarded → allow, read-only → deny
|
|
127
|
-
if [ "$MODE" = "read-only" ]; then
|
|
128
|
-
deny "${tool} not in read-only allowlist"
|
|
129
|
-
fi
|
|
130
|
-
|
|
131
|
-
exit 0
|