diff --git a/CHANGELOG.md b/CHANGELOG.md index f1ee744..1822f88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ * Support added for config env variable expansion on nested levels, not just top-level provider/processor keys * _ChunkedValue ASCII validation added, SPF & TXT +* Minor validation improvement to catch cases where Record values is provided a + single a-single-value by accident instead of a list, a common type-o that + can results in each character being a value in the resulting Record data ## v1.4.0 - 2023-12-04 - Minor Meta diff --git a/octodns/record/base.py b/octodns/record/base.py index 443e7ba..44c1941 100644 --- a/octodns/record/base.py +++ b/octodns/record/base.py @@ -277,7 +277,14 @@ class ValuesMixin(object): def validate(cls, name, fqdn, data): reasons = super().validate(name, fqdn, data) - values = data.get('values', data.get('value', [])) + try: + values = data['values'] + if isinstance(values, str): + reasons.append( + f'single value provided under values key, "{values}"' + ) + except KeyError: + values = data.get('value', []) reasons.extend(cls._value_type.validate(values, cls._type)) diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index c85341f..8ae5238 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -683,6 +683,43 @@ class TestRecordValidation(TestCase): lenient=True, ) + def test_values_is_single_value(self): + with self.assertRaises(ValidationError) as ctx: + Record.new( + self.zone, + 'thing', + {'type': 'TXT', 'ttl': 42, 'values': 'just one'}, + ) + self.assertEqual( + ['single value provided under values key, "just one"'], + ctx.exception.reasons, + ) + + # same thing is fine as `value` + txt = Record.new( + self.zone, 'thing', {'type': 'TXT', 'ttl': 42, 'value': 'just one'} + ) + self.assertEqual(1, len(txt.values)) + self.assertEqual('just one', txt.values[0]) + + # same thing is fine when a list + txt = Record.new( + self.zone, + 'thing', + {'type': 'TXT', 'ttl': 42, 'values': ['just one']}, + ) + self.assertEqual(1, len(txt.values)) + self.assertEqual('just one', txt.values[0]) + + # or tuple + txt = Record.new( + self.zone, + 'thing', + {'type': 'TXT', 'ttl': 42, 'values': ('just one',)}, + ) + self.assertEqual(1, len(txt.values)) + self.assertEqual('just one', txt.values[0]) + def test_validation_context(self): # fails validation, no context with self.assertRaises(ValidationError) as ctx: