Add --bind-conf flag for BIND domains.conf generation
Generate a BIND-format domains.conf file alongside catalog zones. New input properties: file= (zone data path) and dnssec (bare flag). When --bind-conf is set, every zone must have file= or it errors. Renames ZoneEntry.File to ZonesFile (input path for error messages) and adds ZoneFile (BIND file path) and DNSSEC (bool) fields.
This commit is contained in:
138
bindconf_test.go
Normal file
138
bindconf_test.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateBindConf(t *testing.T) {
|
||||
entries := []ZoneEntry{
|
||||
{Zone: "bitcard.org.", ZoneFile: "data/misc/bitcard.org", DNSSEC: true, ZonesFile: "test", Line: 1},
|
||||
{Zone: "askask.com.", ZoneFile: "data/ask/askask.com", ZonesFile: "test", Line: 2},
|
||||
}
|
||||
|
||||
got := generateBindConf(entries)
|
||||
|
||||
// Header
|
||||
assertContains(t, got, "# THIS FILE IS GENERATED BY catalog-zone-gen")
|
||||
assertContains(t, got, "#=============================================")
|
||||
|
||||
// Zones should be sorted alphabetically (askask.com before bitcard.org)
|
||||
askIdx := strings.Index(got, "askask.com")
|
||||
bitIdx := strings.Index(got, "bitcard.org")
|
||||
if askIdx == -1 || bitIdx == -1 {
|
||||
t.Fatal("expected both zones in output")
|
||||
}
|
||||
if askIdx >= bitIdx {
|
||||
t.Error("expected askask.com before bitcard.org (alphabetical sort)")
|
||||
}
|
||||
|
||||
// Non-DNSSEC zone
|
||||
assertContains(t, got, `zone "askask.com" {`)
|
||||
assertContains(t, got, ` type master;`)
|
||||
assertContains(t, got, ` file "data/ask/askask.com";`)
|
||||
|
||||
// DNSSEC zone has directives on file line
|
||||
assertContains(t, got, ` file "data/misc/bitcard.org"; dnssec-policy standard; inline-signing yes;`)
|
||||
|
||||
// No trailing dot in zone name
|
||||
if strings.Contains(got, `zone "askask.com."`) {
|
||||
t.Error("zone name should not have trailing dot in BIND config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateBindConfEmpty(t *testing.T) {
|
||||
got := generateBindConf(nil)
|
||||
// Should just have the header
|
||||
lines := splitLines(got)
|
||||
if len(lines) != 3 {
|
||||
t.Errorf("expected 3 header lines for empty input, got %d", len(lines))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateBindConfNoDNSSEC(t *testing.T) {
|
||||
entries := []ZoneEntry{
|
||||
{Zone: "example.com.", ZoneFile: "data/example.com", ZonesFile: "test", Line: 1},
|
||||
}
|
||||
|
||||
got := generateBindConf(entries)
|
||||
|
||||
if strings.Contains(got, "dnssec-policy") {
|
||||
t.Error("non-DNSSEC zone should not have dnssec-policy")
|
||||
}
|
||||
if strings.Contains(got, "inline-signing") {
|
||||
t.Error("non-DNSSEC zone should not have inline-signing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateBindConf(t *testing.T) {
|
||||
t.Run("all zones have file", func(t *testing.T) {
|
||||
entries := []ZoneEntry{
|
||||
{Zone: "a.example.com.", ZoneFile: "data/a", ZonesFile: "zones.txt", Line: 1},
|
||||
{Zone: "b.example.com.", ZoneFile: "data/b", ZonesFile: "zones.txt", Line: 2},
|
||||
}
|
||||
if err := validateBindConf(entries); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missing file", func(t *testing.T) {
|
||||
entries := []ZoneEntry{
|
||||
{Zone: "a.example.com.", ZoneFile: "data/a", ZonesFile: "zones.txt", Line: 1},
|
||||
{Zone: "b.example.com.", ZoneFile: "", ZonesFile: "zones.txt", Line: 3},
|
||||
}
|
||||
err := validateBindConf(entries)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing file")
|
||||
}
|
||||
assertContains(t, err.Error(), "zones.txt:3:")
|
||||
assertContains(t, err.Error(), "b.example.com.")
|
||||
assertContains(t, err.Error(), "missing file=")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteBindConf(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "domains.conf")
|
||||
|
||||
entries := []ZoneEntry{
|
||||
{Zone: "example.com.", ZoneFile: "data/example.com", ZonesFile: "test", Line: 1},
|
||||
{Zone: "example.org.", ZoneFile: "data/example.org", DNSSEC: true, ZonesFile: "test", Line: 2},
|
||||
}
|
||||
|
||||
if err := writeBindConf(path, entries); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := string(data)
|
||||
|
||||
assertContains(t, got, `zone "example.com"`)
|
||||
assertContains(t, got, `zone "example.org"`)
|
||||
assertContains(t, got, "dnssec-policy standard")
|
||||
}
|
||||
|
||||
func TestWriteBindConfValidationError(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "domains.conf")
|
||||
|
||||
entries := []ZoneEntry{
|
||||
{Zone: "example.com.", ZoneFile: "", ZonesFile: "zones.txt", Line: 5},
|
||||
}
|
||||
|
||||
err := writeBindConf(path, entries)
|
||||
if err == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
assertContains(t, err.Error(), "zones.txt:5:")
|
||||
|
||||
// File should not have been written
|
||||
if _, statErr := os.Stat(path); statErr == nil {
|
||||
t.Error("file should not be written when validation fails")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user