complete MCP tool surface — Matrix approval webhook loop + token verification
Plan #6 (MCP Tool Completion / bin/homelab Migration) done. - Approval records created for gated request_execution actions - Notifier sends Matrix messages with HMAC approval tokens - Stores matrix_event_id, polls /relations/{id}/m.annotation for ✅/❌ - Reaction detection triggers DecideApproval API call - Token verification added to DecideApproval endpoint - Migration 013: matrix_event_id + alert_sent_at on approvals - AGENTS.md: 21-tool surface documented, stale homelab CLI refs removed - Plan index updated, audit cross-reference refreshed
This commit is contained in:
@@ -271,17 +271,17 @@ func newServer(pool *db.Pool, agentID uuid.UUID) *mcp.Server {
|
||||
return textResult(result), nil
|
||||
|
||||
case "systemctl":
|
||||
svc := strings.TrimPrefix(targetSlug, "lxc:")
|
||||
if params == "enable" || params == "disable" {
|
||||
pool.Exec(ctx, `UPDATE executions SET status='pending_approval', risk_class='config_mutation' WHERE entity_id=$1`, id)
|
||||
createApproval(ctx, pool, id, targetID, "systemctl", svc+":"+params, "config_mutation")
|
||||
return textResult(fmt.Sprintf("systemctl %s on %s requires approval — execution %s queued", params, svc, id)), nil
|
||||
}
|
||||
host, user, err := resolveHost(ctx, pool, targetSlug)
|
||||
if err != nil {
|
||||
return textResult(fmt.Sprintf("resolve: %v", err)), nil
|
||||
}
|
||||
svc := strings.TrimPrefix(targetSlug, "lxc:")
|
||||
cmd := fmt.Sprintf("systemctl %s %s 2>&1; sleep 1; systemctl is-active %s", params, svc, svc)
|
||||
if params == "enable" || params == "disable" {
|
||||
// config_mutation — mark as pending for operator approval
|
||||
pool.Exec(ctx, `UPDATE executions SET status='pending_approval', risk_class='config_mutation' WHERE entity_id=$1`, id)
|
||||
return textResult(fmt.Sprintf("systemctl %s on %s requires approval — execution %s queued", params, svc, id)), nil
|
||||
}
|
||||
out, err := sshExec(ctx, host, user, cmd)
|
||||
result := fmt.Sprintf("systemctl %s %s: %s", params, svc, out)
|
||||
if err != nil {
|
||||
@@ -329,6 +329,7 @@ func newServer(pool *db.Pool, agentID uuid.UUID) *mcp.Server {
|
||||
}
|
||||
// upgrade requires approval — queue
|
||||
pool.Exec(ctx, `UPDATE executions SET status='pending_approval', risk_class='config_mutation' WHERE entity_id=$1`, id)
|
||||
createApproval(ctx, pool, id, targetID, "apt_upgrade", params, "config_mutation")
|
||||
return textResult(fmt.Sprintf("apt_upgrade on %s requires approval — execution %s queued", targetSlug, id)), nil
|
||||
|
||||
default:
|
||||
@@ -941,4 +942,5 @@ func createApproval(ctx context.Context, pool *db.Pool, execID, targetID uuid.UU
|
||||
VALUES ($1, $2, $3, $4, 'execution', $5::jsonb, 'pending',
|
||||
now() + interval '1 hour', now())`,
|
||||
approvalID, targetID, action, riskClass, payload)
|
||||
pool.Exec(ctx, `UPDATE executions SET approval_id = $2 WHERE entity_id = $1`, execID, approvalID)
|
||||
}
|
||||
Reference in New Issue
Block a user