fix(sys-dns-cloudflare-records): keep a record set pending when one entry cannot be judged

cloudflare_records_converged skipped an entry its expected() rejects (a
TXT value given as an int, a ttl of null) when building the per-owner
declarations, yet cloudflare_dns still writes for such an entry. In
[TXT t 12345, TXT t "12345" ttl 300] the second entry was judged
converged and skipped while the first was applied with ttl 1, so the
record flipped on every run. A record set declared more than once now
stays pending as a whole when any of its entries cannot be judged, like
the hazardous solo and absent entries already do. No producer in the
repository builds such a list today.

🎯 Fix: 93 %
💥 Break: 3 %
🌱 Efficiency: –
⚡ Speed: –
🛡️ Security: ~100 %
🏆 Score: 90
🚦 Gate: ✅ 90/5, efficiency and speed <= 100, security 100 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5.5 committed 2026-11-05 11:54:49 +00:00
1 parent 59b46235e8
commit d96fe45650
2 files changed
+32 -6

No files matched your search

@@ -360,9 +360,11 @@ def split(
zone already holds as declared, and one warning per zone whose
records could not be read, whose entries all stay pending. Every
entry of a record set declared more than once stays pending when
one of its entries is hazardous or two of them declare the record
the module finds by one ``_identity`` differently, since each
verdict alone would let the last entry's apply undo the other's.
one of its entries is hazardous, ``expected`` cannot judge one of
them, whose apply may still write the record set, or two of them
declare the record the module finds by one ``_identity`` differently,
since each verdict alone would let the last entry's apply undo the
other's.
"""
owners = [_owner(record) for record in records]
wants = [expected(record) for record in records]
@@ -372,9 +374,10 @@ def split(
for owner, record, want in zip(owners, records, wants, strict=True):
if owner is None or sizes[owner] < 2:
continue
if _hazardous(record) or (
want is not None
and declared.setdefault((owner, _identity(want)), want) != want
if (
want is None
or _hazardous(record)
or declared.setdefault((owner, _identity(want)), want) != want
):
blocked.add(owner)
zones: dict[str, list[Any] | None] = {}
@@ -471,6 +471,29 @@ class TestCloudflareRecordsConverged(unittest.TestCase):
self.assertEqual(pending, records)
self.assertEqual(labels, [])
def test_a_name_with_an_entry_the_plugin_cannot_judge_stays_pending(self):
t = f"t.{ZONE}"
txt = {"type": "TXT", "zone": ZONE, "name": "t"}
groups = {
"txt int value": (
[dict(txt, value=12345), dict(txt, value="12345", ttl=300)],
[rr("TXT", t, "12345", ttl=300)],
),
"txt int value last": (
[dict(txt, value="12345", ttl=300), dict(txt, value=12345)],
[rr("TXT", t, "12345", ttl=300)],
),
"a null ttl": (
[a("x", ttl=None), a("x", ttl=300)],
[rr("A", f"x.{ZONE}", "203.0.113.7", ttl=300)],
),
}
for group, (records, zone) in groups.items():
with self.subTest(group=group):
pending, labels, _ = run_split(records, _FakeCloudflare([zone]))
self.assertEqual(pending, records)
self.assertEqual(labels, [])
def test_entries_of_one_name_the_module_edits_as_distinct_or_equal_records_stay_judged(
self,
):