Add the Hammerhead control plane

Dashboard and API, accounts (organizations, roles, invitations, 2FA, OIDC
single sign-on, API keys, revocable sessions), an encrypted SQLite database,
resource logins, alerts and /metrics, mail egress management with DKIM keys,
and the .env loader. Split out of the original single repository; depends on
Reef for the shared types. The end-to-end tests that run Hammerhead, Blacktip
and Bamboo together live in e2e/.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
VeillaxandClaude Sonnet 5.5 committed 2026-10-26 02:50:03 -06:00
1 parent 3daa368233
commit f521fa8668
35 files changed
+10392 -1

No files matched your search

+216
View File
@@ -0,0 +1,216 @@
package e2e
import (
"fmt"
"net"
"strconv"
"strings"
"testing"
"time"
"git.veillax.com/Veillax/blacktip"
"git.veillax.com/Veillax/reef/model"
)
// freeRun finds n consecutive ports that are free for both TCP and UDP.
func freeRun(t *testing.T, n int) int {
t.Helper()
for try := 0; try < 200; try++ {
base := 20000 + (time.Now().Nanosecond()/1000+try*37)%30000
var closers []func()
ok := true
for i := 0; i < n && ok; i++ {
l, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(base+i))
if err != nil {
ok = false
break
}
closers = append(closers, func() { l.Close() })
pc, err := net.ListenPacket("udp", "127.0.0.1:"+strconv.Itoa(base+i))
if err != nil {
ok = false
break
}
closers = append(closers, func() { pc.Close() })
}
for _, c := range closers {
c()
}
if ok {
return base
}
}
t.Fatal("no free port block")
return 0
}
func tcpOn(t *testing.T, port int) {
l, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(port))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { l.Close() })
go func() {
for {
c, err := l.Accept()
if err != nil {
return
}
go func() {
defer c.Close()
buf := make([]byte, 64)
n, _ := c.Read(buf)
fmt.Fprintf(c, "tcp%d:%s", port, buf[:n])
}()
}
}()
}
func udpOn(t *testing.T, port int) {
pc, err := net.ListenPacket("udp", "127.0.0.1:"+strconv.Itoa(port))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { pc.Close() })
go func() {
buf := make([]byte, 64)
for {
n, from, err := pc.ReadFrom(buf)
if err != nil {
return
}
pc.WriteTo([]byte(fmt.Sprintf("udp%d:%s", port, buf[:n])), from)
}
}()
}
func TestPortRanges(t *testing.T) {
w := setup(t, blacktip.TraefikConfig{})
target := freeRun(t, 3)
pub := freeRun(t, 3)
if target == pub {
pub = freeRun(t, 4) + 0
}
for i := 0; i < 3; i++ {
tcpOn(t, target+i)
udpOn(t, target+i)
}
base := "/api/orgs/" + w.org + "/mappings"
open := func(proto, ip string, site string, port, end, tport int) (model.Mapping, int, string) {
var m model.Mapping
code, raw := w.admin.do("POST", base, map[string]any{"proto": proto, "edgeId": w.edge, "bindIp": ip, "port": port, "portEnd": end,
"targets": tgt(site, tport), "enabled": true}, &m)
return m, code, raw
}
tcp, code, raw := open("tcp", "127.0.0.1", w.site, pub, pub+2, target)
if code != 200 {
t.Fatalf("open range: %d %s", code, raw)
}
if _, code, raw = open("udp", "127.0.0.1", w.site, pub, pub+2, target); code != 200 {
t.Fatalf("a udp range over the same numbers is a different protocol and must be allowed: %d %s", code, raw)
}
if _, code, raw = open("tcp", "127.0.0.2", w.local, pub, pub+2, target); code != 200 {
t.Fatalf("local range: %d %s", code, raw)
}
if tcp.PortEnd != pub+2 {
t.Errorf("portEnd = %d, want %d", tcp.PortEnd, pub+2)
}
// each public port reaches the target port at the same offset, through the tunnel and directly
for _, ip := range []string{"127.0.0.1", "127.0.0.2"} {
for i := 0; i < 3; i++ {
got := tcpAsk(t, ip+":"+strconv.Itoa(pub+i), "hi")
if want := fmt.Sprintf("tcp%d:hi", target+i); got != want {
t.Errorf("%s port %d -> %q, want %q", ip, pub+i, got, want)
}
}
}
for i := 0; i < 3; i++ {
got := udpAsk(t, "127.0.0.1:"+strconv.Itoa(pub+i), "yo")
if want := fmt.Sprintf("udp%d:yo", target+i); got != want {
t.Errorf("udp port %d -> %q, want %q", pub+i, got, want)
}
}
// shrinking the range closes the ports that fell off the end
if code, raw := w.admin.do("PUT", base+"/"+tcp.ID, map[string]any{"proto": "tcp", "edgeId": w.edge, "bindIp": "127.0.0.1", "port": pub, "portEnd": pub + 1,
"targets": tgt(w.site, target), "enabled": true}, nil); code != 200 {
t.Fatalf("shrink: %d %s", code, raw)
}
deadline := time.Now().Add(6 * time.Second)
for {
c, err := net.DialTimeout("tcp", "127.0.0.1:"+strconv.Itoa(pub+2), 500*time.Millisecond)
if err != nil {
break
}
c.Close()
if time.Now().After(deadline) {
t.Fatal("a port past the end of the range stayed open")
}
time.Sleep(200 * time.Millisecond)
}
if got := tcpAsk(t, "127.0.0.1:"+strconv.Itoa(pub+1), "x"); got != fmt.Sprintf("tcp%d:x", target+1) {
t.Errorf("a port still inside the range: %q", got)
}
// validation
bad := func(what, proto string, port, end, tport int) {
t.Helper()
if _, code, raw := open(proto, "127.0.0.9", w.site, port, end, tport); code != 400 {
t.Errorf("%s was accepted (%d %s)", what, code, raw)
}
}
bad("a range on http", "http", 8080, 8082, 80)
bad("an end before the start", "tcp", 5000, 4990, 80)
bad("a range of 1001 ports", "tcp", 10000, 11000, 80)
bad("a range past 65535", "tcp", 65530, 65540, 80)
bad("targets that would run past 65535", "tcp", 5000, 5009, 65530)
if _, code, _ := open("tcp", "127.0.0.1", w.site, pub+1, pub+1, target); code != 400 {
t.Error("a single port inside an existing range must conflict")
}
if _, code, _ := open("tcp", "127.0.0.1", w.site, pub-1, pub, target); code != 400 {
t.Error("a range overlapping the start of an existing range must conflict")
}
if _, code, raw := open("tcp", "127.0.0.1", w.site, pub+2, pub+4, target); code != 200 {
t.Errorf("a range that starts right after the existing one is fine: %d %s", code, raw)
}
// one busy port inside a range is reported, and the others still work
busyBase := freeRun(t, 3)
busy, err := net.Listen("tcp", "127.0.0.3:"+strconv.Itoa(busyBase+1))
if err != nil {
t.Fatal(err)
}
defer busy.Close()
bm, code, raw := open("tcp", "127.0.0.3", w.local, busyBase, busyBase+2, target)
if code != 200 {
t.Fatalf("open busy range: %d %s", code, raw)
}
if got := tcpAsk(t, "127.0.0.3:"+strconv.Itoa(busyBase), "a"); got != fmt.Sprintf("tcp%d:a", target) {
t.Errorf("a free port next to a busy one: %q", got)
}
deadline = time.Now().Add(8 * time.Second)
for {
var st struct {
Mappings []struct {
ID string
Status model.MappingStatus
}
}
w.admin.must("GET", "/api/orgs/"+w.org+"/state", nil, &st)
msg := ""
for _, m := range st.Mappings {
if m.ID == bm.ID {
msg = m.Status.Error
}
}
if strings.Contains(msg, strconv.Itoa(busyBase+1)) {
break
}
if time.Now().After(deadline) {
t.Fatalf("the busy port isn't named in the status: %q", msg)
}
time.Sleep(250 * time.Millisecond)
}
}