feat: Extract Wild Central as standalone Go service
Extract the Central networking functionality from wild-cloud/api into a standalone service. Wild Central manages DNS (dnsmasq), gateway (HAProxy), firewall (nftables), VPN (WireGuard), TLS (certbot), security (CrowdSec), and DDNS — all the network appliance concerns. All Cloud-specific code (instances, clusters, nodes, apps, backups, operations, kubectl/talosctl tooling) has been removed. The API struct and route registration contain only Central endpoints. Tests updated to match the new API signature. Builds and all tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
158
internal/nftables/manager_test.go
Normal file
158
internal/nftables/manager_test.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package nftables
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewManager_DefaultPath(t *testing.T) {
|
||||
m := NewManager("")
|
||||
if m.GetRulesPath() != defaultRulesPath {
|
||||
t.Errorf("got %q, want %q", m.GetRulesPath(), defaultRulesPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewManager_CustomPath(t *testing.T) {
|
||||
m := NewManager("/tmp/wild-cloud.nft")
|
||||
if m.GetRulesPath() != "/tmp/wild-cloud.nft" {
|
||||
t.Errorf("got %q, want /tmp/wild-cloud.nft", m.GetRulesPath())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortsToStr(t *testing.T) {
|
||||
cases := []struct {
|
||||
ports []int
|
||||
want string
|
||||
}{
|
||||
{[]int{80, 443, 8404}, "80, 443, 8404"},
|
||||
{[]int{443}, "443"},
|
||||
{[]int{}, ""},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := portsToStr(c.ports); got != c.want {
|
||||
t.Errorf("portsToStr(%v) = %q, want %q", c.ports, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_AlwaysIncludesStructure(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{80, 443}, nil, nil, "")
|
||||
|
||||
for _, want := range []string{
|
||||
"table inet wild-cloud",
|
||||
"set allowed_tcp_ports",
|
||||
"chain input",
|
||||
"type filter hook input priority filter; policy accept;",
|
||||
"iif \"lo\" accept",
|
||||
"ct state { established, related } accept",
|
||||
} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Errorf("expected %q in output, got:\n%s", want, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_WithPorts_IncludesElements(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{80, 443, 8404}, nil, nil, "")
|
||||
|
||||
if !strings.Contains(out, "elements = { 80, 443, 8404 }") {
|
||||
t.Errorf("expected elements line with ports, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_NoPorts_TCPSetHasNoElements(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{}, nil, nil, "")
|
||||
|
||||
// TCP set should have no elements when no ports given
|
||||
if strings.Contains(out, "allowed_tcp_ports") && strings.Contains(out, "elements") {
|
||||
// Check that the elements line is not inside the TCP block
|
||||
tcpBlock := out[strings.Index(out, "set allowed_tcp_ports"):]
|
||||
tcpBlock = tcpBlock[:strings.Index(tcpBlock, "}")+1]
|
||||
if strings.Contains(tcpBlock, "elements") {
|
||||
t.Errorf("expected no elements in allowed_tcp_ports block when no ports, got:\n%s", tcpBlock)
|
||||
}
|
||||
}
|
||||
// UDP set always has DNS/DHCP elements
|
||||
if !strings.Contains(out, "53, 67, 68") {
|
||||
t.Errorf("expected DNS/DHCP elements in allowed_udp_ports even with no TCP ports, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_ExtraPortsMerged(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{80, 443}, []int{22, 443}, nil, "") // 443 deduplicated
|
||||
|
||||
if !strings.Contains(out, "22") {
|
||||
t.Errorf("expected extra port 22 in output, got:\n%s", out)
|
||||
}
|
||||
// 443 should appear only once
|
||||
count := strings.Count(out, "443")
|
||||
if count != 1 {
|
||||
t.Errorf("expected 443 exactly once, got %d times in:\n%s", count, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_NoWANInterface_NoDropRules(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{80, 443}, nil, nil, "")
|
||||
|
||||
if strings.Contains(out, "drop") {
|
||||
t.Errorf("expected no drop rules without WAN interface, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_WithWANInterface_IncludesDropRules(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{80, 443}, nil, nil, "eth0")
|
||||
|
||||
if !strings.Contains(out, `iif "eth0"`) {
|
||||
t.Errorf("expected WAN interface in rules, got:\n%s", out)
|
||||
}
|
||||
if !strings.Contains(out, "drop") {
|
||||
t.Errorf("expected drop rule with WAN interface, got:\n%s", out)
|
||||
}
|
||||
if !strings.Contains(out, "@allowed_tcp_ports") {
|
||||
t.Errorf("expected reference to allowed_tcp_ports set, got:\n%s", out)
|
||||
}
|
||||
if !strings.Contains(out, "@allowed_udp_ports") {
|
||||
t.Errorf("expected reference to allowed_udp_ports set, got:\n%s", out)
|
||||
}
|
||||
// DNS and DHCP UDP ports should be in the allowed_udp_ports set
|
||||
if !strings.Contains(out, "53, 67, 68") {
|
||||
t.Errorf("expected DNS/DHCP UDP ports in allowed_udp_ports set, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_AlwaysIncludesUDPSet(t *testing.T) {
|
||||
m := NewManager("")
|
||||
// No WAN interface — permissive mode, but UDP set should still be visible
|
||||
out := m.Generate([]int{80, 443}, nil, []int{51820}, "")
|
||||
|
||||
if !strings.Contains(out, "set allowed_udp_ports") {
|
||||
t.Errorf("expected allowed_udp_ports set even without WAN interface, got:\n%s", out)
|
||||
}
|
||||
if !strings.Contains(out, "51820") {
|
||||
t.Errorf("expected extra UDP port 51820 in allowed_udp_ports set, got:\n%s", out)
|
||||
}
|
||||
// No drop rules without WAN interface
|
||||
if strings.Contains(out, "drop") {
|
||||
t.Errorf("expected no drop rules without WAN interface, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate_ExtraUDPPorts(t *testing.T) {
|
||||
m := NewManager("")
|
||||
out := m.Generate([]int{80, 443}, nil, []int{5353}, "eth0")
|
||||
|
||||
// User UDP port should appear in the UDP exception list
|
||||
if !strings.Contains(out, "5353") {
|
||||
t.Errorf("expected extra UDP port 5353 in output, got:\n%s", out)
|
||||
}
|
||||
// Hardcoded DNS/DHCP should still be there
|
||||
if !strings.Contains(out, "53, 67, 68") {
|
||||
t.Errorf("expected DNS/DHCP UDP ports still present, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user