Skip to main content
Glama
command.py5.7 kB
""" Command execution interface for the enhanced Sandbox SDK. """ import subprocess import uuid from typing import List, Optional import aiohttp from .command_execution import CommandExecution class Command: """ Command class for executing shell commands in a sandbox. Supports both local and remote command execution. """ def __init__(self, sandbox_instance): """ Initialize the command instance. Args: sandbox_instance: The sandbox instance this command belongs to """ self._sandbox = sandbox_instance async def run( self, command: str, args: Optional[List[str]] = None, timeout: Optional[int] = None, working_directory: Optional[str] = None, ) -> CommandExecution: """ Execute a shell command in the sandbox. Args: command: The command to execute args: Optional list of command arguments timeout: Optional timeout in seconds working_directory: Optional working directory for command execution Returns: A CommandExecution object containing the results Raises: RuntimeError: If the sandbox is not started or execution fails """ if not self._sandbox._is_started: raise RuntimeError("Sandbox is not started. Call start() first.") if args is None: args = [] if self._sandbox.remote: # Remote execution via microsandbox server return await self._run_remote(command, args, timeout, working_directory) else: # Local execution return await self._run_local(command, args, timeout, working_directory) async def _run_remote( self, command: str, args: List[str], timeout: Optional[int], working_directory: Optional[str], ) -> CommandExecution: """ Execute a command remotely via the microsandbox server. """ headers = {"Content-Type": "application/json"} if self._sandbox._api_key: headers["Authorization"] = f"Bearer {self._sandbox._api_key}" request_data = { "jsonrpc": "2.0", "method": "sandbox.command.run", "params": { "sandbox": self._sandbox._name, "namespace": self._sandbox._namespace, "command": command, "args": args, }, "id": str(uuid.uuid4()), } if timeout is not None: request_data["params"]["timeout"] = timeout if working_directory is not None: request_data["params"]["working_directory"] = working_directory try: async with self._sandbox._session.post( f"{self._sandbox._server_url}/api/v1/rpc", json=request_data, headers=headers, ) as response: if response.status != 200: error_text = await response.text() raise RuntimeError(f"Failed to execute command: {error_text}") response_data = await response.json() if "error" in response_data: raise RuntimeError( f"Failed to execute command: {response_data['error']['message']}" ) result = response_data.get("result", {}) return CommandExecution(output_data=result) except aiohttp.ClientError as e: raise RuntimeError(f"Failed to execute command: {e}") async def _run_local( self, command: str, args: List[str], timeout: Optional[int], working_directory: Optional[str], ) -> CommandExecution: """ Execute a command locally. """ # Security check for dangerous commands dangerous_patterns = [ "rm -rf", "sudo", "chmod 777", ">/dev/null", "format", "del /f", "rmdir /s", ] full_command = f"{command} {' '.join(args)}" for pattern in dangerous_patterns: if pattern in full_command.lower(): return CommandExecution( stdout="", stderr=f"Command blocked for security: contains '{pattern}'", exit_code=1, command=full_command, timeout=False, ) try: # Use subprocess to execute the command result = subprocess.run( [command] + args, capture_output=True, text=True, timeout=timeout, cwd=working_directory, ) return CommandExecution( stdout=result.stdout, stderr=result.stderr, exit_code=result.returncode, command=full_command, timeout=False, ) except subprocess.TimeoutExpired: return CommandExecution( stdout="", stderr=f"Command timed out after {timeout} seconds", exit_code=124, # Standard timeout exit code command=full_command, timeout=True, ) except Exception as e: return CommandExecution( stdout="", stderr=f"Command execution failed: {str(e)}", exit_code=1, command=full_command, timeout=False, )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/scooter-lacroix/sandbox-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server