From 38c472a11806b66d52b6932637f9e708bcaa5e1a Mon Sep 17 00:00:00 2001 From: dtoro Date: Wed, 5 Aug 2026 16:31:41 +0200 Subject: [PATCH] =?UTF-8?q?0.26.0=20=E2=80=94=20transport-aware=20classifi?= =?UTF-8?q?er=20escalation=20+=20standalone-server=20monitoring=20override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - classifyAndGate: escalate read-only commands on lxc: targets that touch /opt/, /etc/, /var/lib/ to config_mutation. The classifier scores command text only, not the SSH transport layer — SSH-ing into a container to read config is riskier than pct exec from the host. - ontology: standalone-server monitoring override from inherited [ping, resource, updates] to [http]. VPS-like machines may not be SSH/ICMP-reachable from the scheduler; HTTP is the LCD liveness signal. Entities with full SSH can override per-entity. --- VERSION | 2 +- internal/mcp/server.go | 14 ++++++++++++++ seeds/ontology.yaml | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5d60147..e93b647 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.25.1 \ No newline at end of file +0.26.0 \ No newline at end of file diff --git a/internal/mcp/server.go b/internal/mcp/server.go index 2154c85..e80c344 100644 --- a/internal/mcp/server.go +++ b/internal/mcp/server.go @@ -826,6 +826,20 @@ var ( func classifyAndGate(ctx context.Context, pool *db.Pool, agentID, targetID uuid.UUID, targetSlug, command, purpose, declaredRisk, sessionID string) *mcp.CallToolResult { riskClass := policy.ClassifyCommand(command, declaredRisk) + + // Transport-aware escalation: read-only commands on LXC targets that + // touch config paths (/opt/, /etc/) escalate to config_mutation. + // The classifier only scores the command text, not the transport layer + // — SSH-ing into a container to read /opt/ is riskier than running + // the same command locally on the Proxmox host via pct exec. + // Caught live: "cat /etc/hostname" on lxc:dns queued as config_mutation + // while "pct exec 107 -- cat /etc/hostname" on host:hubris auto-ran. + if riskClass == policy.RiskReadOnly && strings.HasPrefix(targetSlug, "lxc:") { + if strings.Contains(command, "/opt/") || strings.Contains(command, "/etc/") || strings.Contains(command, "/var/lib/") { + riskClass = policy.RiskConfigMutation + } + } + runParams, _ := json.Marshal(map[string]string{"command": command, "purpose": purpose}) actionCol := "run:" + string(runParams) diff --git a/seeds/ontology.yaml b/seeds/ontology.yaml index ffc9a2c..b9bfa52 100644 --- a/seeds/ontology.yaml +++ b/seeds/ontology.yaml @@ -241,6 +241,11 @@ entity_types: layer: infrastructure lifecycle: infrastructure description: Machine outside PVE management (e.g. external VPS). + # Override inherited [ping, resource, updates] — standalone servers may + # not be SSH/ICMP-reachable from the scheduler. HTTP is the least- + # common-denominator liveness signal. Entities with full SSH access + # can override to [ping, resource, http]. + monitoring: [http] attributes: type: object properties: