diff --git a/octodns/record/ds.py b/octodns/record/ds.py index 305facb..b682ba8 100644 --- a/octodns/record/ds.py +++ b/octodns/record/ds.py @@ -41,26 +41,54 @@ class DsValue(EqualityTupleMixin, dict): data = (data,) reasons = [] for value in data: - try: - int(value['key_tag']) - except KeyError: - reasons.append('missing key_tag') - except ValueError: - reasons.append(f'invalid key_tag "{value["key_tag"]}"') - try: - int(value['algorithm']) - except KeyError: - reasons.append('missing algorithm') - except ValueError: - reasons.append(f'invalid algorithm "{value["algorithm"]}"') - try: - int(value['digest_type']) - except KeyError: - reasons.append('missing digest_type') - except ValueError: - reasons.append(f'invalid digest_type "{value["digest_type"]}"') - if 'digest' not in value: - reasons.append('missing digest') + # we need to validate both "old" style field names and new + # it is safe to assume if public_key or flags are defined then it is "old" style + # A DS record without public_key doesn't make any sense and shouldn't have validated previously + if "public_key" in value or "flags" in value: + try: + int(value['flags']) + except KeyError: + reasons.append('missing flags') + except ValueError: + reasons.append(f'invalid flags "{value["flags"]}"') + try: + int(value['protocol']) + except KeyError: + reasons.append('missing protocol') + except ValueError: + reasons.append(f'invalid protocol "{value["protocol"]}"') + try: + int(value['algorithm']) + except KeyError: + reasons.append('missing algorithm') + except ValueError: + reasons.append(f'invalid algorithm "{value["algorithm"]}"') + if 'public_key' not in value: + reasons.append('missing public_key') + + else: + try: + int(value['key_tag']) + except KeyError: + reasons.append('missing key_tag') + except ValueError: + reasons.append(f'invalid key_tag "{value["key_tag"]}"') + try: + int(value['algorithm']) + except KeyError: + reasons.append('missing algorithm') + except ValueError: + reasons.append(f'invalid algorithm "{value["algorithm"]}"') + try: + int(value['digest_type']) + except KeyError: + reasons.append('missing digest_type') + except ValueError: + reasons.append( + f'invalid digest_type "{value["digest_type"]}"' + ) + if 'digest' not in value: + reasons.append('missing digest') return reasons @classmethod @@ -68,14 +96,23 @@ class DsValue(EqualityTupleMixin, dict): return [cls(v) for v in values] def __init__(self, value): - super().__init__( - { + # we need to instantiate both based on "old" style field names and new + # it is safe to assume if public_key or flags are defined then it is "old" style + if "public_key" in value or "flags" in value: + init = { + 'key_tag': int(value['flags']), + 'algorithm': int(value['protocol']), + 'digest_type': int(value['algorithm']), + 'digest': value['public_key'], + } + else: + init = { 'key_tag': int(value['key_tag']), 'algorithm': int(value['algorithm']), 'digest_type': int(value['digest_type']), 'digest': value['digest'], } - ) + super().__init__(init) @property def key_tag(self): diff --git a/tests/test_octodns_record_ds.py b/tests/test_octodns_record_ds.py index e4a65fa..f0429de 100644 --- a/tests/test_octodns_record_ds.py +++ b/tests/test_octodns_record_ds.py @@ -72,6 +72,21 @@ class TestRecordDs(TestCase): 'digest': 'bcdef0123456a', }, ), + # diff digest with previously used key names + ( + { + 'flags': 0, + 'protocol': 1, + 'algorithm': 2, + 'public_key': 'abcdef0123456', + }, + { + 'key_tag': 0, + 'algorithm': 1, + 'digest_type': 2, + 'digest': 'bcdef0123456a', + }, + ), ): a = DsValue(a) self.assertEqual(a, a) @@ -162,10 +177,48 @@ class TestRecordDs(TestCase): ['invalid digest_type "a"'], DsValue.validate(data, 'DS') ) - # missing digest_type (list) + # missing public_key (list) data = {'key_tag': 1, 'algorithm': 2, 'digest_type': 3} self.assertEqual(['missing digest'], DsValue.validate([data], 'DS')) + # do validations again with old field style + + # missing flags (list) + data = {'protocol': 2, 'algorithm': 3, 'public_key': '99148c81'} + self.assertEqual(['missing flags'], DsValue.validate([data], 'DS')) + + # missing protocol (list) + data = {'flags': 1, 'algorithm': 3, 'public_key': '99148c81'} + self.assertEqual(['missing protocol'], DsValue.validate([data], 'DS')) + + # missing algorithm (list) + data = {'flags': 1, 'protocol': 2, 'public_key': '99148c81'} + self.assertEqual(['missing algorithm'], DsValue.validate([data], 'DS')) + + # missing public_key (list) + data = {'flags': 1, 'algorithm': 3, 'protocol': 2} + self.assertEqual(['missing public_key'], DsValue.validate([data], 'DS')) + + # missing public_key (list) + data = {'flags': 1, 'algorithm': 3, 'protocol': 2, 'digest': '99148c81'} + self.assertEqual(['missing public_key'], DsValue.validate([data], 'DS')) + + # invalid flags, protocol and algorithm + data = { + 'flags': 'a', + 'protocol': 'a', + 'algorithm': 'a', + 'public_key': '99148c81', + } + self.assertEqual( + [ + 'invalid flags "a"', + 'invalid protocol "a"', + 'invalid algorithm "a"', + ], + DsValue.validate(data, 'DS'), + ) + zone = Zone('unit.tests.', []) values = [ { @@ -175,10 +228,10 @@ class TestRecordDs(TestCase): 'digest': '99148c81', }, { - 'key_tag': 1, - 'algorithm': 2, - 'digest_type': 3, - 'digest': '99148c44', + 'flags': 1, + 'protocol': 2, + 'algorithm': 3, + 'public_key': '99148c44', }, ] a = DsRecord(zone, 'ds', {'ttl': 32, 'values': values})