Skip to content

Comments

NEW PROVIDER: UniFi Network DNS provider#4013

Merged
tlimoncelli merged 8 commits intoStackExchange:mainfrom
zupolgec:provider-unifi
Feb 24, 2026
Merged

NEW PROVIDER: UniFi Network DNS provider#4013
tlimoncelli merged 8 commits intoStackExchange:mainfrom
zupolgec:provider-unifi

Conversation

@zupolgec
Copy link
Collaborator

@zupolgec zupolgec commented Jan 26, 2026

Summary

Add support for managing static DNS records on UniFi Network controllers via the v2 API (Network 8.2+).

Features

  • Supported record types: A, AAAA, CNAME, MX, TXT, SRV, NS
  • Local access: Direct connection to UniFi controller with optional TLS verification skip for self-signed certs
  • Cloud access: Remote management via UniFi Cloud Connector (api.ui.com) - requires UniFi OS 5.0.3+
  • Domain filtering: Automatically filters records by domain suffix since UniFi stores all records flat

Configuration

Local Access

{
  "unifi": {
    "TYPE": "UNIFI",
    "host": "https://192.168.1.1",
    "api_key": "your-api-key",
    "site": "default",
    "skip_tls_verify": "true"
  }
}

Cloud Access

{
  "unifi_cloud": {
    "TYPE": "UNIFI",
    "console_id": "your-console-id",
    "api_key": "cloud-api-key",
    "site": "default"
  }
}

Usage Example

var DNS_UNIFI = NewDnsProvider("unifi");

D("home.internal", REG_NONE, DnsProvider(DNS_UNIFI),
    A("server", "10.0.0.10"),
    CNAME("www", "server.home.internal."),
    MX("@", 10, "mail.home.internal."),
END);

Testing

Tested using the OLD API (/v2/api/site/{site}/static-dns) via:

  • Local access: UDM Pro (Network 10.0.162)
  • Cloud access: Remote console via api.ui.com (Network 10.1.78)

All CRUD operations verified working on both access methods.

References

@zupolgec
Copy link
Collaborator Author

Hi @tlimoncelli, Unifi is launching a new API to manage DNS records in v10.1.
Should this new API be implemented in a new UNIFI_V2 provider, or we can add version detection in this new provider (since no one is using it yet) or a flag?

@tlimoncelli
Copy link
Collaborator

tlimoncelli commented Jan 27, 2026

Hi @tlimoncelli, Unifi is launching a new API to manage DNS records in v10.1. Should this new API be implemented in a new UNIFI_V2 provider, or we can add version detection in this new provider (since no one is using it yet) or a flag?

Either is fine. If you want to skip v1 and only support v2, that's fine too. (edited for clarity)

@tlimoncelli tlimoncelli changed the title new provider: Add UniFi Network DNS provider NEW PROVIDER: UniFi Network DNS provider Jan 27, 2026
@zupolgec
Copy link
Collaborator Author

Hi @tlimoncelli, Unifi is launching a new API to manage DNS records in v10.1. Should this new API be implemented in a new UNIFI_V2 provider, or we can add version detection in this new provider (since no one is using it yet) or a flag?

Either is fine. If you want to skip v1 and only support v2, that's fine too. (edited for clarity)

Right now v2 is Early Access. And v1 would support all Unifi versions back to 8.x. That could be immediately useful for more users. I'll go with a flag that defaults to "auto" for version detection, best of both.

@tlimoncelli
Copy link
Collaborator

tlimoncelli commented Feb 2, 2026

Thank you for contributing this new provider, @zupolgec !

Some notes:

  1. @fm: Faisal Misle is our “liaison to maintainers”. He'll reach out to you soon. He'll be requesting your email address so that we have a more direct way to contact you.
  2. By now you should have recieved a Github invite to have the "triage" role for this repo. Please accept the invite so we can assign bugs to you.
  3. I reviewed the checklist at the end of https://docs.dnscontrol.org/developer-info/writing-providers and some things are missing: Please update the OWNERS, README.md, and create a documentation page.
  4. When done, please (1) run bin/generate.sh, (2) rebase, (3) post the output of the integration tests as a comment to this PR.

My home internet router doesn't have an API. Maybe I should check out UniFi!

Thanks again!
Tom

Copy link
Collaborator

@tlimoncelli tlimoncelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment

