Wartung (B10): Restart-Allowlist vereinheitlichen

Der ServicesCard-"Anzeige- statt Unit-Name"-Bug ist behoben (Frontend nutzt
durchgehend x.unit). Der echte Rest-Fehler lag in der ZWEITEN Restart-Wahrheit:
/api/system/restart (system.py) + das MCP-Tool restart_service hatten eine
veraltete Allowlist ohne llama-swap (Engine) und hermes-terminal, dafuer mit
Geist-Eintrag hermes-webui. Ein Engine-Neustart per Sprache/MCP schlug daher mit
"nicht erlaubt" fehl.

Fix: /api/system/restart delegiert jetzt an services.maintenance.restart_service
(EINE Allowlist-Wahrheit, kennt System- via sudo -n UND User-Dienste, wird auch
von der UI genutzt). MCP-Tool-Docstring auf die echten Dienste korrigiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-03 19:14:32 +02:00
parent 4e5a7eed35
commit d0688a7b64
2 changed files with 11 additions and 8 deletions
+8 -6
View File
@@ -9,13 +9,14 @@ import logging
import os import os
import subprocess import subprocess
from fastapi import APIRouter, HTTPException from fastapi import APIRouter
from pydantic import BaseModel from pydantic import BaseModel
import httpx import httpx
from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL, MEM0_SERVICE_URL, VOICE_SERVICE_URL from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL, MEM0_SERVICE_URL, VOICE_SERVICE_URL
from services import backup as backup_svc from services import backup as backup_svc
from services import maintenance
from services.agent import agent_status from services.agent import agent_status
from services.gateway import gateway_reachable from services.gateway import gateway_reachable
from services.llamaswap import engine_reachable, list_models from services.llamaswap import engine_reachable, list_models
@@ -27,8 +28,6 @@ log = logging.getLogger(__name__)
router = APIRouter(prefix="/api") router = APIRouter(prefix="/api")
# Nur diese User-Dienste dürfen neugestartet werden.
ALLOWED_SERVICES = {"mission-control-2", "hermes-gateway", "hermes-webui", "mem0-service", "voice-service"}
# Quelle für Self-Update (auf der Box ~/mission-control-v2). # Quelle für Self-Update (auf der Box ~/mission-control-v2).
SOURCE_DIR = os.path.expanduser(os.environ.get("MC2_SOURCE_DIR", "~/mission-control-v2")) SOURCE_DIR = os.path.expanduser(os.environ.get("MC2_SOURCE_DIR", "~/mission-control-v2"))
@@ -99,9 +98,12 @@ class RestartReq(BaseModel):
@router.post("/system/restart") @router.post("/system/restart")
def restart(req: RestartReq) -> dict: def restart(req: RestartReq) -> dict:
if req.service not in ALLOWED_SERVICES: """Dienst neustarten. Delegiert an den Wartungs-Service (EINE Allowlist-Wahrheit):
raise HTTPException(400, f"Dienst '{req.service}' nicht erlaubt.") der kennt System-Dienste (llama-swap, via sudo -n) UND User-Dienste und wird auch von
return _run(["systemctl", "--user", "restart", req.service]) der UI (/api/maintenance/restart) genutzt. Vorher lag hier eine zweite, veraltete Liste
(ohne llama-swap/hermes-terminal, mit Geist-Eintrag hermes-webui) → Engine-Neustart per
Sprache/MCP schlug fehl."""
return maintenance.restart_service(req.service)
@router.post("/system/self-update") @router.post("/system/self-update")
+3 -2
View File
@@ -226,8 +226,9 @@ def list_services() -> str:
@mcp.tool() @mcp.tool()
def restart_service(service: str) -> str: def restart_service(service: str) -> str:
"""Startet einen erlaubten Dienst neu """Startet einen erlaubten Dienst neu. Erlaubt: llama-swap (Engine) | mission-control-2 |
(mission-control-2 | hermes-gateway | hermes-webui | mem0-service | voice-service).""" hermes-gateway | hermes-terminal | mem0-service | voice-service. Der Engine-Neustart
(llama-swap = System-Dienst) kann das Box-Passwort verlangen, wenn kein NOPASSWD gesetzt ist."""
res = _post("/api/system/restart", {"service": service}) res = _post("/api/system/restart", {"service": service})
return f"Restart {service}: {'ok' if res.get('ok') else 'Fehler — ' + res.get('err', '')}" return f"Restart {service}: {'ok' if res.get('ok') else 'Fehler — ' + res.get('err', '')}"