mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-27 11:04:26 +01:00
added some regex based checks for dangerous commands (#38)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from pathlib import Path
|
||||
from subprocess import CompletedProcess, run
|
||||
from typing import List
|
||||
from goose.utils.check_shell_command import is_dangerous_command
|
||||
|
||||
from exchange import Message
|
||||
from rich import box
|
||||
@@ -135,7 +136,7 @@ class Developer(Toolkit):
|
||||
command (str): The shell command to run. It can support multiline statements
|
||||
if you need to run more than one at a time
|
||||
"""
|
||||
self.notifier.status("running shell command")
|
||||
self.notifier.status("planning to run shell command")
|
||||
# Log the command being executed in a visually structured format (Markdown).
|
||||
# The `.log` method is used here to log the command execution in the application's UX
|
||||
# this method is dynamically attached to functions in the Goose framework to handle user-visible
|
||||
@@ -156,13 +157,13 @@ class Developer(Toolkit):
|
||||
rating = int(rating)
|
||||
except ValueError:
|
||||
rating = 5 # if we can't interpret we default to unsafe
|
||||
if int(rating) > 3:
|
||||
if is_dangerous_command(command) or int(rating) > 3:
|
||||
if not keep_unsafe_command_prompt(command):
|
||||
raise RuntimeError(
|
||||
f"The command {command} was rejected as dangerous by the user."
|
||||
+ " Do not proceed further, instead ask for instructions."
|
||||
)
|
||||
|
||||
self.notifier.status("running shell command")
|
||||
result: CompletedProcess = run(command, shell=True, text=True, capture_output=True, check=False)
|
||||
if result.returncode == 0:
|
||||
output = "Command succeeded"
|
||||
|
||||
33
src/goose/utils/check_shell_command.py
Normal file
33
src/goose/utils/check_shell_command.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import re
|
||||
|
||||
|
||||
def is_dangerous_command(command: str) -> bool:
|
||||
"""
|
||||
Check if the command matches any dangerous patterns.
|
||||
|
||||
Args:
|
||||
command (str): The shell command to check.
|
||||
|
||||
Returns:
|
||||
bool: True if the command is dangerous, False otherwise.
|
||||
"""
|
||||
dangerous_patterns = [
|
||||
r"\brm\b", # rm command
|
||||
r"\bgit\s+push\b", # git push command
|
||||
r"\bsudo\b", # sudo command
|
||||
# Add more dangerous command patterns here
|
||||
r"\bmv\b", # mv command
|
||||
r"\bchmod\b", # chmod command
|
||||
r"\bchown\b", # chown command
|
||||
r"\bmkfs\b", # mkfs command
|
||||
r"\bsystemctl\b", # systemctl command
|
||||
r"\breboot\b", # reboot command
|
||||
r"\bshutdown\b", # shutdown command
|
||||
# Manipulating files in ~/ directly or dot files
|
||||
r"^~/[^/]+$", # Files directly in home directory
|
||||
r"/\.[^/]+$", # Dot files
|
||||
]
|
||||
for pattern in dangerous_patterns:
|
||||
if re.search(pattern, command):
|
||||
return True
|
||||
return False
|
||||
27
tests/utils/test_check_shell_command.py
Normal file
27
tests/utils/test_check_shell_command.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import pytest
|
||||
from goose.utils.check_shell_command import is_dangerous_command
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"command",
|
||||
[
|
||||
"rm -rf /",
|
||||
"git push origin master",
|
||||
"sudo reboot",
|
||||
"mv /etc/passwd /tmp/",
|
||||
"chmod 777 /etc/passwd",
|
||||
"chown root:root /etc/passwd",
|
||||
"mkfs -t ext4 /dev/sda1",
|
||||
"systemctl stop nginx",
|
||||
"reboot",
|
||||
"shutdown now",
|
||||
"echo hello > ~/.bashrc",
|
||||
],
|
||||
)
|
||||
def test_dangerous_commands(command):
|
||||
assert is_dangerous_command(command)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("command", ["ls -la", 'echo "Hello World"', "cp ~/folder/file.txt /tmp/"])
|
||||
def test_safe_commands(command):
|
||||
assert not is_dangerous_command(command)
|
||||
Reference in New Issue
Block a user