@zupolgec
Copy link
Collaborator Author

zupolgec commented Feb 2, 2026

  1. I reviewed the checklist at the end of https://docs.dnscontrol.org/developer-info/writing-providers and some things are missing: Please update the OWNERS, README.md, and create a documentation page.
  2. When done, please (1) run bin/generate.sh, (2) rebase, (3) post the output of the integration tests as a comment to this PR.

Docs added. This is the result of the integration tests:

Testing Profile="UNIFI" (TYPE="UNIFI")
--- PASS: 250 tests
--- SKIP: 157 tests (unsupported record types, provider-specific features)
--- FAIL: 2 tests (known API limitations)

Known failures (knownFailures: "26,43"):
- Test 26: TXT with interior double-quotes - UniFi API rejects "Incorrectly quoted value"
- Test 43: SRV custom TTL - UniFi doesn't preserve TTL for SRV records (always returns 300)

My home internet router doesn't have an API. Maybe I should check out UniFi!

I love Ubiquiti and their products, huge fan. I like to think of them as the Apple of networking equipment (the old Apple at least).
I also like Mikrotik devices, really hackable and configurable. Probably it will be my next provider proposal 😀

tlimoncelli added a commit that referenced this pull request Feb 20, 2026
## Summary

This PR introduces a new DNS provider for MikroTik RouterOS devices,
managing DNS static entries and forwarders via the RouterOS REST API.
**Requires RouterOS 7.x.**

