From d60513fd515f21dbce8ebc5cf2686602107c41d7 Mon Sep 17 00:00:00 2001 From: Matteo Contrini Date: Wed, 4 Feb 2026 20:29:21 +0100 Subject: [PATCH 1/6] Add support for Bunny DNS PullZone (PZ) record type --- integrationTest/helpers_integration_test.go | 4 ++-- providers/bunnydns/api.go | 2 +- providers/bunnydns/convert.go | 8 ++++---- providers/bunnydns/convert_test.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/integrationTest/helpers_integration_test.go b/integrationTest/helpers_integration_test.go index 4b2d4055d5..e0684858b7 100644 --- a/integrationTest/helpers_integration_test.go +++ b/integrationTest/helpers_integration_test.go @@ -411,8 +411,8 @@ func cfWorkerRoute(pattern, target string) *models.RecordConfig { return r } -func bunnyPullZone(name, pullZoneId string) *models.RecordConfig { - return makeRec(name, pullZoneId, "BUNNY_DNS_PZ") +func bunnyPullZone(name, pullZoneID string) *models.RecordConfig { + return makeRec(name, pullZoneID, "BUNNY_DNS_PZ") } func cfRedir(pattern, target string) *models.RecordConfig { diff --git a/providers/bunnydns/api.go b/providers/bunnydns/api.go index 537b0f71bc..561aa9654e 100644 --- a/providers/bunnydns/api.go +++ b/providers/bunnydns/api.go @@ -42,7 +42,7 @@ type record struct { Weight uint16 `json:"Weight"` Port uint16 `json:"Port"` Tag string `json:"Tag"` - PullZoneId int64 `json:"PullZoneId,omitempty"` + PullZoneID int64 `json:"PullZoneId,omitempty"` LinkName string `json:"LinkName,omitempty"` } diff --git a/providers/bunnydns/convert.go b/providers/bunnydns/convert.go index 042747468f..269f896008 100644 --- a/providers/bunnydns/convert.go +++ b/providers/bunnydns/convert.go @@ -40,13 +40,13 @@ func fromRecordConfig(rc *models.RecordConfig) (*record, error) { case recordTypeTLSA: r.Value = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) case recordTypePullZone: - // When creating Pull Zone records, the API expects an integer PullZoneId field, + // When creating Pull Zone records, the API expects an integer PullZoneID field, // while the Value field should be empty. - pullZoneId, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) + pullZoneID, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) if err != nil { return nil, fmt.Errorf("invalid Pull Zone ID for BUNNY_DNS_PZ: %w", err) } - r.PullZoneId = pullZoneId + r.PullZoneID = pullZoneID r.Value = "" } @@ -95,7 +95,7 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { var err error switch rc.Type { case "BUNNY_DNS_PZ": - // When reading Pull Zone records, the API provides the PullZoneId in the LinkName field as string. + // When reading Pull Zone records, the API provides the PullZoneID in the LinkName field as string. if r.LinkName == "" { return nil, fmt.Errorf("missing Pull Zone ID (LinkName) for BUNNY_DNS_PZ") } diff --git a/providers/bunnydns/convert_test.go b/providers/bunnydns/convert_test.go index 505b237075..d16fa5356d 100644 --- a/providers/bunnydns/convert_test.go +++ b/providers/bunnydns/convert_test.go @@ -17,8 +17,8 @@ func TestFromRecordConfigPullZone(t *testing.T) { if err != nil { t.Fatalf("fromRecordConfig returned error: %v", err) } - if rec.PullZoneId != 12345 { - t.Fatalf("expected PullZoneId=12345; got=%d", rec.PullZoneId) + if rec.PullZoneID != 12345 { + t.Fatalf("expected PullZoneID=12345; got=%d", rec.PullZoneID) } } From 4e975d4961fe2cbd3851eeaf9ccdaceb7a7357a4 Mon Sep 17 00:00:00 2001 From: Matteo Contrini Date: Wed, 4 Feb 2026 21:25:12 +0100 Subject: [PATCH 2/6] Rename `PullZoneID` to `PullZoneId` --- integrationTest/helpers_integration_test.go | 4 ++-- providers/bunnydns/api.go | 2 +- providers/bunnydns/convert.go | 8 ++++---- providers/bunnydns/convert_test.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/integrationTest/helpers_integration_test.go b/integrationTest/helpers_integration_test.go index e0684858b7..4b2d4055d5 100644 --- a/integrationTest/helpers_integration_test.go +++ b/integrationTest/helpers_integration_test.go @@ -411,8 +411,8 @@ func cfWorkerRoute(pattern, target string) *models.RecordConfig { return r } -func bunnyPullZone(name, pullZoneID string) *models.RecordConfig { - return makeRec(name, pullZoneID, "BUNNY_DNS_PZ") +func bunnyPullZone(name, pullZoneId string) *models.RecordConfig { + return makeRec(name, pullZoneId, "BUNNY_DNS_PZ") } func cfRedir(pattern, target string) *models.RecordConfig { diff --git a/providers/bunnydns/api.go b/providers/bunnydns/api.go index 561aa9654e..537b0f71bc 100644 --- a/providers/bunnydns/api.go +++ b/providers/bunnydns/api.go @@ -42,7 +42,7 @@ type record struct { Weight uint16 `json:"Weight"` Port uint16 `json:"Port"` Tag string `json:"Tag"` - PullZoneID int64 `json:"PullZoneId,omitempty"` + PullZoneId int64 `json:"PullZoneId,omitempty"` LinkName string `json:"LinkName,omitempty"` } diff --git a/providers/bunnydns/convert.go b/providers/bunnydns/convert.go index 269f896008..042747468f 100644 --- a/providers/bunnydns/convert.go +++ b/providers/bunnydns/convert.go @@ -40,13 +40,13 @@ func fromRecordConfig(rc *models.RecordConfig) (*record, error) { case recordTypeTLSA: r.Value = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) case recordTypePullZone: - // When creating Pull Zone records, the API expects an integer PullZoneID field, + // When creating Pull Zone records, the API expects an integer PullZoneId field, // while the Value field should be empty. - pullZoneID, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) + pullZoneId, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) if err != nil { return nil, fmt.Errorf("invalid Pull Zone ID for BUNNY_DNS_PZ: %w", err) } - r.PullZoneID = pullZoneID + r.PullZoneId = pullZoneId r.Value = "" } @@ -95,7 +95,7 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { var err error switch rc.Type { case "BUNNY_DNS_PZ": - // When reading Pull Zone records, the API provides the PullZoneID in the LinkName field as string. + // When reading Pull Zone records, the API provides the PullZoneId in the LinkName field as string. if r.LinkName == "" { return nil, fmt.Errorf("missing Pull Zone ID (LinkName) for BUNNY_DNS_PZ") } diff --git a/providers/bunnydns/convert_test.go b/providers/bunnydns/convert_test.go index d16fa5356d..505b237075 100644 --- a/providers/bunnydns/convert_test.go +++ b/providers/bunnydns/convert_test.go @@ -17,8 +17,8 @@ func TestFromRecordConfigPullZone(t *testing.T) { if err != nil { t.Fatalf("fromRecordConfig returned error: %v", err) } - if rec.PullZoneID != 12345 { - t.Fatalf("expected PullZoneID=12345; got=%d", rec.PullZoneID) + if rec.PullZoneId != 12345 { + t.Fatalf("expected PullZoneId=12345; got=%d", rec.PullZoneId) } } From 895e13f19dfa5a1e3db0115a00a65b029180326d Mon Sep 17 00:00:00 2001 From: Thomas Limoncelli Date: Thu, 5 Feb 2026 16:06:55 -0500 Subject: [PATCH 3/6] Fix typo in GetRegistrarCorrections, fix formatting --- providers/cnr/nameservers.go | 2 +- providers/cscglobal/registrar.go | 2 +- providers/dnsimple/dnsimpleProvider.go | 1 - providers/doh/dohProvider.go | 3 +-- providers/easyname/easynameProvider.go | 2 +- providers/gidinet/registrar.go | 1 + providers/hexonet/nameservers.go | 2 +- providers/hostingde/hostingdeProvider.go | 5 ----- providers/internetbs/internetbsProvider.go | 2 +- providers/namecheap/namecheapProvider.go | 2 ++ providers/namedotcom/nameservers.go | 2 +- 11 files changed, 10 insertions(+), 14 deletions(-) diff --git a/providers/cnr/nameservers.go b/providers/cnr/nameservers.go index 423cd0223d..93cda7f966 100644 --- a/providers/cnr/nameservers.go +++ b/providers/cnr/nameservers.go @@ -61,7 +61,7 @@ func (n *Client) getNameserversRaw(domain string) ([]string, error) { return ns, nil } -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (n *Client) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { nss, err := n.getNameserversRaw(dc.Name) if err != nil { diff --git a/providers/cscglobal/registrar.go b/providers/cscglobal/registrar.go index 96db1c6d47..5fb42f430f 100644 --- a/providers/cscglobal/registrar.go +++ b/providers/cscglobal/registrar.go @@ -9,7 +9,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" ) -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (client *providerClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { nss, err := client.getNameservers(dc.Name) if err != nil { diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index 4086f0d11e..0eb4a811de 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -235,7 +235,6 @@ func (c *dnsimpleProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]* return nil, err } sort.Strings(nameServers) - actual := strings.Join(nameServers, ",") var expectedSet []string diff --git a/providers/doh/dohProvider.go b/providers/doh/dohProvider.go index ba98f15428..18b51ce02d 100644 --- a/providers/doh/dohProvider.go +++ b/providers/doh/dohProvider.go @@ -40,7 +40,7 @@ func newDNSOverHTTPS(m map[string]string) (providers.Registrar, error) { return api, nil } -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (c *dohProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { nss, err := c.getNameservers(dc.Name) if err != nil { @@ -58,7 +58,6 @@ func (c *dohProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*model if foundNameservers == expectedNameservers { return nil, nil } - return []*models.Correction{ { Msg: fmt.Sprintf("Update nameservers %s -> %s", foundNameservers, expectedNameservers), diff --git a/providers/easyname/easynameProvider.go b/providers/easyname/easynameProvider.go index 5f6b38db82..9a6e89c128 100644 --- a/providers/easyname/easynameProvider.go +++ b/providers/easyname/easynameProvider.go @@ -44,7 +44,7 @@ func newEasyname(m map[string]string) (providers.Registrar, error) { return api, nil } -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (c *easynameProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { domain, err := c.getDomain(dc.Name) if err != nil { diff --git a/providers/gidinet/registrar.go b/providers/gidinet/registrar.go index b648ed70f0..ce4ecb692d 100644 --- a/providers/gidinet/registrar.go +++ b/providers/gidinet/registrar.go @@ -35,6 +35,7 @@ func (c *gidinetProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*m desired[i] = strings.ToLower(strings.TrimSuffix(ns, ".")) } // Deduplicate nameservers (can happen when NAMESERVER() and DNS provider both add them) + // FUTURE(tlim): Remove deduplication logic. The "existing" and "desired" lists are not merged, and "desired" is authoritative. seen := make(map[string]bool) var uniqueDesired []string for _, ns := range desired { diff --git a/providers/hexonet/nameservers.go b/providers/hexonet/nameservers.go index 93052679ef..3151eb4b75 100644 --- a/providers/hexonet/nameservers.go +++ b/providers/hexonet/nameservers.go @@ -58,7 +58,7 @@ func (n *HXClient) getNameserversRaw(domain string) ([]string, error) { return ns, nil } -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (n *HXClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { nss, err := n.getNameserversRaw(dc.Name) if err != nil { diff --git a/providers/hostingde/hostingdeProvider.go b/providers/hostingde/hostingdeProvider.go index 32a54087b5..bda05b4f45 100644 --- a/providers/hostingde/hostingdeProvider.go +++ b/providers/hostingde/hostingdeProvider.go @@ -325,11 +325,6 @@ func firstNonZero(items ...uint32) uint32 { } func (hp *hostingdeProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - // err := dc.Punycode() - // if err != nil { - // return nil, err - // } - found, err := hp.getNameservers(dc.Name) if err != nil { return nil, fmt.Errorf("error getting nameservers: %w", err) diff --git a/providers/internetbs/internetbsProvider.go b/providers/internetbs/internetbsProvider.go index e4e08f000f..2e1decaa19 100644 --- a/providers/internetbs/internetbsProvider.go +++ b/providers/internetbs/internetbsProvider.go @@ -44,7 +44,7 @@ func newInternetBs(m map[string]string) (providers.Registrar, error) { return api, nil } -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (c *internetbsProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { nss, err := c.getNameservers(dc.Name) if err != nil { diff --git a/providers/namecheap/namecheapProvider.go b/providers/namecheap/namecheapProvider.go index b0a3fca6d6..07a946b7ac 100644 --- a/providers/namecheap/namecheapProvider.go +++ b/providers/namecheap/namecheapProvider.go @@ -383,12 +383,14 @@ func (n *namecheapProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([] } sort.Strings(info.DNSDetails.Nameservers) found := strings.Join(info.DNSDetails.Nameservers, ",") + desiredNs := []string{} for _, d := range dc.Nameservers { desiredNs = append(desiredNs, d.Name) } sort.Strings(desiredNs) desired := strings.Join(desiredNs, ",") + if found != desired { parts := strings.SplitN(dc.Name, ".", 2) sld, tld := parts[0], parts[1] diff --git a/providers/namedotcom/nameservers.go b/providers/namedotcom/nameservers.go index f370143406..2804f16a1b 100644 --- a/providers/namedotcom/nameservers.go +++ b/providers/namedotcom/nameservers.go @@ -45,7 +45,7 @@ func (n *namedotcomProvider) getNameserversRaw(domain string) ([]string, error) return response.Nameservers, nil } -// GetRegistrarCorrections gathers corrections that would being n to match dc. +// GetRegistrarCorrections gathers corrections that would bring n to match dc. func (n *namedotcomProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { nss, err := n.getNameserversRaw(dc.Name) if err != nil { From d33d31b457ca48997903e91fd4b0a8492c9be5e2 Mon Sep 17 00:00:00 2001 From: Thomas Limoncelli Date: Thu, 5 Feb 2026 16:31:30 -0500 Subject: [PATCH 4/6] REFACTOR: Remove commented out code (mostly GetDomainCorrections) --- pkg/diff2/groupsort.go | 40 --------- pkg/providers/providers.go | 5 -- pkg/txtutil/txtcombined.go | 53 ------------ providers/cloudns/cloudnsProvider.go | 37 -------- providers/desec/desecProvider.go | 23 ----- providers/dnsmadeeasy/dnsMadeEasyProvider.go | 36 -------- providers/namecheap/namecheapProvider.go | 90 -------------------- 7 files changed, 284 deletions(-) delete mode 100644 pkg/diff2/groupsort.go delete mode 100644 pkg/txtutil/txtcombined.go diff --git a/pkg/diff2/groupsort.go b/pkg/diff2/groupsort.go deleted file mode 100644 index 872c3c2ffb..0000000000 --- a/pkg/diff2/groupsort.go +++ /dev/null @@ -1,40 +0,0 @@ -package diff2 - -// type recset struct { -// Key models.RecordKey -// Recs []*models.RecordConfig -// } - -// func groupbyRSet(recs models.Records, origin string) []recset { - -// if len(recs) == 0 { -// return nil -// } - -// // Sort the NameFQDN to a consistent order. The actual sort methodology -// // doesn't matter as long as equal values are adjacent. -// // Use the PrettySort ordering so that the records are extra pretty. -// pretty := prettyzone.PrettySort(recs, origin, 0, nil) -// recs = pretty.Records - -// var result []recset -// var acc []*models.RecordConfig - -// // Do the first element -// prevkey := recs[0].Key() -// acc = append(acc, recs[0]) - -// for i := 1; i < len(recs); i++ { -// curkey := recs[i].Key() -// if prevkey == curkey { // A run of equal keys. -// acc = append(acc, recs[i]) -// } else { // New key. Append old data to result and start new acc. -// result = append(result, recset{Key: prevkey, Recs: acc}) -// acc = []*models.RecordConfig{recs[i]} -// } -// prevkey = curkey -// } -// result = append(result, recset{Key: prevkey, Recs: acc}) // The remainder - -// return result -// } diff --git a/pkg/providers/providers.go b/pkg/providers/providers.go index b0639f4773..b0f56a7a80 100644 --- a/pkg/providers/providers.go +++ b/pkg/providers/providers.go @@ -193,11 +193,6 @@ func (n None) GetZoneRecordsCorrections(dc *models.DomainConfig, records models. return nil, 0, nil } -// GetDomainCorrections returns corrections to update a domain. -func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - return nil, nil -} - var featuresNone = DocumentationNotes{ // The default for unlisted capabilities is 'Cannot'. // See providers/capabilities.go for the entire list of capabilities. diff --git a/pkg/txtutil/txtcombined.go b/pkg/txtutil/txtcombined.go deleted file mode 100644 index da4fac2c9c..0000000000 --- a/pkg/txtutil/txtcombined.go +++ /dev/null @@ -1,53 +0,0 @@ -//go:generate go tool stringer -type=State - -package txtutil - -// func ParseCombined(s string) (string, error) { -// return txtDecodeCombined(s) -// } - -// // // txtDecode decodes TXT strings received from ROUTE53 and GCLOUD. -// func txtDecodeCombined(s string) (string, error) { - -// // The dns package doesn't expose the quote parser. Therefore we create a TXT record and extract the strings. -// rr, err := dns.NewRR("example.com. IN TXT " + s) -// if err != nil { -// return "", fmt.Errorf("could not parse %q TXT: %w", s, err) -// } - -// return strings.Join(rr.(*dns.TXT).Txt, ""), nil -// } - -// func EncodeCombined(t string) string { -// return txtEncodeCombined(ToChunks(t)) -// } - -// // txtEncode encodes TXT strings as the old GetTargetCombined() function did. -// func txtEncodeCombined(ts []string) string { -// //printer.Printf("DEBUG: route53 txt outboundv=%v\n", ts) - -// // Don't call this on fake types. -// rdtype := dns.StringToType["TXT"] - -// // Magically create an RR of the correct type. -// rr := dns.TypeToRR[rdtype]() - -// // Fill in the header. -// rr.Header().Name = "example.com." -// rr.Header().Rrtype = rdtype -// rr.Header().Class = dns.ClassINET -// rr.Header().Ttl = 300 - -// // Fill in the TXT data. -// rr.(*dns.TXT).Txt = ts - -// // Generate the quoted string: -// header := rr.Header().String() -// full := rr.String() -// if !strings.HasPrefix(full, header) { -// panic("assertion failed. dns.Hdr.String() behavior has changed in an incompatible way") -// } - -// //printer.Printf("DEBUG: route53 txt encodedv=%v\n", t) -// return full[len(header):] -// } diff --git a/providers/cloudns/cloudnsProvider.go b/providers/cloudns/cloudnsProvider.go index 059aee9a0a..fa221d66ef 100644 --- a/providers/cloudns/cloudnsProvider.go +++ b/providers/cloudns/cloudnsProvider.go @@ -96,43 +96,6 @@ func (c *cloudnsProvider) GetNameservers(domain string) ([]*models.Nameserver, e return models.ToNameservers(names) } -// // GetDomainCorrections returns the corrections for a domain. -// func (c *cloudnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { -// dc, err := dc.Copy() -// if err != nil { -// return nil, err -// } - -// dc.Punycode() - -// if c.domainIndex == nil { -// if err := c.fetchDomainList(); err != nil { -// return nil, err -// } -// } -// _, ok := c.domainIndex[dc.Name] -// if !ok { -// return nil, fmt.Errorf("'%s' not a zone in ClouDNS account", dc.Name) -// } - -// existingRecords, err := c.GetZoneRecords(dc.Name) -// if err != nil { -// return nil, err -// } -// // Normalize -// models.PostProcessRecords(existingRecords) - -// // Get a list of available TTL values. -// // The TTL list needs to be obtained for each domain, so get it first here. -// c.fetchAvailableTTLValues(dc.Name) -// // ClouDNS can only be specified from a specific TTL list, so change the TTL in advance. -// for _, record := range dc.Records { -// record.TTL = fixTTL(record.TTL) -// } - -// return c.GetZoneRecordsCorrections(dc, existingRecords) -// } - // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *cloudnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { domainID, ok, err := c.idForDomain(dc.Name) diff --git a/providers/desec/desecProvider.go b/providers/desec/desecProvider.go index af49030fe4..54c7ab879a 100644 --- a/providers/desec/desecProvider.go +++ b/providers/desec/desecProvider.go @@ -77,29 +77,6 @@ func (c *desecProvider) GetNameservers(domain string) ([]*models.Nameserver, err return models.ToNameservers(defaultNameServerNames) } -// func (c *desecProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { -// if dc.AutoDNSSEC == "off" { -// printer.Printf("Notice: DNSSEC signing was not requested, but cannot be turned off. (deSEC always signs all records.)\n") -// } - -// existing, err := c.GetZoneRecords(dc.Name) -// if err != nil { -// return nil, err -// } -// models.PostProcessRecords(existing) -// clean := PrepFoundRecords(existing) -// var minTTL uint32 -// c.mutex.Lock() -// if ttl, ok := c.domainIndex[dc.Name]; !ok { -// minTTL = 3600 -// } else { -// minTTL = ttl -// } -// c.mutex.Unlock() -// PrepDesiredRecords(dc, minTTL) -// return c.GetZoneRecordsCorrections(dc, clean) -// } - // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *desecProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { punycodeDomain, err := idna.ToASCII(domain) diff --git a/providers/dnsmadeeasy/dnsMadeEasyProvider.go b/providers/dnsmadeeasy/dnsMadeEasyProvider.go index cc7d9effcc..bfd58e48af 100644 --- a/providers/dnsmadeeasy/dnsMadeEasyProvider.go +++ b/providers/dnsmadeeasy/dnsMadeEasyProvider.go @@ -68,42 +68,6 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro return api, nil } -// // GetDomainCorrections returns the corrections for a domain. -// func (api *dnsMadeEasyProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { -// dc, err := dc.Copy() -// if err != nil { -// return nil, err -// } - -// err = dc.Punycode() -// if err != nil { -// return nil, err -// } - -// for _, rec := range dc.Records { -// if rec.Type == "ALIAS" { -// // ALIAS is called ANAME on DNS Made Easy -// rec.Type = "ANAME" -// } else if rec.Type == "NS" { -// // NS records have fixed TTL on DNS Made Easy and it cannot be changed -// rec.TTL = fixedNameServerRecordTTL -// } -// } - -// domainName := dc.Name - -// // Get existing records -// existingRecords, err := api.GetZoneRecords(domainName) -// if err != nil { -// return nil, err -// } - -// // Normalize -// models.PostProcessRecords(existingRecords) - -// return api.GetZoneRecordsCorrections(dc, existingRecords) -// } - func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { domainName := dc.Name domainID, err := api.findDomainID(domainName) diff --git a/providers/namecheap/namecheapProvider.go b/providers/namecheap/namecheapProvider.go index 07a946b7ac..a486e33e64 100644 --- a/providers/namecheap/namecheapProvider.go +++ b/providers/namecheap/namecheapProvider.go @@ -144,99 +144,9 @@ func (n *namecheapProvider) GetZoneRecords(domain string, meta map[string]string } } - // Copying this from GetDomainCorrections. This seems redundant - // with what toRecords() does. Leaving it out. - // for _, r := range records.Hosts { - // if r.Type == "SOA" { - // continue - // } - // rec := &models.RecordConfig{ - // Type: r.Type, - // TTL: uint32(r.TTL), - // MxPreference: uint16(r.MXPref), - // Original: r, - // } - // rec.SetLabel(r.Name, dc.Name) - // switch rtype := r.Type; rtype { // #rtype_variations - // case "TXT": - // rec.SetTargetTXT(r.Address) - // case "CAA": - // rec.SetTargetCAAString(r.Address) - // default: - // rec.SetTarget(r.Address) - // } - // actual = append(actual, rec) - // } - return toRecords(records, domain) } -// // GetDomainCorrections returns the corrections for the domain. -// func (n *namecheapProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { -// dc.Punycode() -// sld, tld := splitDomain(dc.Name) -// var records *nc.DomainDNSGetHostsResult -// var err error -// doWithRetry(func() error { -// records, err = n.client.DomainsDNSGetHosts(sld, tld) -// return err -// }) -// if err != nil { -// return nil, err -// } - -// var actual []*models.RecordConfig - -// // namecheap does not allow setting @ NS with basic DNS -// dc.Filter(func(r *models.RecordConfig) bool { -// if r.Type == "NS" && r.GetLabel() == "@" { -// if !strings.HasSuffix(r.GetTargetField(), "registrar-servers.com.") { -// printer.Println("\n", r.GetTargetField(), "Namecheap does not support changing apex NS records. Skipping.") -// } -// return false -// } -// return true -// }) - -// // namecheap has this really annoying feature where they add some parking records if you have no records. -// // This causes a few problems for our purposes, specifically the integration tests. -// // lets detect that one case and pretend it is a no-op. -// if len(dc.Records) == 0 && len(records.Hosts) == 2 { -// if records.Hosts[0].Type == "CNAME" && -// strings.Contains(records.Hosts[0].Address, "parkingpage") && -// records.Hosts[1].Type == "URL" { -// return nil, nil -// } -// } - -// for _, r := range records.Hosts { -// if r.Type == "SOA" { -// continue -// } -// rec := &models.RecordConfig{ -// Type: r.Type, -// TTL: uint32(r.TTL), -// MxPreference: uint16(r.MXPref), -// Original: r, -// } -// rec.SetLabel(r.Name, dc.Name) -// switch rtype := r.Type; rtype { // #rtype_variations -// case "TXT": -// rec.SetTargetTXT(r.Address) -// case "CAA": -// rec.SetTargetCAAString(r.Address) -// default: -// rec.SetTarget(r.Address) -// } -// actual = append(actual, rec) -// } - -// // Normalize -// models.PostProcessRecords(actual) - -// return n.GetZoneRecordsCorrections(dc, actual) -// } - // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (n *namecheapProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, int, error) { // namecheap does not allow setting @ NS with basic DNS From 27ab5b82a968cd7eeded17d5702b04c085d96e06 Mon Sep 17 00:00:00 2001 From: Matteo Contrini Date: Wed, 4 Feb 2026 20:29:21 +0100 Subject: [PATCH 5/6] Add support for Bunny DNS PullZone (PZ) record type --- integrationTest/helpers_integration_test.go | 4 ++-- providers/bunnydns/api.go | 2 +- providers/bunnydns/convert.go | 8 ++++---- providers/bunnydns/convert_test.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/integrationTest/helpers_integration_test.go b/integrationTest/helpers_integration_test.go index 4b2d4055d5..e0684858b7 100644 --- a/integrationTest/helpers_integration_test.go +++ b/integrationTest/helpers_integration_test.go @@ -411,8 +411,8 @@ func cfWorkerRoute(pattern, target string) *models.RecordConfig { return r } -func bunnyPullZone(name, pullZoneId string) *models.RecordConfig { - return makeRec(name, pullZoneId, "BUNNY_DNS_PZ") +func bunnyPullZone(name, pullZoneID string) *models.RecordConfig { + return makeRec(name, pullZoneID, "BUNNY_DNS_PZ") } func cfRedir(pattern, target string) *models.RecordConfig { diff --git a/providers/bunnydns/api.go b/providers/bunnydns/api.go index 537b0f71bc..561aa9654e 100644 --- a/providers/bunnydns/api.go +++ b/providers/bunnydns/api.go @@ -42,7 +42,7 @@ type record struct { Weight uint16 `json:"Weight"` Port uint16 `json:"Port"` Tag string `json:"Tag"` - PullZoneId int64 `json:"PullZoneId,omitempty"` + PullZoneID int64 `json:"PullZoneId,omitempty"` LinkName string `json:"LinkName,omitempty"` } diff --git a/providers/bunnydns/convert.go b/providers/bunnydns/convert.go index 042747468f..269f896008 100644 --- a/providers/bunnydns/convert.go +++ b/providers/bunnydns/convert.go @@ -40,13 +40,13 @@ func fromRecordConfig(rc *models.RecordConfig) (*record, error) { case recordTypeTLSA: r.Value = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) case recordTypePullZone: - // When creating Pull Zone records, the API expects an integer PullZoneId field, + // When creating Pull Zone records, the API expects an integer PullZoneID field, // while the Value field should be empty. - pullZoneId, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) + pullZoneID, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) if err != nil { return nil, fmt.Errorf("invalid Pull Zone ID for BUNNY_DNS_PZ: %w", err) } - r.PullZoneId = pullZoneId + r.PullZoneID = pullZoneID r.Value = "" } @@ -95,7 +95,7 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { var err error switch rc.Type { case "BUNNY_DNS_PZ": - // When reading Pull Zone records, the API provides the PullZoneId in the LinkName field as string. + // When reading Pull Zone records, the API provides the PullZoneID in the LinkName field as string. if r.LinkName == "" { return nil, fmt.Errorf("missing Pull Zone ID (LinkName) for BUNNY_DNS_PZ") } diff --git a/providers/bunnydns/convert_test.go b/providers/bunnydns/convert_test.go index 505b237075..d16fa5356d 100644 --- a/providers/bunnydns/convert_test.go +++ b/providers/bunnydns/convert_test.go @@ -17,8 +17,8 @@ func TestFromRecordConfigPullZone(t *testing.T) { if err != nil { t.Fatalf("fromRecordConfig returned error: %v", err) } - if rec.PullZoneId != 12345 { - t.Fatalf("expected PullZoneId=12345; got=%d", rec.PullZoneId) + if rec.PullZoneID != 12345 { + t.Fatalf("expected PullZoneID=12345; got=%d", rec.PullZoneID) } } From 9fd1c5f6c859114c86595b6085d932aa65b4ce1b Mon Sep 17 00:00:00 2001 From: Matteo Contrini Date: Wed, 4 Feb 2026 21:25:12 +0100 Subject: [PATCH 6/6] Rename `PullZoneID` to `PullZoneId` --- integrationTest/helpers_integration_test.go | 4 ++-- providers/bunnydns/api.go | 2 +- providers/bunnydns/convert.go | 8 ++++---- providers/bunnydns/convert_test.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/integrationTest/helpers_integration_test.go b/integrationTest/helpers_integration_test.go index e0684858b7..4b2d4055d5 100644 --- a/integrationTest/helpers_integration_test.go +++ b/integrationTest/helpers_integration_test.go @@ -411,8 +411,8 @@ func cfWorkerRoute(pattern, target string) *models.RecordConfig { return r } -func bunnyPullZone(name, pullZoneID string) *models.RecordConfig { - return makeRec(name, pullZoneID, "BUNNY_DNS_PZ") +func bunnyPullZone(name, pullZoneId string) *models.RecordConfig { + return makeRec(name, pullZoneId, "BUNNY_DNS_PZ") } func cfRedir(pattern, target string) *models.RecordConfig { diff --git a/providers/bunnydns/api.go b/providers/bunnydns/api.go index 561aa9654e..537b0f71bc 100644 --- a/providers/bunnydns/api.go +++ b/providers/bunnydns/api.go @@ -42,7 +42,7 @@ type record struct { Weight uint16 `json:"Weight"` Port uint16 `json:"Port"` Tag string `json:"Tag"` - PullZoneID int64 `json:"PullZoneId,omitempty"` + PullZoneId int64 `json:"PullZoneId,omitempty"` LinkName string `json:"LinkName,omitempty"` } diff --git a/providers/bunnydns/convert.go b/providers/bunnydns/convert.go index 269f896008..042747468f 100644 --- a/providers/bunnydns/convert.go +++ b/providers/bunnydns/convert.go @@ -40,13 +40,13 @@ func fromRecordConfig(rc *models.RecordConfig) (*record, error) { case recordTypeTLSA: r.Value = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) case recordTypePullZone: - // When creating Pull Zone records, the API expects an integer PullZoneID field, + // When creating Pull Zone records, the API expects an integer PullZoneId field, // while the Value field should be empty. - pullZoneID, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) + pullZoneId, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) if err != nil { return nil, fmt.Errorf("invalid Pull Zone ID for BUNNY_DNS_PZ: %w", err) } - r.PullZoneID = pullZoneID + r.PullZoneId = pullZoneId r.Value = "" } @@ -95,7 +95,7 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { var err error switch rc.Type { case "BUNNY_DNS_PZ": - // When reading Pull Zone records, the API provides the PullZoneID in the LinkName field as string. + // When reading Pull Zone records, the API provides the PullZoneId in the LinkName field as string. if r.LinkName == "" { return nil, fmt.Errorf("missing Pull Zone ID (LinkName) for BUNNY_DNS_PZ") } diff --git a/providers/bunnydns/convert_test.go b/providers/bunnydns/convert_test.go index d16fa5356d..505b237075 100644 --- a/providers/bunnydns/convert_test.go +++ b/providers/bunnydns/convert_test.go @@ -17,8 +17,8 @@ func TestFromRecordConfigPullZone(t *testing.T) { if err != nil { t.Fatalf("fromRecordConfig returned error: %v", err) } - if rec.PullZoneID != 12345 { - t.Fatalf("expected PullZoneID=12345; got=%d", rec.PullZoneID) + if rec.PullZoneId != 12345 { + t.Fatalf("expected PullZoneId=12345; got=%d", rec.PullZoneId) } }