cli/internal/cmd/unifi/cmd_routes.go
Snider 3993d0583e Secure SSH and TLS connections, and fix CI issues
Addresses security concerns from OWASP audit and CodeQL by enforcing strict
host key verification and TLS certificate verification.

Security Changes:
- Enforced strict SSH host key checking in pkg/container and devops.
- Removed insecure SSH host key verification from pkg/ansible.
- Added synchronous host key discovery during VM boot using ssh-keyscan.
- Updated UniFi client to enforce TLS certificate verification by default.
- Added --insecure flag and config option for UniFi to allow opt-in to
  skipping TLS verification for self-signed certificates.

CI and Maintenance:
- Fixed auto-merge workflow by providing repository context to 'gh' command.
- Resolved merge conflicts in .github/workflows/auto-merge.yml.
- Added unit tests for secured Ansible SSH client.
- Fixed formatting issues identified by QA checks.
2026-02-05 03:48:42 +00:00

86 lines
1.9 KiB
Go

package unifi
import (
"fmt"
"github.com/host-uk/core/pkg/cli"
"github.com/host-uk/core/pkg/log"
uf "github.com/host-uk/core/pkg/unifi"
)
// Routes command flags.
var (
routesSite string
routesType string
)
// addRoutesCommand adds the 'routes' subcommand for listing the gateway routing table.
func addRoutesCommand(parent *cli.Command) {
cmd := &cli.Command{
Use: "routes",
Short: "List gateway routing table",
Long: "List the active routing table from the UniFi gateway, showing network segments and next-hop destinations.",
RunE: func(cmd *cli.Command, args []string) error {
return runRoutes()
},
}
cmd.Flags().StringVar(&routesSite, "site", "", "Site name (default: \"default\")")
cmd.Flags().StringVar(&routesType, "type", "", "Filter by route type (static, connected, kernel, bgp, ospf)")
parent.AddCommand(cmd)
}
func runRoutes() error {
client, err := uf.NewFromConfig("", "", "", "", false)
if err != nil {
return log.E("unifi.routes", "failed to initialise client", err)
}
routes, err := client.GetRoutes(routesSite)
if err != nil {
return log.E("unifi.routes", "failed to fetch routes", err)
}
// Filter by type if requested
if routesType != "" {
var filtered []uf.Route
for _, r := range routes {
if uf.RouteTypeName(r.Type) == routesType || r.Type == routesType {
filtered = append(filtered, r)
}
}
routes = filtered
}
if len(routes) == 0 {
cli.Text("No routes found.")
return nil
}
table := cli.NewTable("Network", "Next Hop", "Interface", "Type", "Distance", "FIB")
for _, r := range routes {
typeName := uf.RouteTypeName(r.Type)
fib := dimStyle.Render("no")
if r.Selected {
fib = successStyle.Render("yes")
}
table.AddRow(
valueStyle.Render(r.Network),
r.NextHop,
dimStyle.Render(r.Interface),
dimStyle.Render(typeName),
fmt.Sprintf("%d", r.Distance),
fib,
)
}
cli.Blank()
cli.Print(" %d routes\n\n", len(routes))
table.Render()
return nil
}