fix(s03): match Windows del as a command word

This commit is contained in:
mameikagou
2026-08-26 00:18:53 +08:00
parent 04486201fc
commit 44e33d0ec3
55 changed files with 866 additions and 331 deletions

View File

@@ -102,12 +102,26 @@ agent_loop(history)
**PreToolUse / PostToolUse**、ツール実行の前後のフック。s03 の権限チェックロジックは PreToolUse フックに包まれ、さらにログフックと大出力リマインダーが追加される:
```python
import re
DESTRUCTIVE_COMMAND_WORD = re.compile(
r"(?i)(?:^|[;&|()\n])\s*(?:rm|del)(?=\s|$|[;&|()])"
)
def contains_destructive_command(command: str) -> bool:
return bool(DESTRUCTIVE_COMMAND_WORD.search(command))
# PreToolUse: 権限チェックs03 のロジック、ループからフックに移動)
def permission_hook(block):
if block.name == "bash":
command = block.input.get("command", "")
for pattern in DENY_LIST:
if pattern in block.input.get("command", ""):
if pattern in command:
return "Permission denied by deny list"
if contains_destructive_command(command):
return "Potentially destructive command"
if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):
@@ -130,6 +144,8 @@ register_hook("PreToolUse", log_hook)
register_hook("PostToolUse", large_output_hook)
```
継承された shell rule は大文字小文字を区別せず、command の先頭または shell separator の直後にある完全な `rm`/`del` command word だけを検出する。`model``delimiter``echo del test.txt` は危険な command として扱わない。
**Stop** はループが終了する直前に発火する。以下の hook は終了時の統計を出力する:
```python

View File

@@ -102,12 +102,26 @@ agent_loop(history)
**PreToolUse / PostToolUse**, hooks before and after tool execution. s03's permission check logic is now wrapped as a PreToolUse hook, plus a logging hook and a large-output reminder:
```python
import re
DESTRUCTIVE_COMMAND_WORD = re.compile(
r"(?i)(?:^|[;&|()\n])\s*(?:rm|del)(?=\s|$|[;&|()])"
)
def contains_destructive_command(command: str) -> bool:
return bool(DESTRUCTIVE_COMMAND_WORD.search(command))
# PreToolUse: permission check (s03 logic, moved from loop to hook)
def permission_hook(block):
if block.name == "bash":
command = block.input.get("command", "")
for pattern in DENY_LIST:
if pattern in block.input.get("command", ""):
if pattern in command:
return "Permission denied by deny list"
if contains_destructive_command(command):
return "Potentially destructive command"
if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):
@@ -130,6 +144,8 @@ register_hook("PreToolUse", log_hook)
register_hook("PostToolUse", large_output_hook)
```
The inherited shell rule is case-insensitive and matches a complete `rm` or `del` command word only at the start of a command or after a shell separator. It does not match `model`, `delimiter`, or `echo del test.txt`.
**Stop** triggers when the loop is about to exit. The following hook prints a cleanup summary:
```python

View File

@@ -102,12 +102,26 @@ agent_loop(history)
**PreToolUse / PostToolUse**,工具执行前后的 hook。s03 的权限检查逻辑现在包装成 PreToolUse hook再加一个日志 hook 和一个大输出提醒:
```python
import re
DESTRUCTIVE_COMMAND_WORD = re.compile(
r"(?i)(?:^|[;&|()\n])\s*(?:rm|del)(?=\s|$|[;&|()])"
)
def contains_destructive_command(command: str) -> bool:
return bool(DESTRUCTIVE_COMMAND_WORD.search(command))
# PreToolUse: 权限检查s03 的逻辑,从循环移到 hook
def permission_hook(block):
if block.name == "bash":
command = block.input.get("command", "")
for pattern in DENY_LIST:
if pattern in block.input.get("command", ""):
if pattern in command:
return "Permission denied by deny list"
if contains_destructive_command(command):
return "Potentially destructive command"
if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):
@@ -130,6 +144,8 @@ register_hook("PreToolUse", log_hook)
register_hook("PostToolUse", large_output_hook)
```
沿用的 shell 规则不区分大小写,只在命令开头或 shell 分隔符之后识别完整的 `rm`/`del` 命令词。`model``delimiter``echo del test.txt` 不会被识别为危险命令。
**Stop** 在循环即将退出时触发。以下 hook 打印收尾统计:
```python

View File

@@ -21,6 +21,7 @@ Hooks run callbacks at fixed points in the agent loop:
"""
import os
import re
import subprocess
from pathlib import Path
@@ -139,22 +140,32 @@ def trigger_hooks(event: str, *args):
# s03 permission check logic, now wrapped as a hook
DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_COMMAND_WORD = re.compile(
r"(?i)(?:^|[;&|()\n])\s*(?:rm|del)(?=\s|$|[;&|()])"
)
DESTRUCTIVE = ["> /etc/", "chmod 777"]
def contains_destructive_command(command: str) -> bool:
return bool(DESTRUCTIVE_COMMAND_WORD.search(command))
def permission_hook(block):
"""PreToolUse: s03 check_permission() logic moved here."""
if block.name == "bash":
command = block.input.get("command", "")
for pattern in DENY_LIST:
if pattern in block.input.get("command", ""):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
for kw in DESTRUCTIVE:
if kw in block.input.get("command", ""):
print(f"\n\033[33m[permission] Potentially destructive command\033[0m")
print(f" Tool: {block.name}({block.input})")
choice = input(" Allow? [y/N] ").strip().lower()
if choice not in ("y", "yes"):
return "Permission denied by user"
if contains_destructive_command(command) or any(
kw in command for kw in DESTRUCTIVE
):
print(f"\n\033[33m[permission] Potentially destructive command\033[0m")
print(f" Tool: {block.name}({block.input})")
choice = input(" Allow? [y/N] ").strip().lower()
if choice not in ("y", "yes"):
return "Permission denied by user"
if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):