diff --git a/internal/db/migrate.go b/internal/db/migrate.go index 87a31a7..eb475ec 100644 --- a/internal/db/migrate.go +++ b/internal/db/migrate.go @@ -38,6 +38,34 @@ CREATE TABLE IF NOT EXISTS records ( CREATE INDEX IF NOT EXISTS idx_records_zone_name ON records(zone_id, name);`, }, + { + Version: 2, + Name: "seed zones and records from CoreDNS zone files", + SQL: ` +-- Zone: svc.mcp.metacircular.net (service addresses) +INSERT INTO zones (id, name, primary_ns, admin_email, refresh, retry, expire, minimum_ttl, serial) +VALUES (1, 'svc.mcp.metacircular.net', 'ns.mcp.metacircular.net.', 'admin.metacircular.net.', 3600, 600, 86400, 300, 2026032601); + +-- Zone: mcp.metacircular.net (node addresses) +INSERT INTO zones (id, name, primary_ns, admin_email, refresh, retry, expire, minimum_ttl, serial) +VALUES (2, 'mcp.metacircular.net', 'ns.mcp.metacircular.net.', 'admin.metacircular.net.', 3600, 600, 86400, 300, 2026032501); + +-- svc.mcp.metacircular.net records +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'metacrypt', 'A', '192.168.88.181', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'metacrypt', 'A', '100.95.252.120', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcr', 'A', '192.168.88.181', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcr', 'A', '100.95.252.120', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'sgard', 'A', '192.168.88.181', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'sgard', 'A', '100.95.252.120', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcp-agent', 'A', '192.168.88.181', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcp-agent', 'A', '100.95.252.120', 300); + +-- mcp.metacircular.net records +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'rift', 'A', '192.168.88.181', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'rift', 'A', '100.95.252.120', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'ns', 'A', '192.168.88.181', 300); +INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'ns', 'A', '100.95.252.120', 300);`, + }, } // Migrate applies all pending migrations. diff --git a/internal/db/records_test.go b/internal/db/records_test.go index a5c7f1a..af417e7 100644 --- a/internal/db/records_test.go +++ b/internal/db/records_test.go @@ -7,7 +7,7 @@ import ( func createTestZone(t *testing.T, db *DB) *Zone { t.Helper() - zone, err := db.CreateZone("svc.mcp.metacircular.net", "ns.mcp.metacircular.net.", "admin.metacircular.net.", 3600, 600, 86400, 300) + zone, err := db.CreateZone("test.example.com", "ns.example.com.", "admin.example.com.", 3600, 600, 86400, 300) if err != nil { t.Fatalf("create zone: %v", err) } @@ -18,7 +18,7 @@ func TestCreateRecordA(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record: %v", err) } @@ -37,7 +37,7 @@ func TestCreateRecordAAAA(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "AAAA", "2001:db8::1", 300) + record, err := db.CreateRecord("test.example.com", "metacrypt", "AAAA", "2001:db8::1", 300) if err != nil { t.Fatalf("create record: %v", err) } @@ -50,7 +50,7 @@ func TestCreateRecordCNAME(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - record, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net.", 300) + record, err := db.CreateRecord("test.example.com", "alias", "CNAME", "rift.mcp.metacircular.net.", 300) if err != nil { t.Fatalf("create record: %v", err) } @@ -63,7 +63,7 @@ func TestCreateRecordInvalidIP(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - _, err := db.CreateRecord("svc.mcp.metacircular.net", "bad", "A", "not-an-ip", 300) + _, err := db.CreateRecord("test.example.com", "bad", "A", "not-an-ip", 300) if err == nil { t.Fatal("expected error for invalid IPv4") } @@ -74,13 +74,13 @@ func TestCreateRecordCNAMEExclusivity(t *testing.T) { createTestZone(t, db) // Create an A record first. - _, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + _, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create A record: %v", err) } // Trying to add a CNAME for the same name should fail. - _, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "CNAME", "rift.mcp.metacircular.net.", 300) + _, err = db.CreateRecord("test.example.com", "metacrypt", "CNAME", "rift.mcp.metacircular.net.", 300) if !errors.Is(err, ErrConflict) { t.Fatalf("expected ErrConflict, got %v", err) } @@ -91,13 +91,13 @@ func TestCreateRecordCNAMEExclusivityReverse(t *testing.T) { createTestZone(t, db) // Create a CNAME record first. - _, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net.", 300) + _, err := db.CreateRecord("test.example.com", "alias", "CNAME", "rift.mcp.metacircular.net.", 300) if err != nil { t.Fatalf("create CNAME record: %v", err) } // Trying to add an A record for the same name should fail. - _, err = db.CreateRecord("svc.mcp.metacircular.net", "alias", "A", "192.168.88.181", 300) + _, err = db.CreateRecord("test.example.com", "alias", "A", "192.168.88.181", 300) if !errors.Is(err, ErrConflict) { t.Fatalf("expected ErrConflict, got %v", err) } @@ -108,12 +108,12 @@ func TestCreateRecordBumpsSerial(t *testing.T) { zone := createTestZone(t, db) originalSerial := zone.Serial - _, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + _, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record: %v", err) } - updated, err := db.GetZone("svc.mcp.metacircular.net") + updated, err := db.GetZone("test.example.com") if err != nil { t.Fatalf("get zone: %v", err) } @@ -126,21 +126,21 @@ func TestListRecords(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - _, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + _, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record 1: %v", err) } - _, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300) + _, err = db.CreateRecord("test.example.com", "metacrypt", "A", "100.95.252.120", 300) if err != nil { t.Fatalf("create record 2: %v", err) } - _, err = db.CreateRecord("svc.mcp.metacircular.net", "mcr", "A", "192.168.88.181", 300) + _, err = db.CreateRecord("test.example.com", "mcr", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record 3: %v", err) } // List all records. - records, err := db.ListRecords("svc.mcp.metacircular.net", "", "") + records, err := db.ListRecords("test.example.com", "", "") if err != nil { t.Fatalf("list records: %v", err) } @@ -149,7 +149,7 @@ func TestListRecords(t *testing.T) { } // Filter by name. - records, err = db.ListRecords("svc.mcp.metacircular.net", "metacrypt", "") + records, err = db.ListRecords("test.example.com", "metacrypt", "") if err != nil { t.Fatalf("list records by name: %v", err) } @@ -158,7 +158,7 @@ func TestListRecords(t *testing.T) { } // Filter by type. - records, err = db.ListRecords("svc.mcp.metacircular.net", "", "A") + records, err = db.ListRecords("test.example.com", "", "A") if err != nil { t.Fatalf("list records by type: %v", err) } @@ -171,7 +171,7 @@ func TestUpdateRecord(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record: %v", err) } @@ -192,7 +192,7 @@ func TestDeleteRecord(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record: %v", err) } @@ -211,12 +211,12 @@ func TestDeleteRecordBumpsSerial(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record: %v", err) } - zone, err := db.GetZone("svc.mcp.metacircular.net") + zone, err := db.GetZone("test.example.com") if err != nil { t.Fatalf("get zone: %v", err) } @@ -226,7 +226,7 @@ func TestDeleteRecordBumpsSerial(t *testing.T) { t.Fatalf("delete record: %v", err) } - zone, err = db.GetZone("svc.mcp.metacircular.net") + zone, err = db.GetZone("test.example.com") if err != nil { t.Fatalf("get zone after delete: %v", err) } @@ -239,12 +239,12 @@ func TestLookupRecords(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - _, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + _, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create record: %v", err) } - records, err := db.LookupRecords("svc.mcp.metacircular.net", "metacrypt", "A") + records, err := db.LookupRecords("test.example.com", "metacrypt", "A") if err != nil { t.Fatalf("lookup records: %v", err) } @@ -260,7 +260,7 @@ func TestCreateRecordCNAMEMissingDot(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - _, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net", 300) + _, err := db.CreateRecord("test.example.com", "alias", "CNAME", "rift.mcp.metacircular.net", 300) if err == nil { t.Fatal("expected error for CNAME without trailing dot") } @@ -270,16 +270,16 @@ func TestMultipleARecords(t *testing.T) { db := openTestDB(t) createTestZone(t, db) - _, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + _, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create first A record: %v", err) } - _, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300) + _, err = db.CreateRecord("test.example.com", "metacrypt", "A", "100.95.252.120", 300) if err != nil { t.Fatalf("create second A record: %v", err) } - records, err := db.LookupRecords("svc.mcp.metacircular.net", "metacrypt", "A") + records, err := db.LookupRecords("test.example.com", "metacrypt", "A") if err != nil { t.Fatalf("lookup records: %v", err) } diff --git a/internal/db/zones_test.go b/internal/db/zones_test.go index 7a69546..e50c7f6 100644 --- a/internal/db/zones_test.go +++ b/internal/db/zones_test.go @@ -79,8 +79,9 @@ func TestListZones(t *testing.T) { if err != nil { t.Fatalf("list zones: %v", err) } - if len(zones) != 2 { - t.Fatalf("got %d zones, want 2", len(zones)) + // 2 seed zones + 2 created = 4 total. Verify ours are present and ordered. + if len(zones) != 4 { + t.Fatalf("got %d zones, want 4", len(zones)) } if zones[0].Name != "a.example.com" { t.Fatalf("zones should be ordered by name, got %q first", zones[0].Name) diff --git a/internal/dns/server_test.go b/internal/dns/server_test.go index feb9511..b8076ba 100644 --- a/internal/dns/server_test.go +++ b/internal/dns/server_test.go @@ -29,23 +29,23 @@ func setupTestServer(t *testing.T) (*Server, *db.DB) { database := openTestDB(t) logger := slog.Default() - _, err := database.CreateZone("svc.mcp.metacircular.net", "ns.mcp.metacircular.net.", "admin.metacircular.net.", 3600, 600, 86400, 300) + _, err := database.CreateZone("test.example.com", "ns.example.com.", "admin.example.com.", 3600, 600, 86400, 300) if err != nil { t.Fatalf("create zone: %v", err) } - _, err = database.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300) + _, err = database.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300) if err != nil { t.Fatalf("create A record: %v", err) } - _, err = database.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300) + _, err = database.CreateRecord("test.example.com", "metacrypt", "A", "100.95.252.120", 300) if err != nil { t.Fatalf("create A record 2: %v", err) } - _, err = database.CreateRecord("svc.mcp.metacircular.net", "mcr", "AAAA", "2001:db8::1", 300) + _, err = database.CreateRecord("test.example.com", "mcr", "AAAA", "2001:db8::1", 300) if err != nil { t.Fatalf("create AAAA record: %v", err) } - _, err = database.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "metacrypt.svc.mcp.metacircular.net.", 300) + _, err = database.CreateRecord("test.example.com", "alias", "CNAME", "metacrypt.test.example.com.", 300) if err != nil { t.Fatalf("create CNAME record: %v", err) } @@ -57,12 +57,12 @@ func setupTestServer(t *testing.T) (*Server, *db.DB) { func TestFindZone(t *testing.T) { srv, _ := setupTestServer(t) - zone := srv.findZone("metacrypt.svc.mcp.metacircular.net.") + zone := srv.findZone("metacrypt.test.example.com.") if zone == nil { t.Fatal("expected to find zone") } - if zone.Name != "svc.mcp.metacircular.net" { - t.Fatalf("got zone %q, want %q", zone.Name, "svc.mcp.metacircular.net") + if zone.Name != "test.example.com" { + t.Fatalf("got zone %q, want %q", zone.Name, "test.example.com") } zone = srv.findZone("nonexistent.com.") @@ -73,17 +73,17 @@ func TestFindZone(t *testing.T) { func TestBuildSOA(t *testing.T) { srv, database := setupTestServer(t) - zone, err := database.GetZone("svc.mcp.metacircular.net") + zone, err := database.GetZone("test.example.com") if err != nil { t.Fatalf("get zone: %v", err) } soa := srv.buildSOA(zone) - if soa.Ns != "ns.mcp.metacircular.net." { - t.Fatalf("got ns %q, want %q", soa.Ns, "ns.mcp.metacircular.net.") + if soa.Ns != "ns.example.com." { + t.Fatalf("got ns %q, want %q", soa.Ns, "ns.example.com.") } - if soa.Hdr.Name != "svc.mcp.metacircular.net." { - t.Fatalf("got name %q, want %q", soa.Hdr.Name, "svc.mcp.metacircular.net.") + if soa.Hdr.Name != "test.example.com." { + t.Fatalf("got name %q, want %q", soa.Hdr.Name, "test.example.com.") } } @@ -91,7 +91,7 @@ func TestRecordToRR_A(t *testing.T) { srv, _ := setupTestServer(t) rec := db.Record{Name: "metacrypt", Type: "A", Value: "192.168.88.181", TTL: 300} - rr := srv.recordToRR("metacrypt.svc.mcp.metacircular.net.", rec) + rr := srv.recordToRR("metacrypt.test.example.com.", rec) if rr == nil { t.Fatal("expected non-nil RR") } @@ -109,7 +109,7 @@ func TestRecordToRR_AAAA(t *testing.T) { srv, _ := setupTestServer(t) rec := db.Record{Name: "mcr", Type: "AAAA", Value: "2001:db8::1", TTL: 300} - rr := srv.recordToRR("mcr.svc.mcp.metacircular.net.", rec) + rr := srv.recordToRR("mcr.test.example.com.", rec) if rr == nil { t.Fatal("expected non-nil RR") } @@ -126,8 +126,8 @@ func TestRecordToRR_AAAA(t *testing.T) { func TestRecordToRR_CNAME(t *testing.T) { srv, _ := setupTestServer(t) - rec := db.Record{Name: "alias", Type: "CNAME", Value: "metacrypt.svc.mcp.metacircular.net.", TTL: 300} - rr := srv.recordToRR("alias.svc.mcp.metacircular.net.", rec) + rec := db.Record{Name: "alias", Type: "CNAME", Value: "metacrypt.test.example.com.", TTL: 300} + rr := srv.recordToRR("alias.test.example.com.", rec) if rr == nil { t.Fatal("expected non-nil RR") } @@ -136,7 +136,7 @@ func TestRecordToRR_CNAME(t *testing.T) { if !ok { t.Fatalf("expected *dns.CNAME, got %T", rr) } - if cname.Target != "metacrypt.svc.mcp.metacircular.net." { - t.Fatalf("got target %q, want %q", cname.Target, "metacrypt.svc.mcp.metacircular.net.") + if cname.Target != "metacrypt.test.example.com." { + t.Fatalf("got target %q, want %q", cname.Target, "metacrypt.test.example.com.") } }