RBAC: the built-in view ClusterRole (which never includes Secrets, so Vault-managed material stays structurally invisible) plus a read-only extra for nodes, namespaces, PVs, storage classes, CRDs, Flux resources and metrics, bound to the chat service account. Tooling: a cluster-read plugin registers a GET-only cluster_read tool against the in-cluster API using the pod's projected token - secrets paths refused in the handler as well, malformed segments rejected, responses bounded and stripped of managedFields noise. Classified read_files/low in the HUX capability map. RBAC applies on push; the tool activates when the pods next roll (bundled with the round-3 voice build). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
73 lines
3.1 KiB
Python
73 lines
3.1 KiB
Python
"""Conservative mapping from Hermes tools to HUX capabilities."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ToolPolicy:
|
|
"""The HUX gate inputs for one tool family."""
|
|
|
|
capability: str
|
|
risk: str
|
|
external: bool
|
|
|
|
|
|
EXACT = {
|
|
"read_file": ToolPolicy("read_files", "low", False),
|
|
"read_many_files": ToolPolicy("read_files", "low", False),
|
|
"list_directory": ToolPolicy("read_files", "low", False),
|
|
"search_files": ToolPolicy("read_files", "low", False),
|
|
"session_search": ToolPolicy("read_files", "low", False),
|
|
"tool_search": ToolPolicy("read_files", "low", False),
|
|
"write_file": ToolPolicy("write_files", "medium", False),
|
|
"patch": ToolPolicy("write_files", "medium", False),
|
|
"memory": ToolPolicy("memory_write", "medium", False),
|
|
"delegate_task": ToolPolicy("delegate", "high", False),
|
|
"terminal": ToolPolicy("shell", "high", True),
|
|
# The Python sandbox is isolated by design; it is internal shell work,
|
|
# unlike the real terminal above.
|
|
"python": ToolPolicy("shell", "medium", False),
|
|
"python_sandbox": ToolPolicy("shell", "medium", False),
|
|
# Core assistant faculties are reads, not side effects.
|
|
"skills": ToolPolicy("read_files", "low", False),
|
|
"clarify": ToolPolicy("read_files", "low", False),
|
|
"todo": ToolPolicy("read_files", "low", False),
|
|
"vision": ToolPolicy("read_files", "low", False),
|
|
# Browsing is the product; it is network, not an unknown side effect.
|
|
"browser": ToolPolicy("network", "medium", True),
|
|
"web": ToolPolicy("network", "medium", True),
|
|
"web_search": ToolPolicy("network", "medium", True),
|
|
# Image generation produces an artifact through the trusted broker.
|
|
"image_gen": ToolPolicy("artifact_write", "medium", False),
|
|
# Read-only cluster visibility; RBAC and the handler both exclude secrets.
|
|
"cluster_read": ToolPolicy("read_files", "low", False),
|
|
}
|
|
|
|
PREFIXES = (
|
|
(("skill_", "skills_", "todo_", "clarify_"), ToolPolicy("read_files", "low", False)),
|
|
(("web_", "browser_", "http_", "mcp_"), ToolPolicy("network", "medium", True)),
|
|
(("send_", "mail_", "email_", "slack_", "discord_", "telegram_"), ToolPolicy("send_message", "high", True)),
|
|
(("kubectl_", "flux_", "deploy_", "release_"), ToolPolicy("deploy", "high", True)),
|
|
(("image_",), ToolPolicy("artifact_write", "medium", False)),
|
|
(("video_", "vision_"), ToolPolicy("read_files", "low", False)),
|
|
(("artifact_",), ToolPolicy("artifact_write", "medium", False)),
|
|
(("memory_",), ToolPolicy("memory_write", "medium", False)),
|
|
(("delegate_", "subagent_"), ToolPolicy("delegate", "high", False)),
|
|
(("write_", "edit_", "file_"), ToolPolicy("write_files", "medium", False)),
|
|
)
|
|
|
|
UNKNOWN = ToolPolicy("external_side_effect", "high", True)
|
|
|
|
|
|
def classify(tool_name: str) -> ToolPolicy:
|
|
"""Return a known mapping, treating every unknown tool as high-risk external."""
|
|
name = tool_name.strip().lower() if isinstance(tool_name, str) else ""
|
|
if name in EXACT:
|
|
return EXACT[name]
|
|
for prefixes, policy in PREFIXES:
|
|
if name.startswith(prefixes):
|
|
return policy
|
|
return UNKNOWN
|