Skip to content

HEDNS: Preserve Dynamic DNS state & add DDNS key management#4087

Merged
tlimoncelli merged 5 commits intoStackExchange:mainfrom
hedger:hedger/hedns-fixes
Feb 20, 2026
Merged

HEDNS: Preserve Dynamic DNS state & add DDNS key management#4087
tlimoncelli merged 5 commits intoStackExchange:mainfrom
hedger:hedger/hedns-fixes

Conversation

@hedger
Copy link
Copy Markdown
Collaborator

@hedger hedger commented Feb 20, 2026

Modifying a Dynamic DNS record on Hurricane Electric DNS (e.g. changing TTL) silently dropped the dynamic flag and its associated DDNS key. There was also no way to manage DDNS keys from dnsconfig.js. This PR fixes #4085.
cc @rblenkinsopp

Changes

  • Record modifications now retain (or explicitly toggle) the Dynamic DNS flag. Unspecified records inherit their current state from the provider.
  • New record modifiers HEDNS_DYNAMIC_ON, HEDNS_DYNAMIC_OFF, and HEDNS_DDNS_KEY(key) allow controlling Dynamic DNS and setting DDNS keys from dnsconfig.js. Keys are write-only since HE DNS doesn't expose them for reading.
  • Zone export includes dynamic state in JS and TSV output formats for HEDNS.
  • Docs: updated provider docs and added record modifier reference pages.

Tests

Added new test groups to integration tests for HEDNS covering dynamic on/off, DDNS keys, state inheritance, and mixed records.

