feat(sre): enforce typed host ansible handoffs

This commit is contained in:
Your Name
2026-07-18 23:11:04 +08:00
parent 83fe799f50
commit 5b2547e4ec
24 changed files with 2255 additions and 58 deletions

View File

@@ -19,10 +19,10 @@ SSH MCP Tool Provider — MCP Phase 2a
群組 B (6 個安全操作工具,需 trust_score >= 0.8)
ssh_docker_restart — DockerContainerExited / HarborDown
ssh_docker_compose_restart — SentryDown / SignOzDown / GiteaDown
ssh_systemctl_restart — OllamaDown / KaliScannerDown
ssh_systemctl_restart — compatibility name; direct execution disabled
ssh_clear_docker_logs — HostOutOfDiskSpace (log 佔用)
ssh_renew_ssl — TLSCertExpiringIn7Days
ssh_reload_nginx — TLSProbeFailure / conf 更新後
ssh_reload_nginx — compatibility name; direct execution disabled
四層安全守衛 (缺一不可):
1. tool_name 必須在白名單
@@ -358,7 +358,10 @@ class SSHProvider(MCPToolProvider):
),
MCPTool(
name="ssh_systemctl_restart",
description="Restart a systemd service (systemctl restart <service>). Requires trust_score >= 0.8.",
description=(
"Compatibility-only name. Direct SSH execution is disabled; "
"use the incident-bound Host Ansible controlled executor."
),
input_schema={"type": "object", "properties": {
"host": {"type": "string"},
"service": {"type": "string"},
@@ -388,7 +391,10 @@ class SSHProvider(MCPToolProvider):
),
MCPTool(
name="ssh_reload_nginx",
description="Test and reload nginx config (nginx -t && systemctl reload nginx). Requires trust_score >= 0.8.",
description=(
"Compatibility-only name. Direct reload is disabled; use "
"the incident-bound Host Ansible controlled executor."
),
input_schema={"type": "object", "properties": {
"host": {"type": "string"},
"trust_score": {"type": "number"},
@@ -430,6 +436,19 @@ class SSHProvider(MCPToolProvider):
error=f"Unknown tool: {tool_name}",
)
# Host/systemd mutation has one writer: the typed Ansible broker. Keep
# the legacy tool name discoverable for compatibility, but never turn
# it into a raw SSH command.
if tool_name in {"ssh_systemctl_restart", "ssh_reload_nginx"}:
return MCPToolResult(
success=False,
execution_id=execution_id,
error=(
f"{tool_name}_disabled_use_"
"host_ansible_controlled_executor"
),
)
host = _normalize_ssh_host(str(parameters.get("host", "")))
# 守衛 2: 允許的 host
@@ -553,6 +572,11 @@ class SSHProvider(MCPToolProvider):
def _build_command(self, tool_name: str, params: dict) -> str:
# 所有接受用戶字串的工具,必須先通過 _validate_param() 白名單驗證
if tool_name in {"ssh_systemctl_restart", "ssh_reload_nginx"}:
raise ValueError(
f"{tool_name}_disabled_use_host_ansible_controlled_executor"
)
if tool_name == "ssh_diagnose":
# 2026-04-27 Claude Sonnet 4.6: 主機告警自動診斷 — 只讀,不修改任何狀態
command = (
@@ -618,10 +642,6 @@ class SSHProvider(MCPToolProvider):
service = _validate_param("service", params["service"])
return f"cd {compose_dir} && docker compose restart {service}"
if tool_name == "ssh_systemctl_restart":
svc = _validate_param("service", params["service"])
return f"systemctl restart {svc}"
if tool_name == "ssh_clear_docker_logs":
name = _validate_param("container_name", params["container_name"])
# 透過 docker inspect 取得 log 路徑,再截斷
@@ -635,9 +655,6 @@ class SSHProvider(MCPToolProvider):
domain = _validate_param("domain", params["domain"])
return f"/snap/bin/certbot renew --cert-name {domain} --non-interactive 2>&1"
if tool_name == "ssh_reload_nginx":
return "nginx -t 2>&1 && systemctl reload nginx && echo 'Nginx reloaded'"
if tool_name == "ssh_docker_prune":
# Disk-gated docker prune: only acts when the alerting condition still holds.
# 2026-05-02 ogt + Claude Sonnet 4.6: ADR-068 飛輪 — disk full SOP