mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 10:19:09 +00:00 
			
		
		
		
	refactor(dns): replace sys-dns-parent-hosts with sys-dns-wildcards; emit only *.parent wildcards from CURRENT_PLAY_DOMAINS_ALL
Rename filter parent_build_records→wildcard_records; create only wildcard (*.parent) A/AAAA records (no base/apex); switch to CURRENT_PLAY_DOMAINS_ALL; update vars to SYN_DNS_WILDCARD_RECORDS; adjust role/task names, defaults, and docs; add unittest expecting *.a.b from www.a.b.example.com. See: https://chatgpt.com/share/68c35dc1-7170-800f-8fbe-772e61780597
This commit is contained in:
		| @@ -1,131 +0,0 @@ | ||||
| import os | ||||
| import sys | ||||
| import unittest | ||||
|  | ||||
| # Make the filter plugin importable | ||||
| ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../..")) | ||||
| FILTER_PATH = os.path.join(ROOT, "roles", "sys-dns-parent-hosts", "filter_plugins") | ||||
| if FILTER_PATH not in sys.path: | ||||
|     sys.path.insert(0, FILTER_PATH) | ||||
|  | ||||
| from parent_dns import parent_build_records  # noqa: E402 | ||||
|  | ||||
|  | ||||
| def has_record(records, rtype, name, zone): | ||||
|     """True if an exact (type, name, zone) record exists.""" | ||||
|     return any( | ||||
|         r.get("type") == rtype and r.get("name") == name and r.get("zone") == zone | ||||
|         for r in records | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def has_name_or_wildcard(records, rtype, label, zone): | ||||
|     """True if either <label> or *.<label> exists for (type, zone).""" | ||||
|     return has_record(records, rtype, label, zone) or has_record( | ||||
|         records, rtype, f"*.{label}", zone | ||||
|     ) | ||||
|  | ||||
|  | ||||
| class TestParentDNS(unittest.TestCase): | ||||
|     def test_end_to_end_with_ipv6(self): | ||||
|         current = { | ||||
|             "web-app-foo": [ | ||||
|                 "example.com", | ||||
|                 "wiki.example.com", | ||||
|                 "c.wiki.example.com", | ||||
|                 "a.b.example.com", | ||||
|             ], | ||||
|             "web-app-bar": ["foo.other.com"],  # different apex -> ignored | ||||
|         } | ||||
|  | ||||
|         recs = parent_build_records( | ||||
|             current_play_domains=current, | ||||
|             apex="example.com", | ||||
|             ip4="192.0.2.10", | ||||
|             ip6="2001:db8::10",  # AAAA may or may not be emitted by role; treat as optional | ||||
|             proxied=True, | ||||
|             explicit_domains=None, | ||||
|             include_apex=True, | ||||
|             min_child_depth=2, | ||||
|         ) | ||||
|  | ||||
|         # Apex must resolve | ||||
|         self.assertTrue(has_record(recs, "A", "@", "example.com")) | ||||
|  | ||||
|         # Parents may be plain or wildcard (or both) | ||||
|         self.assertTrue(has_name_or_wildcard(recs, "A", "wiki", "example.com")) | ||||
|         self.assertTrue(has_name_or_wildcard(recs, "A", "b", "example.com")) | ||||
|  | ||||
|         # AAAA optional: if present, at least apex AAAA must exist | ||||
|         if any(r.get("type") == "AAAA" for r in recs): | ||||
|             self.assertTrue(has_record(recs, "AAAA", "@", "example.com")) | ||||
|  | ||||
|         # Proxied flag is propagated | ||||
|         self.assertTrue(all(r.get("proxied") is True for r in recs if r["type"] in ("A", "AAAA"))) | ||||
|  | ||||
|     def test_explicit_domains_without_ipv6(self): | ||||
|         explicit = ["example.com", "c.wiki.example.com", "x.y.example.com"] | ||||
|  | ||||
|         recs = parent_build_records( | ||||
|             current_play_domains={"ignore": ["foo.example.com"]}, | ||||
|             apex="example.com", | ||||
|             ip4="198.51.100.5", | ||||
|             ip6="",  # No IPv6 -> no AAAA expected | ||||
|             proxied=False, | ||||
|             explicit_domains=explicit, | ||||
|             include_apex=True, | ||||
|             min_child_depth=2, | ||||
|         ) | ||||
|  | ||||
|         # Apex must resolve | ||||
|         self.assertTrue(has_record(recs, "A", "@", "example.com")) | ||||
|  | ||||
|         # Parents may be plain or wildcard | ||||
|         self.assertTrue(has_name_or_wildcard(recs, "A", "wiki", "example.com")) | ||||
|         self.assertTrue(has_name_or_wildcard(recs, "A", "y", "example.com")) | ||||
|  | ||||
|         # No IPv6 supplied -> there should be no AAAA records | ||||
|         self.assertFalse(any(r.get("type") == "AAAA" for r in recs)) | ||||
|  | ||||
|     def test_current_play_domains_may_contain_dicts(self): | ||||
|         # Dict values with strings and lists inside must be accepted and flattened. | ||||
|         current = { | ||||
|             "web-app-foo": { | ||||
|                 "prod": "wiki.example.com", | ||||
|                 "preview": ["c.wiki.example.com"], | ||||
|             }, | ||||
|             "web-app-bar": ["irrelevant.other.com"],  # different apex, ignored | ||||
|         } | ||||
|  | ||||
|         recs = parent_build_records( | ||||
|             current_play_domains=current, | ||||
|             apex="example.com", | ||||
|             ip4="203.0.113.7", | ||||
|             ip6=None, | ||||
|             proxied=False, | ||||
|             explicit_domains=None, | ||||
|             include_apex=True, | ||||
|             min_child_depth=2, | ||||
|         ) | ||||
|  | ||||
|         self.assertTrue(has_record(recs, "A", "@", "example.com")) | ||||
|         self.assertTrue(has_name_or_wildcard(recs, "A", "wiki", "example.com")) | ||||
|  | ||||
|     def test_invalid_inputs_raise(self): | ||||
|         with self.assertRaises(Exception): | ||||
|             parent_build_records( | ||||
|                 current_play_domains={"ok": ["example.com"]}, | ||||
|                 apex="",  # invalid apex | ||||
|                 ip4="192.0.2.1", | ||||
|             ) | ||||
|  | ||||
|         with self.assertRaises(Exception): | ||||
|             parent_build_records( | ||||
|                 current_play_domains={"ok": ["example.com"]}, | ||||
|                 apex="example.com", | ||||
|                 ip4="",  # required | ||||
|             ) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     unittest.main() | ||||
| @@ -0,0 +1,211 @@ | ||||
| # tests/unit/roles/sys-dns-wildcards/filter_plugins/test_wildcard_dns.py | ||||
| import unittest | ||||
| import importlib.util | ||||
| from pathlib import Path | ||||
|  | ||||
|  | ||||
| def _load_module(): | ||||
|     """ | ||||
|     Load the wildcard_dns filter plugin from: | ||||
|       roles/sys-dns-wildcards/filter_plugins/wildcard_dns.py | ||||
|     """ | ||||
|     here = Path(__file__).resolve() | ||||
|     # Go up to repository root (…/tests/unit/roles/… → 5 levels up) | ||||
|     repo_root = here.parents[5] if len(here.parents) >= 6 else here.parents[0] | ||||
|  | ||||
|     path = repo_root / "roles" / "sys-dns-wildcards" / "filter_plugins" / "wildcard_dns.py" | ||||
|     if not path.exists(): | ||||
|         raise FileNotFoundError(f"Could not find {path}") | ||||
|  | ||||
|     spec = importlib.util.spec_from_file_location("wildcard_dns", path) | ||||
|     mod = importlib.util.module_from_spec(spec) | ||||
|     assert spec and spec.loader | ||||
|     spec.loader.exec_module(mod)  # type: ignore[attr-defined] | ||||
|     return mod | ||||
|  | ||||
|  | ||||
| _wildcard_dns = _load_module() | ||||
|  | ||||
|  | ||||
| def _get_filter(): | ||||
|     """Return the wildcard_records filter function from the plugin.""" | ||||
|     fm = _wildcard_dns.FilterModule() | ||||
|     filters = fm.filters() | ||||
|     if "wildcard_records" not in filters: | ||||
|         raise AssertionError("wildcard_records filter not found") | ||||
|     return filters["wildcard_records"] | ||||
|  | ||||
|  | ||||
| def _as_set(records): | ||||
|     """Normalize records for order-independent comparison.""" | ||||
|     return { | ||||
|         (r.get("type"), r.get("name"), r.get("content"), bool(r.get("proxied"))) | ||||
|         for r in records | ||||
|     } | ||||
|  | ||||
|  | ||||
| class TestWildcardDNS(unittest.TestCase): | ||||
|     def setUp(self): | ||||
|         self.wildcard_records = _get_filter() | ||||
|  | ||||
|     def test_only_wildcards_no_apex_or_base(self): | ||||
|         apex = "example.com" | ||||
|         cpda = { | ||||
|             "svc-a": ["c.wiki.example.com", "a.b.example.com"], | ||||
|             "svc-b": {"extra": ["www.a.b.example.com"]}, | ||||
|             "svc-c": "example.com", | ||||
|         } | ||||
|  | ||||
|         recs = self.wildcard_records( | ||||
|             current_play_domains_all=cpda, | ||||
|             apex=apex, | ||||
|             ip4="203.0.113.10", | ||||
|             ip6="2606:4700:4700::1111", | ||||
|             proxied=True, | ||||
|             explicit_domains=None, | ||||
|             min_child_depth=2, | ||||
|             ipv6_enabled=True, | ||||
|         ) | ||||
|  | ||||
|         got = _as_set(recs) | ||||
|         expected = { | ||||
|             ("A", "*.wiki", "203.0.113.10", True), | ||||
|             ("AAAA", "*.wiki", "2606:4700:4700::1111", True), | ||||
|             ("A", "*.b", "203.0.113.10", True), | ||||
|             ("AAAA", "*.b", "2606:4700:4700::1111", True), | ||||
|             # now included because www.a.b.example.com promotes a.b.example.com as a parent | ||||
|             ("A", "*.a.b", "203.0.113.10", True), | ||||
|             ("AAAA", "*.a.b", "2606:4700:4700::1111", True), | ||||
|         } | ||||
|         self.assertEqual(got, expected) | ||||
|  | ||||
|     def test_min_child_depth_prevents_apex_wildcard(self): | ||||
|         apex = "example.com" | ||||
|         cpda = {"svc": ["x.example.com"]}  # depth = 1 | ||||
|  | ||||
|         recs = self.wildcard_records( | ||||
|             current_play_domains_all=cpda, | ||||
|             apex=apex, | ||||
|             ip4="198.51.100.42", | ||||
|             ip6="2606:4700:4700::1111", | ||||
|             proxied=False, | ||||
|             explicit_domains=None, | ||||
|             min_child_depth=2,  # requires >= 2 → no parent derived | ||||
|             ipv6_enabled=True, | ||||
|         ) | ||||
|         self.assertEqual(recs, []) | ||||
|  | ||||
|     def test_ipv6_disabled_and_private_ipv6_filtered(self): | ||||
|         apex = "example.com" | ||||
|         cpda = {"svc": ["a.b.example.com"]} | ||||
|  | ||||
|         # IPv6 disabled → only A record | ||||
|         recs1 = self.wildcard_records( | ||||
|             current_play_domains_all=cpda, | ||||
|             apex=apex, | ||||
|             ip4="203.0.113.9", | ||||
|             ip6="2606:4700:4700::1111", | ||||
|             proxied=False, | ||||
|             explicit_domains=None, | ||||
|             min_child_depth=2, | ||||
|             ipv6_enabled=False, | ||||
|         ) | ||||
|         self.assertEqual(_as_set(recs1), {("A", "*.b", "203.0.113.9", False)}) | ||||
|  | ||||
|         # IPv6 enabled but ULA (not global) → skip AAAA | ||||
|         recs2 = self.wildcard_records( | ||||
|             current_play_domains_all=cpda, | ||||
|             apex=apex, | ||||
|             ip4="203.0.113.9", | ||||
|             ip6="fd00::1", | ||||
|             proxied=False, | ||||
|             explicit_domains=None, | ||||
|             min_child_depth=2, | ||||
|             ipv6_enabled=True, | ||||
|         ) | ||||
|         self.assertEqual(_as_set(recs2), {("A", "*.b", "203.0.113.9", False)}) | ||||
|  | ||||
|     def test_proxied_flag_true_is_set(self): | ||||
|         recs = self.wildcard_records( | ||||
|             current_play_domains_all={"svc": ["a.b.example.com"]}, | ||||
|             apex="example.com", | ||||
|             ip4="203.0.113.7", | ||||
|             ip6=None, | ||||
|             proxied=True, | ||||
|             explicit_domains=None, | ||||
|             min_child_depth=2, | ||||
|             ipv6_enabled=True, | ||||
|         ) | ||||
|         self.assertTrue(all(r.get("proxied") is True for r in recs)) | ||||
|         self.assertEqual(_as_set(recs), {("A", "*.b", "203.0.113.7", True)}) | ||||
|  | ||||
|     def test_explicit_domains_override_source(self): | ||||
|         cpda = {"svc": ["ignore.me.example.com", "a.b.example.com"]} | ||||
|         explicit = ["c.wiki.example.com"] | ||||
|  | ||||
|         recs = self.wildcard_records( | ||||
|             current_play_domains_all=cpda, | ||||
|             apex="example.com", | ||||
|             ip4="203.0.113.5", | ||||
|             ip6="2606:4700:4700::1111", | ||||
|             proxied=False, | ||||
|             explicit_domains=explicit, | ||||
|             min_child_depth=2, | ||||
|             ipv6_enabled=True, | ||||
|         ) | ||||
|         self.assertEqual( | ||||
|             _as_set(recs), | ||||
|             { | ||||
|                 ("A", "*.wiki", "203.0.113.5", False), | ||||
|                 ("AAAA", "*.wiki", "2606:4700:4700::1111", False), | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     def test_nested_structures_flattened_correctly(self): | ||||
|         cpda = { | ||||
|             "svc1": { | ||||
|                 "primary": ["c.wiki.example.com"], | ||||
|                 "extra": {"alt": ["a.b.example.com"]}, | ||||
|             }, | ||||
|             "svc2": "www.a.b.example.com", | ||||
|             "svc3": ["x.example.net"],  # wrong apex → ignored | ||||
|         } | ||||
|  | ||||
|         recs = self.wildcard_records( | ||||
|             current_play_domains_all=cpda, | ||||
|             apex="example.com", | ||||
|             ip4="203.0.113.21", | ||||
|             ip6="2606:4700:4700::1111", | ||||
|             proxied=False, | ||||
|             explicit_domains=None, | ||||
|             min_child_depth=2, | ||||
|             ipv6_enabled=True, | ||||
|         ) | ||||
|         got = _as_set(recs) | ||||
|         expected = { | ||||
|             ("A", "*.wiki", "203.0.113.21", False), | ||||
|             ("AAAA", "*.wiki", "2606:4700:4700::1111", False), | ||||
|             ("A", "*.b", "203.0.113.21", False), | ||||
|             ("AAAA", "*.b", "2606:4700:4700::1111", False), | ||||
|             # now included because www.a.b.example.com promotes a.b.example.com as a parent | ||||
|             ("A", "*.a.b", "203.0.113.21", False), | ||||
|             ("AAAA", "*.a.b", "2606:4700:4700::1111", False), | ||||
|         } | ||||
|         self.assertEqual(got, expected) | ||||
|  | ||||
|     def test_error_on_missing_ip4(self): | ||||
|         with self.assertRaises(Exception): | ||||
|             self.wildcard_records( | ||||
|                 current_play_domains_all={"svc": ["a.b.example.com"]}, | ||||
|                 apex="example.com", | ||||
|                 ip4="",  # must not be empty | ||||
|                 ip6=None, | ||||
|                 proxied=False, | ||||
|                 explicit_domains=None, | ||||
|                 min_child_depth=2, | ||||
|                 ipv6_enabled=True, | ||||
|             ) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     unittest.main() | ||||
		Reference in New Issue
	
	Block a user