Full test run results
PASS
ok      github.com/StackExchange/dnscontrol/v4/integrationTest  1053.995s
--- PASS: TestDNSProviders (1041.65s)
    --- PASS: TestDNSProviders/example.com (1036.81s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty (0.68s)
        --- PASS: TestDNSProviders/example.com/00:A:Create_A (1.14s)
        --- PASS: TestDNSProviders/example.com/00:A:Change_A_target (1.23s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#01 (0.83s)
        --- PASS: TestDNSProviders/example.com/01:Apex:Create_A (1.54s)
        --- PASS: TestDNSProviders/example.com/01:Apex:Change_A_target (1.23s)
        --- PASS: TestDNSProviders/example.com/02:Protocol-Wildcard_***SKIPPED(excluded_by_not("HEDNS"))***:Empty (0.87s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#02 (0.38s)
        --- PASS: TestDNSProviders/example.com/03:AAAA:Create_AAAA (1.21s)
        --- PASS: TestDNSProviders/example.com/03:AAAA:Change_AAAA_target (1.11s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#03 (0.79s)
        --- PASS: TestDNSProviders/example.com/04:CNAME:Create_a_CNAME (2.28s)
        --- PASS: TestDNSProviders/example.com/04:CNAME:Change_CNAME_target (1.23s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#04 (0.69s)
        --- PASS: TestDNSProviders/example.com/05:CNAME-short:Create_a_CNAME (10.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#05 (1.19s)
        --- PASS: TestDNSProviders/example.com/06:MX:Create_MX_apex (1.50s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_apex (1.50s)
        --- PASS: TestDNSProviders/example.com/06:MX:Create_MX (1.80s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_target (1.35s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_p (19.12s)
        --- PASS: TestDNSProviders/example.com/07:RP_***SKIPPED(CanUseRP_not_supported)***:Empty (9.23s)
        --- PASS: TestDNSProviders/example.com/08:RP_***SKIPPED(CanUseRP_not_supported)***:Empty (0.48s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#06 (0.53s)
        --- PASS: TestDNSProviders/example.com/09:TXT:Create_TXT (1.82s)
        --- PASS: TestDNSProviders/example.com/09:TXT:Change_TXT_target (9.19s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#07 (0.86s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:CreateManyAtLabel (2.22s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Empty (9.90s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Create_an_A_record (1.23s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Add_at_label1 (1.36s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Add_at_label2 (1.37s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#08 (1.39s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:CreateManyTypesAtLabel (2.29s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Empty (1.32s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Create_an_A_record (1.15s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Add_Type_At_Label (1.36s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Add_Type_At_Label#01 (1.48s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#09 (1.44s)
        --- PASS: TestDNSProviders/example.com/12:Attl:Create_Arc (10.19s)
        --- PASS: TestDNSProviders/example.com/12:Attl:Change_TTL (1.23s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#10 (0.69s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Start (2.08s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_a_ttl (1.77s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_single_target_from_set (1.22s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_all_ttls (10.37s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#11 (1.39s)
        --- PASS: TestDNSProviders/example.com/14:add_to_label_and_change_orig_ttl:Setup (1.23s)
        --- PASS: TestDNSProviders/example.com/14:add_to_label_and_change_orig_ttl:Add_at_same_label,_new_ttl (1.57s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#12 (1.08s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Create_A (1.19s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Change_to_MX (1.60s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Change_back_to_A (1.67s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#13 (0.69s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Create_a_CNAME (1.25s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Change_to_A_record (9.23s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Change_back_to_CNAME (10.16s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#14 (9.51s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS:Create_a_HTTPS_record (1.68s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS:Change_HTTPS_priority (11.36s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS:Change_HTTPS_target (1.22s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS:Change_HTTPS_params (1.20s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS:Change_HTTPS_params-empty (1.23s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS:Change_HTTPS_all (1.60s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#15 (0.83s)
        --- PASS: TestDNSProviders/example.com/18:Ech:Create_a_HTTPS_record (1.23s)
        --- PASS: TestDNSProviders/example.com/18:Ech:Add_an_ECH_key (1.18s)
        --- PASS: TestDNSProviders/example.com/18:Ech:Ignore_the_ECH_key_while_changing_other_values (1.16s)
        --- PASS: TestDNSProviders/example.com/18:Ech:Change_the_ECH_key_and_other_values (8.88s)
        --- PASS: TestDNSProviders/example.com/18:Ech:Another_domain_with_a_different_ECH_value (1.58s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#16 (0.84s)
        --- PASS: TestDNSProviders/example.com/19:SVCB:Create_a_SVCB_record (1.23s)
        --- PASS: TestDNSProviders/example.com/19:SVCB:Change_SVCB_priority (1.24s)
        --- PASS: TestDNSProviders/example.com/19:SVCB:Change_SVCB_target (1.27s)
        --- PASS: TestDNSProviders/example.com/19:SVCB:Change_SVCB_params (1.20s)
        --- PASS: TestDNSProviders/example.com/19:SVCB:Change_SVCB_params-empty (1.17s)
        --- PASS: TestDNSProviders/example.com/19:SVCB:Change_SVCB_all (1.12s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#17 (0.78s)
        --- PASS: TestDNSProviders/example.com/20:CNAME:Record_pointing_to_@ (10.88s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#18 (2.19s)
        --- PASS: TestDNSProviders/example.com/21:ApexMX:Record_pointing_to_@ (1.80s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#19 (1.05s)
        --- SKIP: TestDNSProviders/example.com/22:NullMX:create (0.00s)
        --- PASS: TestDNSProviders/example.com/22:NullMX:unnull (12.58s)
        --- SKIP: TestDNSProviders/example.com/22:NullMX:renull (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#20 (1.81s)
        --- SKIP: TestDNSProviders/example.com/23:NullMXApex:create (0.00s)
        --- PASS: TestDNSProviders/example.com/23:NullMXApex:unnull (13.39s)
        --- SKIP: TestDNSProviders/example.com/23:NullMXApex:renull (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#21 (10.49s)
        --- PASS: TestDNSProviders/example.com/24:NS:NS_for_subdomain (1.30s)
        --- PASS: TestDNSProviders/example.com/24:NS:Dual_NS_for_subdomain (1.50s)
        --- PASS: TestDNSProviders/example.com/24:NS:NS_Record_pointing_to_@ (2.47s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#22 (1.17s)
        --- PASS: TestDNSProviders/example.com/25:NS_only_APEX:Single_NS_at_apex (1.42s)
        --- PASS: TestDNSProviders/example.com/25:NS_only_APEX:Dual_NS_at_apex (1.47s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#23 (1.01s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_0-byte_TXT (1.19s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_254-byte_TXT (1.57s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_255-byte_TXT (1.45s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_256-byte_TXT (1.44s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_509-byte_TXT (1.57s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_510-byte_TXT (1.65s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_511-byte_TXT (11.49s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_764-byte_TXT (9.13s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_765-byte_TXT (10.48s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_766-byte_TXT (8.60s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_single-quote (9.92s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_backtick (1.92s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-1interior (1.58s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_2_dq-2interior (1.57s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-left (1.24s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-right (1.29s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_semicolon (1.66s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_semicolon_ws (1.58s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_interior_ws (1.56s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_trailing_ws (1.48s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:Create_a_TXT/SPF (1.52s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#24 (9.46s)
        --- PASS: TestDNSProviders/example.com/27:TXT_backslashes:TXT_with_backslashs (2.63s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#25 (1.80s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Create_CAPS (1.46s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Downcase_label (1.25s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Downcase_target (1.92s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Upcase_both (11.17s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#26 (9.31s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:initial (1.55s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:changeOne (1.20s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:deleteOne (1.05s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:addOne (9.10s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#27 (0.99s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:initial (11.77s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:changeOne (1.26s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:deleteOne (1.19s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:addOne (11.18s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#28 (3.65s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Internationalized_name (11.14s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Change_IDN (1.29s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Chinese_label (1.60s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Internationalized_CNAME_Target (9.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#29 (0.70s)
        --- PASS: TestDNSProviders/example.com/32:IDNAs_in_CNAME_targets:IDN_CNAME_AND_Target (1.38s)
        --- PASS: TestDNSProviders/example.com/33:pager101_***SKIPPED(excluded_by_not("HEDNS"))***:Empty (0.68s)
        --- PASS: TestDNSProviders/example.com/34:pager601_***SKIPPED(disabled_by_only)***:Empty (2.12s)
        --- PASS: TestDNSProviders/example.com/35:pager1201_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/36:batchRecordswithOthers_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#30 (0.49s)
        --- PASS: TestDNSProviders/example.com/37:CAA:CAA_record (17.47s)
        --- PASS: TestDNSProviders/example.com/37:CAA:CAA_change_tag (11.19s)
        --- PASS: TestDNSProviders/example.com/37:CAA:CAA_change_target (10.06s)
        --- PASS: TestDNSProviders/example.com/37:CAA:CAA_change_flag (1.32s)
        --- PASS: TestDNSProviders/example.com/37:CAA:CAA_many_records (1.55s)
        --- PASS: TestDNSProviders/example.com/37:CAA:CAA_whitespace (1.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#31 (0.77s)
        --- PASS: TestDNSProviders/example.com/38:LOC:Single_LOC_record (11.28s)
        --- PASS: TestDNSProviders/example.com/38:LOC:Update_single_LOC_record (4.88s)
        --- PASS: TestDNSProviders/example.com/38:LOC:Multiple_LOC_records-create_a-d_modify_apex (17.60s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#32 (1.99s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_record (1.16s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_second_record (1.27s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_delete_second_record (2.54s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_change_order (1.30s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_change_preference (10.28s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_change_flags (1.26s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_change_service (1.89s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_change_regexp (1.55s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_remove_regexp_and_add_target (1.52s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR:NAPTR_change_target (8.69s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#33 (9.01s)
        --- PASS: TestDNSProviders/example.com/40:PTR:Create_PTR_record (8.69s)
        --- PASS: TestDNSProviders/example.com/40:PTR:Modify_PTR_record (1.27s)
        --- PASS: TestDNSProviders/example.com/41:SOA_***SKIPPED(CanUseSOA_not_supported)***:Empty (1.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#34 (0.42s)
        --- PASS: TestDNSProviders/example.com/42:SRV:SRV_record (1.55s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Second_SRV_record,_same_prio (1.73s)
        --- PASS: TestDNSProviders/example.com/42:SRV:3_SRV (1.29s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Delete_one (10.99s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Target (9.05s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Priority (1.18s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Weight (9.09s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Port (9.50s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Empty (1.13s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Null_Target (8.77s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#35 (0.68s)
        --- PASS: TestDNSProviders/example.com/43:SRV:Create_SRV333 (1.24s)
        --- PASS: TestDNSProviders/example.com/43:SRV:Change_TTL999 (1.57s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#36 (9.64s)
        --- PASS: TestDNSProviders/example.com/44:SSHFP:SSHFP_record (9.94s)
        --- PASS: TestDNSProviders/example.com/44:SSHFP:SSHFP_change_algorithm (8.59s)
        --- PASS: TestDNSProviders/example.com/44:SSHFP:SSHFP_change_fingerprint_and_type (1.20s)
        --- PASS: TestDNSProviders/example.com/45:TLSA_***SKIPPED(CanUseTLSA_not_supported)***:Empty (0.71s)
        --- PASS: TestDNSProviders/example.com/46:DS_***SKIPPED(CanUseDS_not_supported)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/47:DS_(children_only)_***SKIPPED(CanUseDSForChildren_not_supported)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/48:DS_(children_only)_CLOUDNS_***SKIPPED(CanUseDSForChildren_not_supported)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/49:DHCID_***SKIPPED(CanUseDHCID_not_supported)***:Empty (0.43s)
        --- PASS: TestDNSProviders/example.com/50:DNAME_***SKIPPED(CanUseDNAME_not_supported)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/51:DNSKEY_***SKIPPED(CanUseDNSKEY_not_supported)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#37 (0.38s)
        --- PASS: TestDNSProviders/example.com/52:ALIAS_on_apex:ALIAS_at_root (6.42s)
        --- PASS: TestDNSProviders/example.com/52:ALIAS_on_apex:change_it (1.55s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#38 (0.70s)
        --- PASS: TestDNSProviders/example.com/53:ALIAS_to_nonfqdn:ALIAS_at_root (10.56s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#39 (1.11s)
        --- PASS: TestDNSProviders/example.com/54:ALIAS_on_subdomain:ALIAS_at_subdomain (10.94s)
        --- PASS: TestDNSProviders/example.com/54:ALIAS_on_subdomain:change_it (1.51s)
        --- PASS: TestDNSProviders/example.com/55:AZURE_ALIAS_A_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (10.00s)
        --- PASS: TestDNSProviders/example.com/56:AZURE_ALIAS_CNAME_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (0.67s)
        --- PASS: TestDNSProviders/example.com/57:R53_ALIAS2_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.53s)
        --- PASS: TestDNSProviders/example.com/58:R53_ALIAS_ORDER_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.40s)
        --- PASS: TestDNSProviders/example.com/59:R53_ALIAS_CNAME_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.45s)
        --- PASS: TestDNSProviders/example.com/60:R53_ALIAS_Loop_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/61:R53_alias_pre-existing_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/62:R53_alias_evaluate_target_health_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.47s)
        --- PASS: TestDNSProviders/example.com/63:R53_B3493_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/64:R53_B3493_REV_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/65:CF_REDIRECT_CONVERT_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/66:CLOUDFLAREAPI_SINGLE_REDIRECT_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.45s)
        --- PASS: TestDNSProviders/example.com/67:CF_PROXY_A_create_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/68:CF_PROXY_A_off_to_on_***SKIPPED(disabled_by_only)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/69:CF_PROXY_A_on_to_off_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/70:CF_PROXY_CNAME_create_***SKIPPED(disabled_by_only)***:Empty (0.46s)
        --- PASS: TestDNSProviders/example.com/71:CF_PROXY_CNAME_off_to_on_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/72:CF_PROXY_CNAME_on_to_off_***SKIPPED(disabled_by_only)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/73:CF_CNAME_FLATTEN_create_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.82s)
        --- PASS: TestDNSProviders/example.com/74:CF_CNAME_FLATTEN_off_to_on_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/75:CF_CNAME_FLATTEN_on_to_off_***SKIPPED(excluded_by_alltrue([false]))***:Empty (1.75s)
        --- PASS: TestDNSProviders/example.com/76:CF_COMMENT_create_***SKIPPED(disabled_by_only)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/77:CF_TAGS_create_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.46s)
        --- PASS: TestDNSProviders/example.com/78:CF_WORKER_ROUTE_***SKIPPED(disabled_by_only)***:Empty (0.43s)
        --- PASS: TestDNSProviders/example.com/79:ADGUARDHOME_A_PASSTHROUGH_***SKIPPED(disabled_by_only)***:Empty (0.51s)
        --- PASS: TestDNSProviders/example.com/80:ADGUARDHOME_AAAA_PASSTHROUGH_***SKIPPED(disabled_by_only)***:Empty (0.46s)
        --- PASS: TestDNSProviders/example.com/81:VERCEL_CAA_whitespace_-_cansignhttpexchanges_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#40 (0.50s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:Create_some_records (18.35s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_label (0.88s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS (0.88s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_label,type (0.75s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#01 (0.83s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_label,type,target (0.74s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#02 (0.83s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_type (0.74s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#03 (0.83s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_type,target (0.75s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#04 (0.83s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_target (0.75s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#05 (0.84s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_manytypes (0.85s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#06 (3.33s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:ignore_label,type,target=* (0.87s)
        --- PASS: TestDNSProviders/example.com/82:IGNORE_main:VERIFY_PREVIOUS#07 (0.88s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#41 (7.91s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:Create_some_records (3.30s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_label (0.82s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS (0.96s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_label,type (1.15s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS#01 (0.90s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_label,type,target (0.86s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS#02 (0.87s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_type (0.93s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS#03 (0.84s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_type,target (0.83s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS#04 (0.76s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_target (0.85s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS#05 (0.87s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:apex_manytypes (0.85s)
        --- PASS: TestDNSProviders/example.com/83:IGNORE_apex:VERIFY_PREVIOUS#06 (0.86s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#42 (3.29s)
        --- PASS: TestDNSProviders/example.com/84:IGNORE_unsafe:Create_some_records (3.54s)
        --- PASS: TestDNSProviders/example.com/84:IGNORE_unsafe:ignore_unsafe_apex (0.88s)
        --- PASS: TestDNSProviders/example.com/84:IGNORE_unsafe:VERIFY_PREVIOUS (0.87s)
        --- PASS: TestDNSProviders/example.com/84:IGNORE_unsafe:ignore_unsafe_label (0.86s)
        --- PASS: TestDNSProviders/example.com/84:IGNORE_unsafe:VERIFY_PREVIOUS#01 (0.82s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#43 (1.67s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:Create_some_records (5.76s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:ignore_label=foo.* (0.83s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:VERIFY_PREVIOUS (0.74s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:ignore_label=foo.bat,type (0.83s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:VERIFY_PREVIOUS#01 (0.75s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:ignore_target=*.domain (0.83s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_wilds:VERIFY_PREVIOUS#02 (0.88s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#44 (15.89s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:Create_some_records (30.83s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:IGNORE_change_ByZone (1.21s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:VERIFY_PREVIOUS (0.82s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:IGNORE_change_ByLabel (1.41s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:VERIFY_PREVIOUS#01 (0.88s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:IGNORE_change_ByRecordSet (8.39s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:VERIFY_PREVIOUS#02 (0.77s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:IGNORE_change_ByRecord (1.34s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_with_modify:VERIFY_PREVIOUS#03 (2.11s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#45 (21.46s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_TARGET_b2285:Create_some_records (2.36s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_TARGET_b2285:Add_a_new_record_-_ignoring_test.foo.com. (0.50s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_TARGET_b2285:VERIFY_PREVIOUS (0.84s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#46 (12.21s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_everything_b2822:Create_some_records (11.28s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_everything_b2822:ignore_them_all (0.95s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_everything_b2822:VERIFY_PREVIOUS (1.23s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#47 (1.92s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:Create_some_records (3.34s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:ignore (1.04s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:VERIFY_PREVIOUS (0.75s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:Verify_nothing_changed (0.82s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:VERIFY_PREVIOUS#01 (0.75s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:ignore_with_change (1.17s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_w/change_b3227:VERIFY_PREVIOUS#02 (0.75s)
        --- PASS: TestDNSProviders/example.com/90:structured_TXT_***SKIPPED(disabled_by_only)***:Empty (0.99s)
        --- PASS: TestDNSProviders/example.com/91:structured_TXT_as_native_records_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/92:CLOUDNS_geodns_tests_***SKIPPED(disabled_by_only)***:Empty (0.38s)
        --- PASS: TestDNSProviders/example.com/93:PORKBUN_URLFWD_tests_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/94:GCORE_metadata_tests_***SKIPPED(disabled_by_only)***:Empty (0.45s)
        --- PASS: TestDNSProviders/example.com/95:NAMECHEAP_url_redirect_records_***SKIPPED(disabled_by_only)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/96:OPENPGPKEY_***SKIPPED(CanUseOPENPGPKEY_not_supported)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/97:SMIMEA_***SKIPPED(CanUseSMIMEA_not_supported)***:Empty (0.37s)
        --- PASS: TestDNSProviders/example.com/98:Bunny_DNS_Pull_Zone_***SKIPPED(disabled_by_only)***:Empty (1.68s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#48 (0.38s)
        --- PASS: TestDNSProviders/example.com/99:HEDNS_DYNAMIC_A_lifecycle:Create_dynamic_A (7.35s)
        --- PASS: TestDNSProviders/example.com/99:HEDNS_DYNAMIC_A_lifecycle:Change_target_preserves_dynamic (1.20s)
        --- PASS: TestDNSProviders/example.com/99:HEDNS_DYNAMIC_A_lifecycle:Turn_off_dynamic (11.54s)
        --- PASS: TestDNSProviders/example.com/99:HEDNS_DYNAMIC_A_lifecycle:Turn_on_dynamic (1.19s)
        --- PASS: TestDNSProviders/example.com/99:HEDNS_DYNAMIC_A_lifecycle:Inherit_dynamic_on_modify (1.23s)
        --- PASS: TestDNSProviders/example.com/99:HEDNS_DYNAMIC_A_lifecycle:Add_static_record (1.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#49 (1.11s)
        --- PASS: TestDNSProviders/example.com/100:HEDNS_DYNAMIC_AAAA+TXT:Create_dynamic_AAAA (1.14s)
        --- PASS: TestDNSProviders/example.com/100:HEDNS_DYNAMIC_AAAA+TXT:Change_dynamic_AAAA_target (1.17s)
        --- PASS: TestDNSProviders/example.com/100:HEDNS_DYNAMIC_AAAA+TXT:Create_dynamic_TXT (1.43s)
        --- PASS: TestDNSProviders/example.com/100:HEDNS_DYNAMIC_AAAA+TXT:Turn_off_dynamic_TXT (1.19s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#50 (9.13s)
        --- PASS: TestDNSProviders/example.com/101:HEDNS_DDNS_KEY:Create_A_with_DDNS_key_(implicit_dynamic) (1.53s)
        --- PASS: TestDNSProviders/example.com/101:HEDNS_DDNS_KEY:Change_target_+_key (1.40s)
        --- PASS: TestDNSProviders/example.com/101:HEDNS_DDNS_KEY:Create_AAAA_with_DDNS_key (10.18s)
        --- PASS: TestDNSProviders/example.com/101:HEDNS_DDNS_KEY:Change_AAAA_target_+_key (1.44s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#51 (0.74s)
        --- PASS: TestDNSProviders/example.com/102:HEDNS_DYNAMIC_mixed_records:Create_mix_of_dynamic_and_static (1.52s)
        --- PASS: TestDNSProviders/example.com/102:HEDNS_DYNAMIC_mixed_records:Modify_only_the_static_record (18.29s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#52 (1.05s)
        --- PASS: TestDNSProviders/example.com/103:final:final (1.24s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#53 (1.45s)
        --- PASS: TestDNSProviders/example.com/104:final:final (10.52s)
=== RUN   TestDualProviders
Testing Profile="HEDNS" (TYPE="HEDNS")
    provider_test.go:50: Clearing everything
    provider_test.go:44: #1:
        - DELETE final.example.com TXT "TestDNSProviders was successful!" ttl=300
    provider_test.go:57: Adding test nameservers
    provider_test.go:44: #1:
        + CREATE example.com NS ns1.example.com. ttl=300
    provider_test.go:44: #2:
        + CREATE example.com NS ns2.example.com. ttl=300
    provider_test.go:60: Running again to ensure stability
    provider_test.go:76: Removing test nameservers
    provider_test.go:44: #1:
        - DELETE example.com NS ns1.example.com. ttl=300
    provider_test.go:44: #2:
        - DELETE example.com NS ns2.example.com. ttl=300
--- PASS: TestDualProviders (11.24s)
=== RUN   TestNameserverDots
Testing Profile="HEDNS" (TYPE="HEDNS")
=== RUN   TestNameserverDots/No_trailing_dot_in_nameserver
--- PASS: TestNameserverDots (0.20s)
    --- PASS: TestNameserverDots/No_trailing_dot_in_nameserver (0.00s)
=== RUN   TestDuplicateNameservers
Testing Profile="HEDNS" (TYPE="HEDNS")
    provider_test.go:145: Skipping. Deduplication logic is not implemented for this provider.
--- SKIP: TestDuplicateNameservers (0.19s)
PASS
ok      github.com/StackExchange/dnscontrol/v4/integrationTest  1053.995s

@hedger hedger force-pushed the hedger/hedns-fixes branch from d109c05 to 6a85720 Compare February 20, 2026 17:58
@hedger
Copy link
Copy Markdown
Collaborator Author

hedger commented Feb 20, 2026

@tlimoncelli
Some thoughts on the architecture: now, some parts that are tied to specific providers are implemented in other parts of the codebase (including provider-specific fields in getZones.go - formatDsl, GetZone()/tsv). That's somewhat suboptimal, and I'd suggest refactoring and improving provider interfaces to include these parts in their implementation. I noticed that when implementing #4083 as well.

@tlimoncelli
Copy link
Copy Markdown
Contributor

@tlimoncelli Some thoughts on the architecture: now, some parts that are tied to specific providers are implemented in other parts of the codebase (including provider-specific fields in getZones.go - formatDsl, GetZone()/tsv). That's somewhat suboptimal, and I'd suggest refactoring and improving provider interfaces to include these parts in their implementation. I noticed that when implementing #4083 as well.

I agree. I have a big overhaul planned which will isolate anything related to a particular provider to a single directory. (That's the hope, at least!)

Copy link
Copy Markdown
Contributor

@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.

Looks good! Please rebase and fix conflicts. Thanks for contributing this!

@hedger hedger force-pushed the hedger/hedns-fixes branch from e56eb52 to 107164f Compare February 20, 2026 20:05
@hedger
Copy link
Copy Markdown
Collaborator Author

hedger commented Feb 20, 2026

@tlimoncelli rebased. Thank you!

@tlimoncelli tlimoncelli merged commit 3c18268 into StackExchange:main Feb 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HEDNS: TXT updates reset and remove API key for entries

2 participants