feat: open Athena tool architecture
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
"""Root-side executor for the single Athena Operator MCP.
|
||||
|
||||
The daemon exposes structured platform operations over a local Unix socket.
|
||||
It deliberately has no arbitrary-command endpoint. Every mutation is first
|
||||
materialised as an expiring, content-bound proposal and requires its exact
|
||||
confirmation string in a later call.
|
||||
It offers both structured, confirmation-bound platform operations and one
|
||||
bounded general terminal escape hatch. The latter keeps the platform useful
|
||||
for unforeseen work while a small denylist protects remote reachability.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -28,7 +28,7 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
VERSION = "1.0.0"
|
||||
VERSION = "2.0.0"
|
||||
STACK = Path(os.environ.get("ATHENA_OPERATOR_STACK", "/opt/mike-ai/stack")).resolve()
|
||||
REPOSITORY = Path(os.environ.get("ATHENA_OPERATOR_REPOSITORY", "/data/mike-ai-operator/repository")).resolve()
|
||||
STATE = Path(os.environ.get("ATHENA_OPERATOR_STATE", "/data/mike-ai-operator/state")).resolve()
|
||||
@@ -59,6 +59,24 @@ ALLOWED_CHECKS = {
|
||||
"compose-mcp": ["docker", "compose", "-f", "platform/mcp/compose.yaml", "config", "-q"],
|
||||
}
|
||||
|
||||
# Athena is physically remote. The general terminal is intentionally broad,
|
||||
# but these operations can strand the machine and therefore remain impossible
|
||||
# through the AI operator. This is a reachability guard, not a general command
|
||||
# allowlist: ordinary Docker, files, Git, HTTP, package, model and remote-SSH
|
||||
# work stays available.
|
||||
TERMINAL_BLOCK_PATTERNS = (
|
||||
r"(?:^|[;&|()\s])(?:shutdown|poweroff|reboot|halt|kexec)(?:\s|$)",
|
||||
r"(?:^|[;&|()\s])init\s+[06](?:\s|$)",
|
||||
r"systemctl\s+(?:stop|restart|disable|mask|kill)\s+[^;&|]*(?:ssh|sshd|networking|networkmanager|systemd-networkd|wireguard|wg-quick)",
|
||||
r"(?:^|[;&|()\s])(?:iptables|ip6tables|nft|ufw|firewall-cmd)(?:\s|$)",
|
||||
r"(?:^|[;&|()\s])ip\s+(?:route|rule|link|addr(?:ess)?)(?:\s|$)",
|
||||
r"(?:^|[;&|()\s])(?:nmcli|wg|wg-quick)(?:\s|$)",
|
||||
r"(?:^|[;&|()\s])(?:mount|umount|fdisk|sfdisk|cfdisk|parted|mkfs(?:\.[a-z0-9]+)?|wipefs)(?:\s|$)",
|
||||
r"(?:^|[;&|()\s])(?:grub-install|update-grub|update-initramfs|modprobe|rmmod|insmod)(?:\s|$)",
|
||||
r"/(?:etc/(?:ssh|network|systemd/network|wireguard)|boot|proc/sys)(?:/|\b)",
|
||||
r"docker\s+(?:stop|restart|rm|kill)\s+[^;&|]*mike-ai-wireguard-gateway",
|
||||
)
|
||||
|
||||
|
||||
def now() -> int:
|
||||
return int(time.time())
|
||||
@@ -201,6 +219,37 @@ def search_source(arguments: dict[str, Any]) -> dict[str, Any]:
|
||||
return {"query": query, "matches": result["output"], "exit_code": result["exit_code"]}
|
||||
|
||||
|
||||
def terminal(arguments: dict[str, Any]) -> dict[str, Any]:
|
||||
command = str(arguments.get("command", "")).strip()
|
||||
if not command or len(command) > 8000 or "\x00" in command:
|
||||
raise ValueError("invalid terminal command")
|
||||
lowered = command.casefold()
|
||||
for pattern in TERMINAL_BLOCK_PATTERNS:
|
||||
if re.search(pattern, lowered, flags=re.IGNORECASE):
|
||||
raise PermissionError(
|
||||
"command blocked because it could break Athena power or remote reachability"
|
||||
)
|
||||
|
||||
cwd_value = str(arguments.get("cwd", str(STACK)))
|
||||
cwd = Path(cwd_value)
|
||||
if not cwd.is_absolute() or not cwd.is_dir():
|
||||
raise ValueError("cwd must be an existing absolute directory")
|
||||
timeout = min(3600, max(1, int(arguments.get("timeout_seconds", 300))))
|
||||
output_limit = min(30000, max(1000, int(arguments.get("max_output_chars", 12000))))
|
||||
result = run(["/bin/bash", "-lc", command], cwd=cwd, timeout=timeout)
|
||||
output = result.get("output", "")
|
||||
if len(output) > output_limit:
|
||||
result["output"] = (
|
||||
output[: int(output_limit * 0.72)]
|
||||
+ f"\n...[terminal output truncated from {len(output)} chars]...\n"
|
||||
+ output[-int(output_limit * 0.25) :]
|
||||
)
|
||||
result["cwd"] = str(cwd)
|
||||
result["reachability_guard"] = "active"
|
||||
audit("terminal", command_sha256=sha(command.encode()), cwd=str(cwd), exit_code=result["exit_code"])
|
||||
return result
|
||||
|
||||
|
||||
def normalise_operation(operation: str, payload: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
||||
if operation not in ALLOWED_OPERATIONS:
|
||||
raise ValueError("unsupported operation")
|
||||
@@ -487,6 +536,7 @@ def dispatch(request: dict[str, Any]) -> dict[str, Any]:
|
||||
if action == "inspect": return inspect(str(arguments.get("subject", "overview")), arguments)
|
||||
if action == "read_source": return read_source(arguments)
|
||||
if action == "search_source": return search_source(arguments)
|
||||
if action == "terminal": return terminal(arguments)
|
||||
if action == "prepare": return prepare(arguments)
|
||||
if action == "execute": return execute(arguments)
|
||||
if action == "job": return job(arguments)
|
||||
|
||||
Reference in New Issue
Block a user