mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
* Change label from primary ASN to ASN * Raise validation error when trying to update ASN * first steps for dotf importer procotol (#697) * migrations (#697) * Add translation to error meessage * Make ASN readonly in table * Add test now that ASN should not be able to update * Set fac.rencode to '' for all entries and make it readonly in serializer * Add unique constraints to network ixlan ip addresses * Add migration to null out duplicate ipaddresses for deleted netixlans * Add unique constraints to network ixlan ip addresses * Add migration to null out duplicate ipaddresses for deleted netixlans * remove old migrations (#697) * fix netixlan ipaddr dedupe migration (#268) add netixlan ipaddr unique constraint migration (#268) * ixf_member_data migrations (#697) * fix table name (#697) * importer protocol (#697) * fix netixlan ipaddr dedupe migration (#268) add netixlan ipaddr unique constraint migration (#268) * ixf proposed changes notifications (#697) * Delete repeated query * Add a test to show rencode is readonly * Blank out rencode when mocking data * Remove validator now that constraint exists * Add back unique field validator w Check Deleted true * conflict resolving (#697) * UniqueFieldValidator raise error with code "unique" (#268) * conflict resolution (#697) * Add fixme comment to tests * conflict resolution (#697) * Remove now invalid undelete tests * UniqueFieldValidator raise error with code "unique" (#268) * delete admin tools for duplicate ip addresses * Make migration to delete duplicateipnetworkixlan * Add ixlan-ixpfx status matching validation, add corresponding test * delete redundant checking in test * resolve conflict ui (#697) * fix migrations hierarchy * squash migrations for ixf member data * clean up preview and post-mortem tools * remove non-sensical permission check when undeleting soft-deleted objects through unique integrity error handling * only include the ix-f data url in notifications to admincom (#697) * resolve on --skip-import (#697) * ac conflict resolution (#697) * Define more accurately the incompatible statuses for ixlan and ixpfx * Add another status test * Preventing disrupting changes (#697) * fix tests (#697) * Stop allow_ixp_update from being write only and add a global stat for automated networks * Add tests for global stats that appear in footer * Change how timezone is called with datetime, to get test_stats.py/test_generate_for_current_date to pass * test for protected entities (#697) * admincom conflict resolution refine readonly fields (#697) network notifications only if the problem is actually actionable by the network (#697) * ixp / ac notifcation when ix-f source cannot be parsed (#697) fix issue with ixlan prefix protection (#697) * migrations (#697) * code documentation (#697) * ux tweaks (#697) * UX tweaks (#697) * Fix typo * fix netixlan returned in IXFMemberData.apply when adding a new one (#697) * fix import log incosistencies (#697) * Add IXFMemberData to test * Update test data * Add protocol tests * Add tests for views * always persist changes to remote data on set_conflict (#697) * More tests * always persist changes to remote data on set_conflict (#697) * suggest-add test * net_present_at_ix should check status (#697) * Add more protocol tests * Edit language of some tests * django-peeringdb to 2.1.1 relock pipfile, pin django-ratelimit to <3 as it breaks stuff * Add net_count_ixf field to ix object (#683) * Add the IX-F Member Export URL to the ixlan API endpoint (#249) * Lock some objects from being deleted by the owner (#696) * regenerate api docs (#249) * always persist changes to remote data on set_add and set_update (#697) * IXFMemberData: always persist remote data changes during set_add and set_update, also allow for saving without touching the updated field * always persist changes to remote data on set_add and set_update (#697) * Fix suggest-add tests * IXFMemberData: always persist remote data changes during set_add and set_update, also allow for saving without touching the updated field * IXFMemberData: always persist remote data changes during set_add and set_update, also allow for saving without touching the updated field * fix issue with deletion when ixfmemberdata for entry existed previously (#697) * fix test_suggest_delete_local_ixf_no_flag (#697 tests) * fix issue with deletion when ixfmemberdata for entry existed previously (#697) * invalid ips get logged and notified to the ix via notify_error (#697) * Fix more tests * issue with previous_data when running without save (#697) properly track speed errors (#697) * reset errors on ixfmemberdata that go into pending_save (#697) * add remote_data to admin view (#697) * fix error reset inconsistency (#697) * Refine invalid data tests * remove debug output * for notifications to ac include contact points for net and ix in the message (#697) * settings to toggle ix-f tickets / emails (#697) * allow turning off ix-f notifications for net and ix separately (#697) * add jsonschema test * Add idempotent tests to updater * remove old ixf member tests * Invalid data tests when ixp_updates are enabled * fix speed error validation (#697) * fix issue with rollback (#697) * fix migration hierarchy * fix ixfmemberdata _email * django-peeringdb to 2.2 and relock * add ixf rollback tests * ixf email notifications off by default * black formatted * pyupgrade Co-authored-by: egfrank <egfrank@20c.com> Co-authored-by: Stefan Pratter <stefan@20c.com>
304 lines
8.0 KiB
Python
304 lines
8.0 KiB
Python
import ipaddress
|
|
import os
|
|
import pytest
|
|
import requests
|
|
|
|
from django.test import override_settings
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.management import call_command
|
|
|
|
from peeringdb_server.validators import (
|
|
validate_address_space,
|
|
validate_info_prefixes4,
|
|
validate_info_prefixes6,
|
|
validate_prefix_overlap,
|
|
validate_phonenumber,
|
|
validate_irr_as_set,
|
|
)
|
|
|
|
from peeringdb_server.models import (
|
|
Organization,
|
|
InternetExchange,
|
|
IXLan,
|
|
IXLanPrefix,
|
|
Network,
|
|
NetworkContact,
|
|
Facility,
|
|
ProtectedAction,
|
|
)
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
INVALID_ADDRESS_SPACES = [
|
|
"0.0.0.0/1",
|
|
"0.0.0.0/8",
|
|
"10.0.0.0/8",
|
|
"127.0.0.0/8",
|
|
"169.254.0.0/16",
|
|
# FIXME: this fails still
|
|
#'172.0.0.0/11',
|
|
"172.16.0.0/12",
|
|
"192.0.2.0/24",
|
|
"192.168.0.0/16",
|
|
"198.18.0.0/15",
|
|
"198.51.100.0/24",
|
|
"203.0.113.0/24",
|
|
# FIXME: this fails still
|
|
#'224.0.0.0/3',
|
|
"224.0.0.0/4",
|
|
"240.0.0.0/4",
|
|
"100.64.0.0/10",
|
|
"0000::/8",
|
|
"0064:ff9b::/96",
|
|
"0100::/8",
|
|
"0200::/7",
|
|
"0400::/6",
|
|
"0800::/5",
|
|
"1000::/4",
|
|
"2001::/33",
|
|
"2001:0:8000::/33",
|
|
"2001:0002::/48",
|
|
"2001:0003::/32",
|
|
"2001:10::/28",
|
|
"2001:20::/28",
|
|
"2001:db8::/32",
|
|
"2002::/16",
|
|
"3ffe::/16",
|
|
"4000::/2",
|
|
"4000::/3",
|
|
"5f00::/8",
|
|
"6000::/3",
|
|
"8000::/3",
|
|
"a000::/3",
|
|
"c000::/3",
|
|
"e000::/4",
|
|
"f000::/5",
|
|
"f800::/6",
|
|
"fc00::/7",
|
|
"fe80::/10",
|
|
"fec0::/10",
|
|
"ff00::/8",
|
|
]
|
|
|
|
|
|
@pytest.fixture(params=INVALID_ADDRESS_SPACES)
|
|
def prefix(request):
|
|
return request.param
|
|
|
|
|
|
# @pytest.mark.django_db
|
|
def test_validate_address_space(prefix):
|
|
"""
|
|
Tests peeringdb_server.validators.validate_address_space
|
|
"""
|
|
with pytest.raises(ValidationError) as exc:
|
|
validate_address_space(ipaddress.ip_network(str(prefix)))
|
|
|
|
|
|
@override_settings(DATA_QUALITY_MAX_PREFIX_V4_LIMIT=500000)
|
|
def test_validate_info_prefixes4():
|
|
"""
|
|
Tests peeringdb_server.validators.validate_info_prefixes4
|
|
"""
|
|
with pytest.raises(ValidationError):
|
|
validate_info_prefixes4(500001)
|
|
with pytest.raises(ValidationError):
|
|
validate_info_prefixes4(-1)
|
|
validate_info_prefixes4(500000)
|
|
assert validate_info_prefixes4(None) == 0
|
|
assert validate_info_prefixes4("") == 0
|
|
|
|
|
|
@override_settings(DATA_QUALITY_MAX_PREFIX_V6_LIMIT=500000)
|
|
def test_validate_info_prefixes6():
|
|
"""
|
|
Tests peeringdb_server.validators.validate_info_prefixes6
|
|
"""
|
|
with pytest.raises(ValidationError):
|
|
validate_info_prefixes6(500001)
|
|
with pytest.raises(ValidationError):
|
|
validate_info_prefixes6(-1)
|
|
validate_info_prefixes6(500000)
|
|
assert validate_info_prefixes6(None) == 0
|
|
assert validate_info_prefixes6("") == 0
|
|
|
|
|
|
@override_settings(
|
|
DATA_QUALITY_MIN_PREFIXLEN_V4=24,
|
|
DATA_QUALITY_MAX_PREFIXLEN_V4=24,
|
|
DATA_QUALITY_MIN_PREFIXLEN_V6=48,
|
|
DATA_QUALITY_MAX_PREFIXLEN_V6=48,
|
|
)
|
|
def test_validate_prefixlen():
|
|
"""
|
|
Tests prefix length limits
|
|
"""
|
|
with pytest.raises(ValidationError):
|
|
validate_address_space("37.77.32.0/20")
|
|
with pytest.raises(ValidationError):
|
|
validate_address_space("131.72.77.240/28")
|
|
with pytest.raises(ValidationError):
|
|
validate_address_space("2403:c240::/32")
|
|
with pytest.raises(ValidationError):
|
|
validate_address_space("2001:504:0:2::/64")
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_validate_prefix_overlap():
|
|
org = Organization.objects.create(name="Test org", status="ok")
|
|
ix = InternetExchange.objects.create(name="Text exchange", status="ok", org=org)
|
|
ixlan = ix.ixlan
|
|
|
|
pfx1 = IXLanPrefix.objects.create(
|
|
ixlan=ixlan,
|
|
protocol="IPv4",
|
|
prefix=ipaddress.ip_network("198.32.125.0/24"),
|
|
status="ok",
|
|
)
|
|
|
|
with pytest.raises(ValidationError) as exc:
|
|
validate_prefix_overlap("198.32.124.0/23")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"value,validated",
|
|
[
|
|
# success validation
|
|
("RIPE::AS-FOO", "RIPE::AS-FOO"),
|
|
("AS-FOO@RIPE", "AS-FOO@RIPE"),
|
|
("AS-FOO-BAR@RIPE", "AS-FOO-BAR@RIPE"),
|
|
("ripe::as-foo", "RIPE::AS-FOO"),
|
|
("as-foo@ripe", "AS-FOO@RIPE"),
|
|
("as-foo@ripe as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
|
("as-foo@ripe,as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
|
("as-foo@ripe, as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
|
(
|
|
"RIPE::AS12345:AS-FOO RIPE::AS12345:AS-FOO:AS9876",
|
|
"RIPE::AS12345:AS-FOO RIPE::AS12345:AS-FOO:AS9876",
|
|
),
|
|
("ripe::as-foo:as123:as345", "RIPE::AS-FOO:AS123:AS345"),
|
|
("RIPE::AS12345", "RIPE::AS12345"),
|
|
("AS12345@RIPE", "AS12345@RIPE"),
|
|
("RIPE::AS123456:RS-FOO", "RIPE::AS123456:RS-FOO"),
|
|
("as-foo", "AS-FOO"),
|
|
("rs-foo", "RS-FOO"),
|
|
("as-foo as-bar", "AS-FOO AS-BAR"),
|
|
("rs-foo as-bar", "RS-FOO AS-BAR"),
|
|
("rs-foo rs-bar", "RS-FOO RS-BAR"),
|
|
("AS15562", "AS15562"),
|
|
("AS-15562", "AS-15562"),
|
|
("AS15562 AS33333", "AS15562 AS33333"),
|
|
# fail validation
|
|
("UNKNOWN::AS-FOO", False),
|
|
("AS-FOO@UNKNOWN", False),
|
|
("ASFOO@UNKNOWN", False),
|
|
("UNKNOWN::ASFOO", False),
|
|
("RIPE:AS-FOO", False),
|
|
("RIPE::RS15562:RS-FOO", False),
|
|
("RIPE::AS123456:RS-FOO:AS-FOO", False),
|
|
('!"*([])?.=+/\\', False),
|
|
('RIPE::!"*([])?.=+/\\', False),
|
|
('!"*([])?.=+/\\@RIPE', False),
|
|
# > DATA_QUALITY_MAX_IRR_DEPTH
|
|
("ripe::as-foo:as123:as345:as678", False),
|
|
],
|
|
)
|
|
def test_validate_irr_as_set(value, validated):
|
|
if not validated:
|
|
with pytest.raises(ValidationError):
|
|
validate_irr_as_set(value)
|
|
else:
|
|
assert validate_irr_as_set(value) == validated
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_validate_phonenumber():
|
|
|
|
# test standalone validator
|
|
|
|
validate_phonenumber("+1 206 555 0199")
|
|
validate_phonenumber("012065550199", "US")
|
|
|
|
with pytest.raises(ValidationError):
|
|
validate_phonenumber("invalid number")
|
|
|
|
with pytest.raises(ValidationError):
|
|
validate_phonenumber("012065550199")
|
|
|
|
# test model field validation
|
|
|
|
org = Organization.objects.create(name="Test org", status="ok")
|
|
ix = InternetExchange.objects.create(
|
|
name="Text exchange",
|
|
status="ok",
|
|
org=org,
|
|
country="US",
|
|
city="Some city",
|
|
region_continent="North America",
|
|
media="Ethernet",
|
|
)
|
|
net = Network.objects.create(name="Text network", asn=12345, status="ok", org=org)
|
|
poc = NetworkContact.objects.create(network=net, status="ok", role="Abuse")
|
|
|
|
# test poc phone validation
|
|
|
|
with pytest.raises(ValidationError):
|
|
poc.phone = "invalid"
|
|
poc.full_clean()
|
|
|
|
poc.phone = "+1 206 555 0199"
|
|
poc.full_clean()
|
|
|
|
# test ix phone validation
|
|
|
|
with pytest.raises(ValidationError):
|
|
ix.tech_phone = "invalid"
|
|
ix.full_clean()
|
|
|
|
ix.tech_phone = "+1 206 555 0199"
|
|
ix.full_clean()
|
|
|
|
with pytest.raises(ValidationError):
|
|
ix.policy_phone = "invalid"
|
|
ix.full_clean()
|
|
|
|
ix.policy_phone = "+1 206 555 0199"
|
|
ix.full_clean()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_validate_ixpfx_ixlan_status_match():
|
|
org = Organization.objects.create(name="Test org", status="ok")
|
|
ix = InternetExchange.objects.create(
|
|
name="Text exchange", status="pending", org=org
|
|
)
|
|
ixlan = ix.ixlan
|
|
|
|
pfx = IXLanPrefix.objects.create(
|
|
ixlan=ixlan,
|
|
protocol="IPv4",
|
|
prefix=ipaddress.ip_network("198.32.125.0/24"),
|
|
status="ok",
|
|
)
|
|
|
|
with pytest.raises(ValidationError) as exc1:
|
|
pfx.clean()
|
|
|
|
assert (
|
|
exc1.value.args[0]
|
|
== "IXLanPrefix with status 'ok' cannot be linked to a IXLan with status 'pending'."
|
|
)
|
|
|
|
ixlan.status = "deleted"
|
|
ixlan.save()
|
|
pfx.status = "pending"
|
|
pfx.save()
|
|
|
|
with pytest.raises(ValidationError) as exc2:
|
|
pfx.clean()
|
|
|
|
assert (
|
|
exc2.value.args[0]
|
|
== "IXLanPrefix with status 'pending' cannot be linked to a IXLan with status 'deleted'."
|
|
)
|