secubox-deb/daemon/cmd/secuboxctl/main.go
CyberMind-FR 12fb41fd30 Add Unix socket control server for secuboxd CLI communication
Implement control server at /run/secuboxd/topo.sock for secuboxctl:
- internal/control/server.go: Unix socket server with command handling
- Commands: mesh.status, mesh.peers, mesh.topology, mesh.nodes
- Commands: node.info, node.rotate, telemetry.latest, ping
- JSON responses with proper error handling
- Graceful shutdown and socket cleanup

Expand secuboxctl CLI with new commands:
- mesh topology: Show mesh topology graph
- mesh nodes: List mesh nodes with ZKP status
- telemetry latest: Show system metrics

All commands tested and working on VM.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-25 08:19:37 +01:00

304 lines
7.8 KiB
Go

// SecuBox CLI Management Tool
// CyberMind — SecuBox-Deb — 2026
package main
import (
"encoding/json"
"fmt"
"net"
"os"
"github.com/spf13/cobra"
)
var socketPath = "/run/secuboxd/topo.sock"
func main() {
rootCmd := &cobra.Command{
Use: "secuboxctl",
Short: "SecuBox mesh management CLI",
Long: "Command-line interface for managing SecuBox mesh network",
}
// mesh subcommand
meshCmd := &cobra.Command{
Use: "mesh",
Short: "Mesh network operations",
}
meshStatusCmd := &cobra.Command{
Use: "status",
Short: "Show mesh network status",
RunE: meshStatus,
}
meshPeersCmd := &cobra.Command{
Use: "peers",
Short: "List mesh peers",
RunE: meshPeers,
}
meshTopologyCmd := &cobra.Command{
Use: "topology",
Short: "Show mesh topology",
RunE: meshTopology,
}
meshNodesCmd := &cobra.Command{
Use: "nodes",
Short: "List mesh nodes",
RunE: meshNodes,
}
meshCmd.AddCommand(meshStatusCmd, meshPeersCmd, meshTopologyCmd, meshNodesCmd)
// node subcommand
nodeCmd := &cobra.Command{
Use: "node",
Short: "Node operations",
}
nodeInfoCmd := &cobra.Command{
Use: "info",
Short: "Show node information",
RunE: nodeInfo,
}
nodeRotateCmd := &cobra.Command{
Use: "rotate",
Short: "Rotate ZKP keys",
RunE: nodeRotate,
}
nodeCmd.AddCommand(nodeInfoCmd, nodeRotateCmd)
// telemetry subcommand
telemetryCmd := &cobra.Command{
Use: "telemetry",
Short: "Telemetry operations",
}
telemetryLatestCmd := &cobra.Command{
Use: "latest",
Short: "Show latest telemetry data",
RunE: telemetryLatest,
}
telemetryCmd.AddCommand(telemetryLatestCmd)
// version command
versionCmd := &cobra.Command{
Use: "version",
Short: "Show version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("secuboxctl v0.1.0")
fmt.Println("CyberMind — SecuBox-Deb — 2026")
},
}
rootCmd.AddCommand(meshCmd, nodeCmd, telemetryCmd, versionCmd)
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
func sendCommand(cmd string) ([]byte, error) {
conn, err := net.Dial("unix", socketPath)
if err != nil {
return nil, fmt.Errorf("failed to connect to secuboxd: %w", err)
}
defer conn.Close()
if _, err := conn.Write([]byte(cmd + "\n")); err != nil {
return nil, fmt.Errorf("failed to send command: %w", err)
}
buf := make([]byte, 65536)
n, err := conn.Read(buf)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
return buf[:n], nil
}
func meshStatus(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("mesh.status")
if err != nil {
return err
}
var status map[string]interface{}
if err := json.Unmarshal(resp, &status); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
fmt.Println("Mesh Status:")
fmt.Printf(" State: %v\n", status["state"])
fmt.Printf(" Peers: %v\n", status["peer_count"])
fmt.Printf(" Role: %v\n", status["role"])
fmt.Printf(" Mesh Gate: %v\n", status["mesh_gate"])
fmt.Printf(" Uptime: %v\n", status["uptime"])
return nil
}
func meshPeers(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("mesh.peers")
if err != nil {
return err
}
var peers []map[string]interface{}
if err := json.Unmarshal(resp, &peers); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
fmt.Println("Mesh Peers:")
fmt.Printf("%-45s %-15s %-10s %s\n", "DID", "ADDRESS", "ROLE", "LAST SEEN")
fmt.Println("─────────────────────────────────────────────────────────────────────────────")
for _, peer := range peers {
fmt.Printf("%-45v %-15v %-10v %v\n",
peer["did"], peer["address"], peer["role"], peer["last_seen"])
}
return nil
}
func nodeInfo(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("node.info")
if err != nil {
return err
}
var info map[string]interface{}
if err := json.Unmarshal(resp, &info); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
fmt.Println("Node Information:")
fmt.Printf(" DID: %v\n", info["did"])
fmt.Printf(" Role: %v\n", info["role"])
fmt.Printf(" Public Key: %v\n", info["public_key"])
fmt.Printf(" Address: %v\n", info["address"])
fmt.Printf(" ZKP Valid: %v\n", info["zkp_valid"])
fmt.Printf(" ZKP Expiry: %v\n", info["zkp_expiry"])
return nil
}
func nodeRotate(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("node.rotate")
if err != nil {
return err
}
var result map[string]interface{}
if err := json.Unmarshal(resp, &result); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
if result["success"] == true {
fmt.Println("ZKP keys rotated successfully")
fmt.Printf(" New expiry: %v\n", result["new_expiry"])
} else {
fmt.Printf("Failed to rotate keys: %v\n", result["error"])
}
return nil
}
func meshTopology(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("mesh.topology")
if err != nil {
return err
}
var topo map[string]interface{}
if err := json.Unmarshal(resp, &topo); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
fmt.Println("Mesh Topology:")
fmt.Printf(" Mesh Gate: %v\n", topo["mesh_gate"])
if nodes, ok := topo["nodes"].([]interface{}); ok {
fmt.Printf("\nNodes (%d):\n", len(nodes))
fmt.Printf(" %-45s %-10s\n", "DID", "ROLE")
fmt.Println(" " + "─────────────────────────────────────────────────────────")
for _, n := range nodes {
if node, ok := n.(map[string]interface{}); ok {
fmt.Printf(" %-45v %-10v\n", node["id"], node["role"])
}
}
}
if edges, ok := topo["edges"].([]interface{}); ok && len(edges) > 0 {
fmt.Printf("\nEdges (%d):\n", len(edges))
for _, e := range edges {
if edge, ok := e.(map[string]interface{}); ok {
fmt.Printf(" %v -> %v\n", edge["from"], edge["to"])
}
}
}
return nil
}
func meshNodes(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("mesh.nodes")
if err != nil {
return err
}
var nodes []map[string]interface{}
if err := json.Unmarshal(resp, &nodes); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
fmt.Println("Mesh Nodes:")
fmt.Printf("%-45s %-15s %-10s %-8s %s\n", "DID", "ADDRESS", "ROLE", "ZKP", "LAST SEEN")
fmt.Println("─────────────────────────────────────────────────────────────────────────────────────────")
for _, node := range nodes {
zkp := "✗"
if node["zkp_valid"] == true {
zkp = "✓"
}
fmt.Printf("%-45v %-15v %-10v %-8s %v\n",
node["did"], node["address"], node["role"], zkp, node["last_seen"])
}
return nil
}
func telemetryLatest(cmd *cobra.Command, args []string) error {
resp, err := sendCommand("telemetry.latest")
if err != nil {
return err
}
var data map[string]interface{}
if err := json.Unmarshal(resp, &data); err != nil {
return fmt.Errorf("failed to parse response: %w", err)
}
if errMsg, ok := data["error"]; ok {
return fmt.Errorf("%v", errMsg)
}
fmt.Println("Latest Telemetry:")
fmt.Printf(" Timestamp: %v\n", data["timestamp"])
fmt.Printf(" Uptime: %v seconds\n", data["uptime"])
fmt.Printf(" Peer Count: %v\n", data["peer_count"])
fmt.Printf(" nftables Rules: %v\n", data["nftables_rules"])
fmt.Printf(" CrowdSec Bans: %v\n", data["crowdsec_bans"])
fmt.Printf(" CPU Usage: %.1f%%\n", data["cpu_percent"])
fmt.Printf(" Memory Usage: %.1f%%\n", data["memory_percent"])
fmt.Printf(" Disk Usage: %.1f%%\n", data["disk_percent"])
return nil
}