From fe14cdf07c35a1579c79145f15dd1157d93488d7 Mon Sep 17 00:00:00 2001 From: rmanyari Date: Wed, 1 Mar 2023 10:31:43 -0700 Subject: [PATCH] Update invalid input handling to return empty set instead of raising exception --- netbox/ipam/filtersets.py | 34 ++++++++++++++++++---------- netbox/ipam/tests/test_filtersets.py | 18 +++++---------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index 9e4a84eba..dbda8811f 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -601,23 +601,33 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet): return queryset.filter(q) def parse_inet_addresses(self, value): - try: - parsed = [] - for addr in value: - if netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr): - parsed.append(addr) - continue + ''' + Parse networks or IP addresses and cast to a format + acceptable by the Postgres inet type. + + Skips invalid values. + ''' + parsed = [] + for addr in value: + if netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr): + parsed.append(addr) + continue + try: network = netaddr.IPNetwork(addr) parsed.append(str(network)) - return parsed - except (AddrFormatError, ValueError): - raise serializers.ValidationError({ - 'address': f'Invalid address {addr}. It must be a valid IPv4 or IPv6 address or network' - }) + except (AddrFormatError, ValueError): + continue + return parsed def filter_address(self, queryset, name, value): + # Let's first parse the addresses passed + # as argument. If they are all invalid, + # we return an empty queryset + value = self.parse_inet_addresses(value) + if (len(value) == 0): + return queryset.none() + try: - value = self.parse_inet_addresses(value) return queryset.filter(address__net_in=value) except ValidationError: return queryset.none() diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py index e4c4abd0b..c53522d7a 100644 --- a/netbox/ipam/tests/test_filtersets.py +++ b/netbox/ipam/tests/test_filtersets.py @@ -864,19 +864,13 @@ class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests): # Check for invalid input. params = {'address': ['/24']} - with self.assertRaises(serializers.ValidationError) as cm: - self.filterset(params, self.queryset).qs.count() - self.assertRegex(cm.exception.detail['address'], r'^Invalid address.*') + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0) + params = {'address': ['10.0.0.1/255.255.999.0']} # Invalid netmask + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0) - params = {'address': ['10.0.0.1/255.255.555.0']} - with self.assertRaises(serializers.ValidationError) as cm: - self.filterset(params, self.queryset).qs.count() - self.assertRegex(cm.exception.detail['address'], r'^Invalid address.*') - - params = {'address': ['10.0.0.1', '/24']} - with self.assertRaises(serializers.ValidationError) as cm: - self.filterset(params, self.queryset).qs.count() - self.assertRegex(cm.exception.detail['address'], r'^Invalid address.*') + # Check for partially invalid input. + params = {'address': ['10.0.0.1', '/24', '10.0.0.10/24']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) def test_mask_length(self): params = {'mask_length': '24'}