Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion s03_permission/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"""

import os
import re
import subprocess
from pathlib import Path

Expand Down Expand Up @@ -151,13 +152,15 @@ def check_deny_list(command: str) -> str | None:
return None


DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"

# Gate 2: Rule matching - context-dependent checks
PERMISSION_RULES = [
{"tools": ["read_file", "write_file", "edit_file"],
"check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR),
"message": "Writing outside workspace"},
{"tools": ["bash"],
"check": lambda args: any(kw in args.get("command", "") for kw in ["rm ", "> /etc/", "chmod 777"]),
"check": lambda args: bool(re.search(DESTRUCTIVE_PATTERN, args.get("command", ""), re.IGNORECASE)),
"message": "Potentially destructive command"},
]

Expand Down
19 changes: 10 additions & 9 deletions s04_hooks/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"""

import os
import re
import subprocess
from pathlib import Path

Expand Down Expand Up @@ -139,22 +140,22 @@ 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_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"

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 re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
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):
Expand Down
16 changes: 8 additions & 8 deletions s05_todo_write/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import ast
import json
import os
import re
import subprocess
from pathlib import Path

Expand Down Expand Up @@ -218,7 +219,7 @@ def trigger_hooks(event: str, *args):
return None

DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"

def permission_hook(block):
"""PreToolUse: s03 permission logic, registered as an s04 hook."""
Expand All @@ -228,13 +229,12 @@ def permission_hook(block):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
for keyword in DESTRUCTIVE:
if keyword in 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 re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
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):
Expand Down
16 changes: 8 additions & 8 deletions s06_subagent/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"""

import os
import re
import subprocess
from pathlib import Path

Expand Down Expand Up @@ -154,7 +155,7 @@ def trigger_hooks(event: str, *args):


DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def permission_hook(block):
Expand All @@ -165,13 +166,12 @@ def permission_hook(block):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
for keyword in DESTRUCTIVE:
if keyword in command:
print("\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 re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print("\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", "")
Expand Down
16 changes: 8 additions & 8 deletions s07_skill_loading/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""

import os
import re
import subprocess
from pathlib import Path

Expand Down Expand Up @@ -241,7 +242,7 @@ def trigger_hooks(event: str, *args):


DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def permission_hook(block):
Expand All @@ -252,13 +253,12 @@ def permission_hook(block):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
for keyword in DESTRUCTIVE:
if keyword in command:
print("\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 re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print("\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", "")
Expand Down
4 changes: 2 additions & 2 deletions s08_context_compact/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def trigger_hooks(event: str, *args):


DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def permission_hook(block):
Expand All @@ -187,7 +187,7 @@ def permission_hook(block):
for pattern in DENY_LIST:
if pattern in command:
return f"Permission denied by deny list: {pattern}"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print("\n\033[33m[permission] Potentially destructive command\033[0m")
print(f" Tool: {block.name}({block.input})")
if input(" Allow? [y/N] ").strip().lower() not in ("y", "yes"):
Expand Down
4 changes: 2 additions & 2 deletions s09_memory/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,15 +634,15 @@ def trigger_hooks(event: str, *args):
return None

DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"

def permission_hook(block):
if block.name == "bash":
command = block.input.get("command", "")
for pattern in DENY_LIST:
if pattern in command:
return f"Permission denied by deny list: {pattern}"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print("\n\033[33m[permission] Potentially destructive command\033[0m")
print(f" Tool: {block.name}({block.input})")
if input(" Allow? [y/N] ").strip().lower() not in ("y", "yes"):
Expand Down
4 changes: 2 additions & 2 deletions s10_task_system/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ def trigger_hooks(event: str, *args):


DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def permission_hook(block):
Expand All @@ -454,7 +454,7 @@ def permission_hook(block):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print("\n\033[33m[permission] Potentially destructive command\033[0m")
print(f" Tool: {block.name}({block.input})")
choice = input(" Allow? [y/N] ").strip().lower()
Expand Down
5 changes: 3 additions & 2 deletions s11_background_tasks/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import atexit
import glob
import os
import re
import signal
import subprocess
import threading
Expand Down Expand Up @@ -225,7 +226,7 @@ def trigger_hooks(event: str, *args):


DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def permission_hook(block):
Expand All @@ -235,7 +236,7 @@ def permission_hook(block):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print("\n\033[33m[permission] Potentially destructive command\033[0m")
print(f" Tool: {block.name}({block.input})")
choice = input(" Allow? [y/N] ").strip().lower()
Expand Down
5 changes: 3 additions & 2 deletions s12_cron_scheduler/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import glob
import json
import os
import re
import secrets
import subprocess
import threading
Expand Down Expand Up @@ -173,7 +174,7 @@ def trigger_hooks(event: str, *args):


DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def request_permission(block, reason: str) -> str | None:
Expand All @@ -195,7 +196,7 @@ def permission_hook(block):
if pattern in command:
print(f"\n\033[31m[blocked] '{pattern}'\033[0m")
return "Permission denied by deny list"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
return request_permission(block, "Potentially destructive command")

if block.name in ("read_file", "write_file", "edit_file"):
Expand Down
4 changes: 2 additions & 2 deletions s13_agent_teams/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -1663,7 +1663,7 @@ def run_create_worktree(name: str, task_id: str) -> str:

HOOKS = {"UserPromptSubmit": [], "PreToolUse": [], "PostToolUse": [], "Stop": []}
DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def register_hook(event: str, callback):
Expand All @@ -1686,7 +1686,7 @@ def check_permission(block, prompt_user: bool = True) -> str | None:
for pattern in DENY_LIST:
if pattern in command:
return f"Permission denied by deny list: {pattern}"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
if not prompt_user:
return "Permission required: ask Lead to run this command."
print(f"\n[permission] {block.name}({block.input})")
Expand Down
4 changes: 2 additions & 2 deletions s14_mcp_plugin/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def assemble_system_prompt() -> str:

HOOKS = {"UserPromptSubmit": [], "PreToolUse": [], "PostToolUse": [], "Stop": []}
DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


def register_hook(event: str, callback):
Expand All @@ -390,7 +390,7 @@ def permission_hook(block):
for pattern in DENY_LIST:
if pattern in command:
return f"Permission denied by deny list: {pattern}"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print(f"\n[permission] {block.name}({block.input})")
if input("Allow? [y/N] ").strip().lower() not in {"y", "yes"}:
return "Permission denied by user"
Expand Down
5 changes: 3 additions & 2 deletions s17_goal_loop/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import glob
import json
import os
import re
import subprocess
import sys
import time
Expand All @@ -45,7 +46,7 @@
MAX_GOAL_LENGTH = 4000
CLEAR_ALIASES = {"clear", "stop", "off", "reset", "none", "cancel"}
DENY_LIST = ["rm -rf /", "sudo", "shutdown", "reboot", "mkfs", "dd if="]
DESTRUCTIVE = ["rm ", "> /etc/", "chmod 777"]
DESTRUCTIVE_PATTERN = r"(?:^|[;&|\n]|&&|\|\|)\s*(?:rm|del|rmdir|erase)(?:[\s/]|$)|> /etc/|chmod 777"


class GoalError(Exception):
Expand Down Expand Up @@ -598,7 +599,7 @@ def _permission_hook(self, block: Any) -> str | None:
for pattern in DENY_LIST:
if pattern in command:
return f"Permission denied by deny list: {pattern}"
if any(keyword in command for keyword in DESTRUCTIVE):
if re.search(DESTRUCTIVE_PATTERN, command, re.IGNORECASE):
print(f"\n[permission] {name}({arguments})")
if input("Allow? [y/N] ").strip().lower() not in {"y", "yes"}:
return "Permission denied by user"
Expand Down
Loading