aboutsummaryrefslogtreecommitdiff
path: root/autogpt/commands/execute_code.py
diff options
context:
space:
mode:
Diffstat (limited to 'autogpt/commands/execute_code.py')
-rw-r--r--autogpt/commands/execute_code.py303
1 files changed, 0 insertions, 303 deletions
diff --git a/autogpt/commands/execute_code.py b/autogpt/commands/execute_code.py
deleted file mode 100644
index aad93193e..000000000
--- a/autogpt/commands/execute_code.py
+++ /dev/null
@@ -1,303 +0,0 @@
-"""Execute code in a Docker container"""
-import os
-import subprocess
-from pathlib import Path
-
-import docker
-from docker.errors import DockerException, ImageNotFound
-from docker.models.containers import Container as DockerContainer
-
-from autogpt.agent.agent import Agent
-from autogpt.command_decorator import command
-from autogpt.config import Config
-from autogpt.logs import logger
-
-from .decorators import sanitize_path_arg
-
-ALLOWLIST_CONTROL = "allowlist"
-DENYLIST_CONTROL = "denylist"
-
-
-@command(
- "execute_python_code",
- "Creates a Python file and executes it",
- {
- "code": {
- "type": "string",
- "description": "The Python code to run",
- "required": True,
- },
- "name": {
- "type": "string",
- "description": "A name to be given to the python file",
- "required": True,
- },
- },
-)
-def execute_python_code(code: str, name: str, agent: Agent) -> str:
- """Create and execute a Python file in a Docker container and return the STDOUT of the
- executed code. If there is any data that needs to be captured use a print statement
-
- Args:
- code (str): The Python code to run
- name (str): A name to be given to the Python file
-
- Returns:
- str: The STDOUT captured from the code when it ran
- """
- ai_name = agent.ai_config.ai_name
- code_dir = agent.workspace.get_path(Path(ai_name, "executed_code"))
- os.makedirs(code_dir, exist_ok=True)
-
- if not name.endswith(".py"):
- name = name + ".py"
-
- # The `name` arg is not covered by @sanitize_path_arg,
- # so sanitization must be done here to prevent path traversal.
- file_path = agent.workspace.get_path(code_dir / name)
- if not file_path.is_relative_to(code_dir):
- return "Error: 'name' argument resulted in path traversal, operation aborted"
-
- try:
- with open(file_path, "w+", encoding="utf-8") as f:
- f.write(code)
-
- return execute_python_file(str(file_path), agent)
- except Exception as e:
- return f"Error: {str(e)}"
-
-
-@command(
- "execute_python_file",
- "Executes an existing Python file",
- {
- "filename": {
- "type": "string",
- "description": "The name of te file to execute",
- "required": True,
- },
- },
-)
-@sanitize_path_arg("filename")
-def execute_python_file(filename: str, agent: Agent) -> str:
- """Execute a Python file in a Docker container and return the output
-
- Args:
- filename (str): The name of the file to execute
-
- Returns:
- str: The output of the file
- """
- logger.info(
- f"Executing python file '{filename}' in working directory '{agent.config.workspace_path}'"
- )
-
- if not filename.endswith(".py"):
- return "Error: Invalid file type. Only .py files are allowed."
-
- file_path = Path(filename)
- if not file_path.is_file():
- # Mimic the response that you get from the command line so that it's easier to identify
- return (
- f"python: can't open file '{filename}': [Errno 2] No such file or directory"
- )
-
- if we_are_running_in_a_docker_container():
- logger.debug(
- f"Auto-GPT is running in a Docker container; executing {file_path} directly..."
- )
- result = subprocess.run(
- ["python", str(file_path)],
- capture_output=True,
- encoding="utf8",
- cwd=agent.config.workspace_path,
- )
- if result.returncode == 0:
- return result.stdout
- else:
- return f"Error: {result.stderr}"
-
- logger.debug("Auto-GPT is not running in a Docker container")
- try:
- client = docker.from_env()
- # You can replace this with the desired Python image/version
- # You can find available Python images on Docker Hub:
- # https://hub.docker.com/_/python
- image_name = "python:3-alpine"
- try:
- client.images.get(image_name)
- logger.debug(f"Image '{image_name}' found locally")
- except ImageNotFound:
- logger.info(
- f"Image '{image_name}' not found locally, pulling from Docker Hub..."
- )
- # Use the low-level API to stream the pull response
- low_level_client = docker.APIClient()
- for line in low_level_client.pull(image_name, stream=True, decode=True):
- # Print the status and progress, if available
- status = line.get("status")
- progress = line.get("progress")
- if status and progress:
- logger.info(f"{status}: {progress}")
- elif status:
- logger.info(status)
-
- logger.debug(f"Running {file_path} in a {image_name} container...")
- container: DockerContainer = client.containers.run(
- image_name,
- ["python", str(file_path.relative_to(agent.workspace.root))],
- volumes={
- agent.config.workspace_path: {
- "bind": "/workspace",
- "mode": "ro",
- }
- },
- working_dir="/workspace",
- stderr=True,
- stdout=True,
- detach=True,
- ) # type: ignore
-
- container.wait()
- logs = container.logs().decode("utf-8")
- container.remove()
-
- # print(f"Execution complete. Output: {output}")
- # print(f"Logs: {logs}")
-
- return logs
-
- except DockerException as e:
- logger.warn(
- "Could not run the script in a container. If you haven't already, please install Docker https://docs.docker.com/get-docker/"
- )
- return f"Error: {str(e)}"
-
- except Exception as e:
- return f"Error: {str(e)}"
-
-
-def validate_command(command: str, config: Config) -> bool:
- """Validate a command to ensure it is allowed
-
- Args:
- command (str): The command to validate
- config (Config): The config to use to validate the command
-
- Returns:
- bool: True if the command is allowed, False otherwise
- """
- if not command:
- return False
-
- command_name = command.split()[0]
-
- if config.shell_command_control == ALLOWLIST_CONTROL:
- return command_name in config.shell_allowlist
- else:
- return command_name not in config.shell_denylist
-
-
-@command(
- "execute_shell",
- "Executes a Shell Command, non-interactive commands only",
- {
- "command_line": {
- "type": "string",
- "description": "The command line to execute",
- "required": True,
- }
- },
- enabled=lambda config: config.execute_local_commands,
- disabled_reason="You are not allowed to run local shell commands. To execute"
- " shell commands, EXECUTE_LOCAL_COMMANDS must be set to 'True' "
- "in your config file: .env - do not attempt to bypass the restriction.",
-)
-def execute_shell(command_line: str, agent: Agent) -> str:
- """Execute a shell command and return the output
-
- Args:
- command_line (str): The command line to execute
-
- Returns:
- str: The output of the command
- """
- if not validate_command(command_line, agent.config):
- logger.info(f"Command '{command_line}' not allowed")
- return "Error: This Shell Command is not allowed."
-
- current_dir = Path.cwd()
- # Change dir into workspace if necessary
- if not current_dir.is_relative_to(agent.config.workspace_path):
- os.chdir(agent.config.workspace_path)
-
- logger.info(
- f"Executing command '{command_line}' in working directory '{os.getcwd()}'"
- )
-
- result = subprocess.run(command_line, capture_output=True, shell=True)
- output = f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
-
- # Change back to whatever the prior working dir was
-
- os.chdir(current_dir)
- return output
-
-
-@command(
- "execute_shell_popen",
- "Executes a Shell Command, non-interactive commands only",
- {
- "query": {
- "type": "string",
- "description": "The search query",
- "required": True,
- }
- },
- lambda config: config.execute_local_commands,
- "You are not allowed to run local shell commands. To execute"
- " shell commands, EXECUTE_LOCAL_COMMANDS must be set to 'True' "
- "in your config. Do not attempt to bypass the restriction.",
-)
-def execute_shell_popen(command_line, agent: Agent) -> str:
- """Execute a shell command with Popen and returns an english description
- of the event and the process id
-
- Args:
- command_line (str): The command line to execute
-
- Returns:
- str: Description of the fact that the process started and its id
- """
- if not validate_command(command_line, agent.config):
- logger.info(f"Command '{command_line}' not allowed")
- return "Error: This Shell Command is not allowed."
-
- current_dir = os.getcwd()
- # Change dir into workspace if necessary
- if agent.config.workspace_path not in current_dir:
- os.chdir(agent.config.workspace_path)
-
- logger.info(
- f"Executing command '{command_line}' in working directory '{os.getcwd()}'"
- )
-
- do_not_show_output = subprocess.DEVNULL
- process = subprocess.Popen(
- command_line, shell=True, stdout=do_not_show_output, stderr=do_not_show_output
- )
-
- # Change back to whatever the prior working dir was
-
- os.chdir(current_dir)
-
- return f"Subprocess started with PID:'{str(process.pid)}'"
-
-
-def we_are_running_in_a_docker_container() -> bool:
- """Check if we are running in a Docker container
-
- Returns:
- bool: True if we are running in a Docker container, False otherwise
- """
- return os.path.exists("/.dockerenv")