1
0
mirror of https://github.com/github/octodns.git synced 2024-05-11 05:55:00 +00:00

Merge branch 'main' into rc-version-fix

This commit is contained in:
Ross McFarland
2023-06-20 09:23:38 -07:00
committed by GitHub
22 changed files with 112 additions and 49 deletions

View File

@@ -8,7 +8,7 @@ jobs:
fail-fast: false
matrix:
# Tested versions based on dates in https://devguide.python.org/devcycle/#end-of-life-branches,
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
steps:
- uses: actions/checkout@master
- name: Setup python

View File

@@ -1,3 +1,7 @@
## v1.0.0.rc2 - 2023-??-?? -
* Record and Zone validation now ensures there's no whitespace in names
## v1.0.0.rc0 - 2023-05-16 - First of the ones
#### Noteworthy changes

View File

@@ -475,7 +475,6 @@ class Manager(object):
force=False,
plan_output_fh=stdout,
):
self.log.info(
'sync: eligible_zones=%s, eligible_targets=%s, dry_run=%s, '
'force=%s, plan_output_fh=%s',

View File

@@ -61,8 +61,13 @@ class AutoArpa(BaseProcessor):
zone,
name,
{'ttl': self.ttl, 'type': 'PTR', 'values': fqdns},
lenient=lenient,
)
zone.add_record(
record,
replace=self.populate_should_replace,
lenient=lenient,
)
zone.add_record(record, replace=self.populate_should_replace)
self.log.info(
'populate: found %s records', len(zone.records) - before

View File

@@ -78,7 +78,6 @@ class Plan(object):
self.existing
and len(self.existing.records) >= self.MIN_EXISTING_RECORDS
):
existing_record_count = len(self.existing.records)
if existing_record_count > 0:
update_pcent = (

View File

@@ -41,6 +41,10 @@ class Record(EqualityTupleMixin):
# convert the error into a reason
reasons.append(str(e))
name = str(name)
if ' ' in name or '\t' in name:
reasons.append('invalid record, whitespace is not allowed')
fqdn = f'{name}.{zone.name}' if name else zone.name
try:
_type = data['type']

View File

@@ -13,7 +13,7 @@ class ValidationError(RecordException):
@classmethod
def build_message(cls, fqdn, reasons):
reasons = '\n - '.join(reasons)
return f'Invalid record {idna_decode(fqdn)}\n - {reasons}'
return f'Invalid record "{idna_decode(fqdn)}"\n - {reasons}'
def __init__(self, fqdn, reasons):
super().__init__(self.build_message(fqdn, reasons))

View File

@@ -4,7 +4,6 @@
class BaseSource(object):
SUPPORTS_MULTIVALUE_PTR = False
SUPPORTS_POOL_VALUE_STATUS = False
SUPPORTS_ROOT_NS = False

View File

@@ -28,6 +28,9 @@ class Zone(object):
def __init__(self, name, sub_zones):
if not name[-1] == '.':
raise Exception(f'Invalid zone name {name}, missing ending dot')
elif ' ' in name or '\t' in name:
raise Exception(f'Invalid zone name {name}, whitespace not allowed')
# internally everything is idna
self.name = idna_encode(str(name)) if name else name
# we'll keep a decoded version around for logs and errors

View File

@@ -1,50 +1,46 @@
# DO NOT EDIT THIS FILE DIRECTLY - use ./script/update-requirements to update
Pygments==2.13.0
attrs==22.1.0
black==22.10.0
bleach==5.0.1
build==0.9.0
certifi==2022.12.7
Pygments==2.15.1
black==23.3.0
bleach==6.0.0
build==0.10.0
certifi==2023.5.7
cffi==1.15.1
charset-normalizer==2.1.1
charset-normalizer==3.1.0
click==8.1.3
cmarkgfm==2022.10.27
commonmark==0.9.1
coverage==6.5.0
docutils==0.19
exceptiongroup==1.0.0
importlib-metadata==5.0.0
iniconfig==1.1.1
coverage==7.2.5
docutils==0.20.1
importlib-metadata==6.6.0
iniconfig==2.0.0
isort==5.11.4
jaraco.classes==3.2.3
keyring==23.9.3
more-itertools==9.0.0
mypy-extensions==0.4.3
packaging==21.3
pathspec==0.10.1
pep517==0.13.0
pkginfo==1.8.3
platformdirs==2.5.2
keyring==23.13.1
markdown-it-py==2.2.0
mdurl==0.1.2
more-itertools==9.1.0
mypy-extensions==1.0.0
packaging==23.1
pathspec==0.11.1
pkginfo==1.9.6
platformdirs==3.5.1
pluggy==1.0.0
pprintpp==0.4.0
pycountry-convert==0.7.2
pycountry==22.3.5
pycparser==2.21
pyflakes==2.5.0
pyparsing==3.0.9
pyflakes==3.0.1
pyproject_hooks==1.0.0
pytest-cov==4.0.0
pytest-mock==3.10.0
pytest-network==0.0.1
pytest==7.2.0
pytest==7.3.1
readme-renderer==37.3
repoze.lru==0.7
requests-toolbelt==0.10.1
requests==2.28.1
requests-toolbelt==1.0.0
requests==2.31.0
rfc3986==2.0.0
rich==12.6.0
tomli==2.0.1
twine==4.0.1
typing_extensions==4.4.0
urllib3==1.26.12
rich==13.3.5
twine==4.0.2
urllib3==2.0.2
webencodings==0.5.1
zipp==3.10.0
zipp==3.15.0

View File

@@ -3,6 +3,6 @@ PyYAML==6.0
dnspython==2.3.0
fqdn==1.5.1
idna==3.4
natsort==8.2.0
natsort==8.3.1
python-dateutil==2.8.2
six==1.16.0

View File

@@ -6,12 +6,12 @@ from unittest import TestCase
from octodns.processor.arpa import AutoArpa
from octodns.record import Record
from octodns.record.exception import ValidationError
from octodns.zone import Zone
class TestAutoArpa(TestCase):
def test_empty_zone(self):
# empty zone no records
zone = Zone('unit.tests.', [])
aa = AutoArpa('auto-arpa')
@@ -227,3 +227,39 @@ class TestAutoArpa(TestCase):
arpa = Zone('0.10.in-addr.arpa.', [])
aa.populate(arpa)
self.assertEqual(0, len(arpa.records))
def test_single_value_A_with_space(self):
zone = Zone('unit.tests.', [])
# invalid record without lenient
with self.assertRaises(ValidationError):
Record.new(
zone,
'a with spaces',
{'ttl': 32, 'type': 'A', 'value': '1.2.3.4'},
)
# invalid record with lenient
lenient = True
record = Record.new(
zone,
'a with spaces',
{'ttl': 32, 'type': 'A', 'value': '1.2.3.4'},
lenient=lenient,
)
zone.add_record(record)
aa = AutoArpa('auto-arpa')
aa.process_source_zone(zone, [])
self.assertEqual(
{'4.3.2.1.in-addr.arpa.': {'a with spaces.unit.tests.'}},
aa._records,
)
# matching zone
arpa = Zone('3.2.1.in-addr.arpa.', [])
aa.populate(arpa, lenient=lenient)
self.assertEqual(1, len(arpa.records))
(ptr,) = arpa.records
self.assertEqual('4.3.2.1.in-addr.arpa.', ptr.fqdn)
self.assertEqual(record.fqdn, ptr.value)
self.assertEqual(3600, ptr.ttl)

View File

@@ -398,6 +398,28 @@ class TestRecordValidation(TestCase):
zone = Zone('unit.tests.', [])
def test_base(self):
# no spaces
for name in (
' ',
' leading',
'trailing ',
'in the middle',
'\t',
'\tleading',
'trailing\t',
'in\tthe\tmiddle',
):
with self.assertRaises(ValidationError) as ctx:
Record.new(
self.zone,
name,
{'ttl': 300, 'type': 'A', 'value': '1.2.3.4'},
)
reason = ctx.exception.reasons[0]
self.assertEqual(
'invalid record, whitespace is not allowed', reason
)
# name = '@'
with self.assertRaises(ValidationError) as ctx:
name = '@'

View File

@@ -10,7 +10,6 @@ from octodns.zone import Zone
class TestRecordIp(TestCase):
def test_ipv4_value_rdata_text(self):
# anything goes, we're a noop
for s in (
None,

View File

@@ -68,7 +68,6 @@ class TestRecordMx(TestCase):
a.__repr__()
def test_mx_value_rdata_text(self):
# empty string won't parse
with self.assertRaises(RrParseError):
MxValue.parse_rdata_text('')

View File

@@ -63,7 +63,6 @@ class TestRecordPtr(TestCase):
)
def test_ptr_rdata_text(self):
# anything goes, we're a noop
for s in (
None,

View File

@@ -81,7 +81,6 @@ class TestRecordSrv(TestCase):
a.__repr__()
def test_srv_value_rdata_text(self):
# empty string won't parse
with self.assertRaises(RrParseError):
SrvValue.parse_rdata_text('')

View File

@@ -85,7 +85,6 @@ class TestRecordSshfp(TestCase):
a.__repr__()
def test_sshfp_value_rdata_text(self):
# empty string won't parse
with self.assertRaises(RrParseError):
SshfpValue.parse_rdata_text('')

View File

@@ -11,7 +11,6 @@ from octodns.zone import Zone
class TestRecordTarget(TestCase):
def test_target_rdata_text(self):
# anything goes, we're a noop
for s in (
None,

View File

@@ -118,7 +118,6 @@ class TestRecordTlsa(TestCase):
a.__repr__()
def test_tsla_value_rdata_text(self):
# empty string won't parse
with self.assertRaises(RrParseError):
TlsaValue.parse_rdata_text('')

View File

@@ -150,7 +150,6 @@ class TestTinyDnsFileSource(TestCase):
self.assertEqual([], changes)
def test_populate_in_addr_arpa(self):
got = Zone('3.2.10.in-addr.arpa.', [])
self.source.populate(got)

View File

@@ -186,8 +186,12 @@ class TestZone(TestCase):
Zone('not.allowed', [])
self.assertTrue('missing ending dot' in str(ctx.exception))
def test_sub_zones(self):
def test_whitespace(self):
with self.assertRaises(Exception) as ctx:
Zone('space not allowed.', [])
self.assertTrue('whitespace not allowed' in str(ctx.exception))
def test_sub_zones(self):
# NS for exactly the sub is allowed
zone = Zone('unit.tests.', set(['sub', 'barred']))
record = Record.new(