I absolutely loved dnscontrol's features and the ease of management for
domains it provides. However, part of my personal DNS-related
infrastructure is powered by Mikrotik devices, and in order to unify
configuration management I drafted this implementation. Hope others will
find it an useful addition
(#4013 (comment))

## Changes

For the new `MIKROTIK` provider:
* Supported record types: `A, AAAA, CNAME, MX, NS, SRV, TXT`
* Custom record types:
- `MIKROTIK_FWD`: conditional DNS forwarding with address list
population
  - `MIKROTIK_NXDOMAIN`: respond with NXDOMAIN for matching queries
- `MIKROTIK_FORWARDER`: manage `/ip/dns/forwarders` entries via a
synthetic `_forwarders.mikrotik` zone
* ROS-specific record metadata (`match_subdomain`, `regexp`,
`address_list`, `comment`) exposed as dnscontrol metadata and
round-tripped through the API
* **Zone detection**: RouterOS has no native zone concept; zones are
inferred from record names using configurable zonehints (longest match),
publicsuffix, or last-two-labels fallback

* `get-zones` enhancements: 
- Auto-emits `{no_ns: "true"}` when a provider returns no nameservers
(useful for any provider without NS records, not just MikroTik)
- Serializes MikroTik-specific metadata and custom record types into the
generated DSL

## Configuration

```json
{
  "home_gateway": {
    "TYPE": "MIKROTIK",
    "host": "http://192.168.88.1:80",
    "username": "admin",
    "password": "passw0rd",
    "zonehints": "home.example.com"
  }
}
```

## Usage Example

```js
var DSP_MIKROTIK = NewDnsProvider("home_gateway");
var REG_NONE = NewRegistrar("none");

D("_forwarders.mikrotik", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, MIKROTIK_FORWARDER("site2site-fwd", "192.168.13.1")
	, MIKROTIK_FORWARDER("doh-upstream", "1.1.1.1", {doh_servers: "https://cloudflare-dns.com/dns-query", verify_doh_cert: "true"}),
)

D("home.example.com", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, DefaultTTL(900)
	, A("mikrotik", "192.168.10.1", TTL(86400))
	, A("srv", "192.168.10.2", TTL(86400))
	, A("pve", "192.168.10.5", TTL(86400))
	, A("galaxy-a20", "192.168.10.193", {comment: "dhcp0_lan-3C:20:F6:11:11:11"})
	, CNAME("proxmox", "srv.home.example.com.", TTL(86400))
	, CNAME("admin", "srv.home.example.com.", TTL(86400))
	, MIKROTIK_FWD("remote", "site2site-fwd", {match_subdomain: "true"}, TTL(86400))
)

D("nextdns.io", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, DefaultTTL(86400)
	, A("dns", "45.90.28.0")
	, A("dns", "45.90.30.0")
	, AAAA("dns", "2a07:a8c0::")
	, AAAA("dns", "2a07:a8c1::")
)

D("twimg.com", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, DefaultTTL(86400)
	// Needed for dynamic routing with address lists based on queries to the resolver
	, MIKROTIK_FWD("@", "8.8.8.8", {match_subdomain: "true", address_list: "dst-to-vpn-list"})

D("example.com", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, MIKROTIK_FWD("@", "doh-upstream", {match_subdomain: "true"})
)
```

## Potential improvements
- Implement access using `api` service with proprietary protocol on port
8728/8729 (with TLS), instead of REST API relying on the `www` service

## Tests
<details>
<summary>Integration tests verified against a physical RouterOS 7.21.3
device, hap ax3

```
PASS
ok      github.com/StackExchange/dnscontrol/v4/integrationTest  39.183s
```
</summary>

```
=== RUN   TestDNSProviders/example.com/103:final:final
    helpers_integration_test.go:196: 
        + CREATE final.example.com TXT "TestDNSProviders was successful!" ttl=300
--- PASS: TestDNSProviders (38.64s)
    --- PASS: TestDNSProviders/example.com (38.64s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty (4.13s)
        --- PASS: TestDNSProviders/example.com/00:A:Create_A (0.06s)
        --- PASS: TestDNSProviders/example.com/00:A:Change_A_target (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#01 (0.03s)
        --- PASS: TestDNSProviders/example.com/01:Apex:Create_A (0.05s)
        --- PASS: TestDNSProviders/example.com/01:Apex:Change_A_target (0.16s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#02 (0.03s)
        --- PASS: TestDNSProviders/example.com/02:Protocol-Wildcard:Create_wildcard (0.09s)
        --- PASS: TestDNSProviders/example.com/02:Protocol-Wildcard:Delete_wildcard (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#03 (0.03s)
        --- PASS: TestDNSProviders/example.com/03:AAAA:Create_AAAA (0.06s)
        --- PASS: TestDNSProviders/example.com/03:AAAA:Change_AAAA_target (0.08s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#04 (0.03s)
        --- PASS: TestDNSProviders/example.com/04:CNAME:Create_a_CNAME (0.07s)
        --- PASS: TestDNSProviders/example.com/04:CNAME:Change_CNAME_target (0.06s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#05 (0.03s)
        --- PASS: TestDNSProviders/example.com/05:CNAME-short:Create_a_CNAME (0.08s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#06 (0.06s)
        --- PASS: TestDNSProviders/example.com/06:MX:Create_MX_apex (0.07s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_apex (0.07s)
        --- PASS: TestDNSProviders/example.com/06:MX:Create_MX (0.09s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_target (0.15s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_p (0.06s)
        --- PASS: TestDNSProviders/example.com/07:RP_***SKIPPED(CanUseRP_not_supported)***:Empty (0.04s)
        --- PASS: TestDNSProviders/example.com/08:RP_***SKIPPED(CanUseRP_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#07 (0.01s)
        --- PASS: TestDNSProviders/example.com/09:TXT:Create_TXT (0.05s)
        --- PASS: TestDNSProviders/example.com/09:TXT:Change_TXT_target (0.06s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#08 (0.03s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:CreateManyAtLabel (0.17s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Empty (0.07s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Create_an_A_record (0.05s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Add_at_label1 (0.07s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Add_at_label2 (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#09 (0.06s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:CreateManyTypesAtLabel (0.13s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Empty (0.15s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Create_an_A_record (0.05s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Add_Type_At_Label (0.06s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Add_Type_At_Label#01 (0.10s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#10 (0.07s)
        --- PASS: TestDNSProviders/example.com/12:Attl:Create_Arc (0.05s)
        --- PASS: TestDNSProviders/example.com/12:Attl:Change_TTL (0.09s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#11 (0.07s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Start (0.15s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_a_ttl (0.17s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_single_target_from_set (0.07s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_all_ttls (0.21s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#12 (0.09s)
        --- PASS: TestDNSProviders/example.com/14:add_to_label_and_change_orig_ttl:Setup (0.06s)
        --- PASS: TestDNSProviders/example.com/14:add_to_label_and_change_orig_ttl:Add_at_same_label,_new_ttl (0.09s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#13 (0.11s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Create_A (0.08s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Change_to_MX (0.08s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Change_back_to_A (0.10s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#14 (0.03s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Create_a_CNAME (0.06s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Change_to_A_record (0.07s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Change_back_to_CNAME (0.20s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS_***SKIPPED(CanUseHTTPS_not_supported)***:Empty (0.05s)
        --- PASS: TestDNSProviders/example.com/18:Ech_***SKIPPED(CanUseHTTPS_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/19:SVCB_***SKIPPED(CanUseSVCB_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#15 (0.01s)
        --- PASS: TestDNSProviders/example.com/20:CNAME:Record_pointing_to_@ (0.56s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#16 (0.05s)
        --- PASS: TestDNSProviders/example.com/21:ApexMX:Record_pointing_to_@ (0.12s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#17 (0.05s)
        --- SKIP: TestDNSProviders/example.com/22:NullMX:create (0.00s)
        --- PASS: TestDNSProviders/example.com/22:NullMX:unnull (0.26s)
        --- SKIP: TestDNSProviders/example.com/22:NullMX:renull (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#18 (0.11s)
        --- SKIP: TestDNSProviders/example.com/23:NullMXApex:create (0.00s)
        --- PASS: TestDNSProviders/example.com/23:NullMXApex:unnull (0.21s)
        --- SKIP: TestDNSProviders/example.com/23:NullMXApex:renull (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#19 (0.10s)
        --- PASS: TestDNSProviders/example.com/24:NS:NS_for_subdomain (0.07s)
        --- PASS: TestDNSProviders/example.com/24:NS:Dual_NS_for_subdomain (0.11s)
        --- PASS: TestDNSProviders/example.com/24:NS:NS_Record_pointing_to_@ (0.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#20 (0.07s)
        --- PASS: TestDNSProviders/example.com/25:NS_only_APEX:Single_NS_at_apex (0.06s)
        --- PASS: TestDNSProviders/example.com/25:NS_only_APEX:Dual_NS_at_apex (0.21s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#21 (0.06s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_0-byte_TXT (0.12s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_254-byte_TXT (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_255-byte_TXT (0.11s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_256-byte_TXT (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_509-byte_TXT (0.20s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_510-byte_TXT (0.11s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_511-byte_TXT (0.08s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_764-byte_TXT (0.19s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_765-byte_TXT (0.10s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_766-byte_TXT (0.10s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_single-quote (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_backtick (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-1interior (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_2_dq-2interior (0.07s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-left (0.06s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-right (0.06s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_semicolon (0.07s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_semicolon_ws (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_interior_ws (0.17s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_trailing_ws (0.08s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:Create_a_TXT/SPF (0.11s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#22 (0.03s)
        --- PASS: TestDNSProviders/example.com/27:TXT_backslashes:TXT_with_backslashs (0.19s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#23 (0.11s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Create_CAPS (0.08s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Downcase_label (0.29s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Downcase_target (0.16s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Upcase_both (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#24 (0.05s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:initial (0.11s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:changeOne (0.07s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:deleteOne (0.16s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:addOne (0.11s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#25 (0.05s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:initial (0.22s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:changeOne (0.20s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:deleteOne (0.09s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:addOne (0.08s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#26 (0.14s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Internationalized_name (0.06s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Change_IDN (0.06s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Chinese_label (0.12s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Internationalized_CNAME_Target (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#27 (0.03s)
        --- PASS: TestDNSProviders/example.com/32:IDNAs_in_CNAME_targets:IDN_CNAME_AND_Target (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#28 (0.03s)
        --- PASS: TestDNSProviders/example.com/33:pager101:99_records (7.55s)
        --- PASS: TestDNSProviders/example.com/33:pager101:100_records (0.75s)
        --- PASS: TestDNSProviders/example.com/33:pager101:101_records (0.61s)
        --- PASS: TestDNSProviders/example.com/34:pager601_***SKIPPED(disabled_by_only)***:Empty (3.46s)
        --- PASS: TestDNSProviders/example.com/35:pager1201_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/36:batchRecordswithOthers_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/37:CAA_***SKIPPED(CanUseCAA_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/38:LOC_***SKIPPED(CanUseLOC_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR_***SKIPPED(CanUseNAPTR_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/40:PTR_***SKIPPED(CanUsePTR_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/41:SOA_***SKIPPED(CanUseSOA_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#29 (0.02s)
        --- PASS: TestDNSProviders/example.com/42:SRV:SRV_record (0.06s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Second_SRV_record,_same_prio (0.07s)
        --- PASS: TestDNSProviders/example.com/42:SRV:3_SRV (0.10s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Delete_one (0.05s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Target (0.14s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Priority (0.10s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Weight (0.07s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Port (0.26s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Empty (0.42s)
        --- SKIP: TestDNSProviders/example.com/42:SRV:Null_Target (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#30 (0.02s)
        --- PASS: TestDNSProviders/example.com/43:SRV:Create_SRV333 (0.15s)
        --- PASS: TestDNSProviders/example.com/43:SRV:Change_TTL999 (0.06s)
        --- PASS: TestDNSProviders/example.com/44:SSHFP_***SKIPPED(CanUseSSHFP_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/45:TLSA_***SKIPPED(CanUseTLSA_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/46:DS_***SKIPPED(CanUseDS_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/47:DS_(children_only)_***SKIPPED(CanUseDSForChildren_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/48:DS_(children_only)_CLOUDNS_***SKIPPED(CanUseDSForChildren_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/49:DHCID_***SKIPPED(CanUseDHCID_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/50:DNAME_***SKIPPED(CanUseDNAME_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/51:DNSKEY_***SKIPPED(CanUseDNSKEY_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/52:ALIAS_on_apex_***SKIPPED(CanUseAlias_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/53:ALIAS_to_nonfqdn_***SKIPPED(CanUseAlias_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/54:ALIAS_on_subdomain_***SKIPPED(CanUseAlias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/55:AZURE_ALIAS_A_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/56:AZURE_ALIAS_CNAME_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/57:R53_ALIAS2_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/58:R53_ALIAS_ORDER_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/59:R53_ALIAS_CNAME_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/60:R53_ALIAS_Loop_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/61:R53_alias_pre-existing_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/62:R53_alias_evaluate_target_health_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/63:R53_B3493_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/64:R53_B3493_REV_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/65:CF_REDIRECT_CONVERT_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/66:CLOUDFLAREAPI_SINGLE_REDIRECT_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/67:CF_PROXY_A_create_***SKIPPED(disabled_by_only)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/68:CF_PROXY_A_off_to_on_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/69:CF_PROXY_A_on_to_off_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/70:CF_PROXY_CNAME_create_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/71:CF_PROXY_CNAME_off_to_on_***SKIPPED(disabled_by_only)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/72:CF_PROXY_CNAME_on_to_off_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/73:CF_CNAME_FLATTEN_create_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/74:CF_CNAME_FLATTEN_off_to_on_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/75:CF_CNAME_FLATTEN_on_to_off_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/76:CF_COMMENT_create_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/77:CF_TAGS_create_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/78:CF_WORKER_ROUTE_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/79:ADGUARDHOME_A_PASSTHROUGH_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/80:ADGUARDHOME_AAAA_PASSTHROUGH_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#31 (0.01s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:create_FWD_record (0.10s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:change_FWD_target (0.06s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:FWD_with_match_subdomain (0.07s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:FWD_with_address_list (0.06s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:FWD_with_comment (0.12s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:multiple_FWD_records (0.11s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:delete_one_FWD (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#32 (0.03s)
        --- PASS: TestDNSProviders/example.com/82:MIKROTIK_NXDOMAIN:create_NXDOMAIN (0.06s)
        --- PASS: TestDNSProviders/example.com/82:MIKROTIK_NXDOMAIN:multiple_NXDOMAIN (0.09s)
        --- PASS: TestDNSProviders/example.com/82:MIKROTIK_NXDOMAIN:delete_one_NXDOMAIN (0.18s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#33 (0.03s)
        --- PASS: TestDNSProviders/example.com/83:MIKROTIK_METADATA:A_record_with_comment (0.07s)
        --- PASS: TestDNSProviders/example.com/83:MIKROTIK_METADATA:change_comment (0.25s)
        --- PASS: TestDNSProviders/example.com/83:MIKROTIK_METADATA:A_with_match_subdomain (0.08s)
        --- PASS: TestDNSProviders/example.com/84:VERCEL_CAA_whitespace_-_cansignhttpexchanges_***SKIPPED(disabled_by_only)***:Empty (0.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#34 (0.02s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:Create_some_records (0.19s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label,type (0.06s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label,type,target (0.06s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#02 (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_type (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#03 (0.07s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_type,target (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#04 (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_target (0.04s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#05 (0.04s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_manytypes (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#06 (0.15s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label,type,target=* (0.06s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#07 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#35 (0.13s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:Create_some_records (0.27s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_label (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS (0.04s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_label,type (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_label,type,target (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#02 (0.08s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_type (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#03 (0.04s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_type,target (0.12s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#04 (0.06s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_target (0.06s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#05 (0.06s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_manytypes (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#06 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#36 (0.14s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:Create_some_records (0.19s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:ignore_unsafe_apex (0.04s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:VERIFY_PREVIOUS (0.06s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:ignore_unsafe_label (0.04s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#37 (0.11s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:Create_some_records (0.30s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:ignore_label=foo.* (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:VERIFY_PREVIOUS (0.06s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:ignore_label=foo.bat,type (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:ignore_target=*.domain (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:VERIFY_PREVIOUS#02 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#38 (0.16s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:Create_some_records (0.42s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByZone (0.12s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS (0.08s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByLabel (0.10s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS#01 (0.11s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByRecordSet (0.09s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS#02 (0.09s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByRecord (0.11s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS#03 (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#39 (0.27s)
        --- PASS: TestDNSProviders/example.com/90:IGNORE_TARGET_b2285:Create_some_records (0.09s)
        --- PASS: TestDNSProviders/example.com/90:IGNORE_TARGET_b2285:Add_a_new_record_-_ignoring_test.foo.com. (0.02s)
        --- PASS: TestDNSProviders/example.com/90:IGNORE_TARGET_b2285:VERIFY_PREVIOUS (0.04s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#40 (0.09s)
        --- PASS: TestDNSProviders/example.com/91:IGNORE_everything_b2822:Create_some_records (0.18s)
        --- PASS: TestDNSProviders/example.com/91:IGNORE_everything_b2822:ignore_them_all (0.05s)
        --- PASS: TestDNSProviders/example.com/91:IGNORE_everything_b2822:VERIFY_PREVIOUS (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#41 (0.23s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:Create_some_records (0.10s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:ignore (0.05s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:VERIFY_PREVIOUS (0.04s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:Verify_nothing_changed (0.15s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:VERIFY_PREVIOUS#01 (0.03s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:ignore_with_change (0.07s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:VERIFY_PREVIOUS#02 (0.03s)
        --- PASS: TestDNSProviders/example.com/93:structured_TXT_***SKIPPED(disabled_by_only)***:Empty (0.08s)
        --- PASS: TestDNSProviders/example.com/94:structured_TXT_as_native_records_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/95:CLOUDNS_geodns_tests_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/96:PORKBUN_URLFWD_tests_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/97:GCORE_metadata_tests_***SKIPPED(disabled_by_only)***:Empty (0.05s)
        --- PASS: TestDNSProviders/example.com/98:NAMECHEAP_url_redirect_records_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/99:OPENPGPKEY_***SKIPPED(CanUseOPENPGPKEY_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/100:SMIMEA_***SKIPPED(CanUseSMIMEA_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/101:Bunny_DNS_Pull_Zone_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#42 (0.01s)
        --- PASS: TestDNSProviders/example.com/102:final:final (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#43 (0.06s)
        --- PASS: TestDNSProviders/example.com/103:final:final (0.07s)
=== RUN   TestDualProviders
Testing Profile="MIKROTIK" (TYPE="MIKROTIK")
    provider_test.go:29: Skipping.  DocDualHost == Cannot
--- SKIP: TestDualProviders (0.00s)
=== RUN   TestNameserverDots
Testing Profile="MIKROTIK" (TYPE="MIKROTIK")
    provider_test.go:108: Skipping.  DocDualHost == Cannot
--- SKIP: TestNameserverDots (0.00s)
=== RUN   TestDuplicateNameservers
Testing Profile="MIKROTIK" (TYPE="MIKROTIK")
    provider_test.go:140: Skipping.  DocDualHost == Cannot
--- SKIP: TestDuplicateNameservers (0.00s)
PASS
ok      github.com/StackExchange/dnscontrol/v4/integrationTest  39.183s
```
</details>

---------

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
@tlimoncelli
Copy link
Collaborator

Hello friend!

Please rebase (there are merge conflicts, sorry!). If you can do this in the today or tomorrow, I'll include this in the next release.

@fm
Copy link

fm commented Feb 23, 2026

Hi @zupolgec,

Apologies for the delay, I thought I had already posted here. As Tom mentioned I am the Maintainer Liaison. Would you be able to send your contact email to us? You can reach me at dnscontrol at faisal dot fm and Tom at tlimoncelli at stack over flow dot com

Your email will not be public and will only be used the the project team to send out maintainer communications.

As a maintainer, we’d like to remind you of your role and expectations we have so that everyone has a positive experience using dnscontrol:

  • Maintainers are expected to support their provider. If a maintainer is no longer able to maintain a provider, they should suggest a replacement or if no replacement is available, the maintainer shall let the maintainer liaison know so they can put out a call for volunteers.
  • Maintainers must be responsible to bug reports and PRs for their provider.
  • Maintainers should set up test accounts and periodically verify that all tests pass (pkg/js/parse_tests and integrationTest), especially when new features are added or changed in the core product.
  • Contributors are encouraged to add new tests and refine old ones. (Test-driven development is encouraged.)

Thank you!!

@zupolgec
Copy link
Collaborator Author

Hey @tlimoncelli, saw your rebase, thanks!

I fixed a couple things on my end — removed some unused functions and fixed godot lint warnings in the unifi provider. Just pushed that.

There are two issues left from the merge that I think are on your side:

  1. providers/desec/desecProvider.go:54 — missing colon on the CanUseOPENPGPKEY line (looks like it got dropped during the merge):

    // broken:
    providers.CanUseOPENPGPKEY        providers.Can(),
    // should be:
    providers.CanUseOPENPGPKEY:       providers.Can(),
  2. providers/unifi/types.gogo fix wants to replace omitempty with omitzero on a few struct tags (Go 1.25+ thing, showed up after the merge). Not sure if that's something you want to handle globally or if I should just commit it.

Let me know!

@tlimoncelli
Copy link
Collaborator

Hello @zupolgec !

Thanks for pointing those out. The first one is now fixed in main. The second issue... feel free to commit it in your PR.

Add support for managing static DNS records on UniFi Network controllers
via the v2 API (Network 8.2+). Supports both local access and remote
cloud access via api.ui.com.

Features:
- Supported record types: A, AAAA, CNAME, MX, TXT, SRV, NS
- Local access with optional TLS verification skip for self-signed certs
- Cloud access via UniFi Cloud Connector (requires UniFi OS 5.0.3+)
- Automatic record filtering by domain suffix

Configuration options:
- host: Local controller URL (e.g., https://192.168.1.1)
- console_id: Cloud console ID for remote access
- api_key: UniFi API key
- site: Site name (defaults to 'default')
- skip_tls_verify: Skip TLS verification for self-signed certs
Support both UniFi Network APIs:
- Legacy API (v2/api/site/{site}/static-dns) for Network 8.2+
- New API (integration/v1/sites/{siteId}/dns/policies) for Network 10.1+

The new 'api_version' config parameter accepts:
- 'auto' (default): probes both APIs, prefers new, falls back to legacy
- 'new': forces new API only
- 'legacy': forces legacy API only

The new API supports native PUT for updates (no delete+create needed).
- Add UNIFI profile to profiles.json with known failures (26, 43)
- Improve AuditRecords to properly return nil when no errors
- Add audit rules for: TXT > 255 chars, null MX, null SRV target
- Remove NS from supported types (requires IP, not hostname)
@zupolgec
Copy link
Collaborator Author

All green now 😀

Copy link
Collaborator

@tlimoncelli tlimoncelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the regex on line 41 of .goreleaser.yml

Please review Step 15 of https://docs.dnscontrol.org/developer-info/writing-providers for a checklist of files that should be modified.


// recordToLegacyMap converts a dnscontrol RecordConfig to a map for API requests.
// UniFi is strict about which fields can be set for each record type.
func recordToLegacyMap(domain string, rc *models.RecordConfig) (map[string]any, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter "domain" is not used. Please remove.

}

// recordToNew converts a dnscontrol RecordConfig to a UniFi new API record.
func recordToNew(domain string, rc *models.RecordConfig) (*dnsPolicyRecord, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter "domain" is never used. Please remove.

@tlimoncelli tlimoncelli merged commit ec957c7 into StackExchange:main Feb 24, 2026
12 checks passed
@zupolgec
Copy link
Collaborator Author

🥳 thanks @tlimoncelli

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants