Skip to content

Commit

Permalink
Merge pull request #295 from joe733/workshop
Browse files Browse the repository at this point in the history
fix: strict CIDR IP validation; bump version
  • Loading branch information
yozachar authored Sep 2, 2023
2 parents 99b425a + 91dad61 commit 71b40bd
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 60 deletions.
78 changes: 56 additions & 22 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
# Changelog

<!--
Note to self: Breaking changes must increment either
- minor version: as long as versions are in 0.y.z or
- major version: when versions are in in x.y.z (x>0)
-->

## 0.22.0 (2023-09-02)

_**What's Changed**_

> - _Breaking_:
> - API changes in `validators.ipv4` and `validators.ipv6` functions
> - `strict` parameter now correctly validates IP addresses strictly in CIDR notation
> - `host_bit` parameter distinguishes between network and host IP address
- fix: url validator considers urls with /#/ as valid by @adrienthiery in [#289](https://github.com/python-validators/validators/pull/289)
- Add note about ValidationFailure to ValidationError in changes.md by @tswfi in [#291](https://github.com/python-validators/validators/pull/291)
- fix: simple hostname validation regex by @joe733 in [#294](https://github.com/python-validators/validators/pull/294)
- fix: strict CIDR IP validation; bump version by @joe733 in [#295](https://github.com/python-validators/validators/pull/295)

_**New Contributors**_

- @adrienthiery made their first contribution in [#289](https://github.com/python-validators/validators/pull/289)
- @tswfi made their first contribution in [#291](https://github.com/python-validators/validators/pull/291)

**Full Changelog**: [`0.21.2...0.22.0`](https://github.com/python-validators/validators/compare/0.21.2...0.22.0)

## 0.21.2 (2023-08-07)

### What's Changed
_**What's Changed**_

> - _Breaking_:
> - `ValidationFailure` renamed to `ValidationError` in [`joe733@12ae1f5`](https://github.com/joe733/pyvalidators/commit/12ae1f5850555d11e1f1a2c03f597fd10610215a)
- feat: refactoring; updates; fixes; bump version by @joe733 in [#283](https://github.com/python-validators/validators/pull/283)
- *Breaking Changes*:
- `ValidationFailure` renamed to `ValidationError` in [joe733@12ae1f5](https://github.com/joe733/pyvalidators/commit/12ae1f5850555d11e1f1a2c03f597fd10610215a)
- feat: refactoring; updates; fixes; bump version by @joe733 in [#283](https://github.com/python-validators/validators/pull/283)(<https://github.com/joe733/pyvalidators/commit/12ae1f5850555d11e1f1a2c03f597fd10610215a>)
- build(deps): bump pymdown-extensions from 9.11 to 10.0 by @dependabot in [#273](https://github.com/python-validators/validators/pull/273)
- build(deps): bump requests from 2.28.2 to 2.31.0 by @dependabot in [#275](https://github.com/python-validators/validators/pull/275)
- add validator ETH addresses (ERC20) by @msamsami in [#276](https://github.com/python-validators/validators/pull/276)
- Added Country Code Validation by @aviiciii in [#280](https://github.com/python-validators/validators/pull/280)
- build(deps-dev): bump certifi from 2022.12.7 to 2023.7.22 by @dependabot in [#281](https://github.com/python-validators/validators/pull/281)

### New Contributors
_**New Contributors**_

- @dependabot made their first contribution in [#273](https://github.com/python-validators/validators/pull/273)
- @msamsami made their first contribution in [#276](https://github.com/python-validators/validators/pull/276)
Expand All @@ -33,6 +64,9 @@

## 0.21.0 (2023-03-25)

> - _Breaking_:
> - Couple of API changes, refer [documentation](https://python-validators.github.io/validators/)
- feat: add build for pypi workflow by @joe733 in [#255](https://github.com/python-validators/validators/pull/255)
- feat: @validator now catches `Exception` by @joe733 in [#254](https://github.com/python-validators/validators/pull/254)
- maint: improves `i18n` package by @joe733 in [#252](https://github.com/python-validators/validators/pull/252)
Expand Down Expand Up @@ -125,11 +159,11 @@

## 0.14.0 (2019-08-21)

- Added new validators ``ipv4_cidr``, ``ipv6_cidr`` (#117, pull request courtesy woodruffw)
- Added new validators `ipv4_cidr`, `ipv6_cidr` (#117, pull request courtesy woodruffw)

## 0.13.0 (2019-05-20)

- Added new validator: ``es_doi``, ``es_nif``, ``es_cif``, ``es_nie`` (#121, pull request courtesy kingbuzzman)
- Added new validator: `es_doi`, `es_nif`, `es_cif`, `es_nie` (#121, pull request courtesy kingbuzzman)

## 0.12.6 (2019-05-08)

Expand Down Expand Up @@ -184,7 +218,7 @@

## 0.10.3 (2016-06-13)

- Added ``public`` parameter to url validator (#26, pull request courtesy Iconceicao)
- Added `public` parameter to url validator (#26, pull request courtesy Iconceicao)

## 0.10.2 (2016-06-11)

Expand All @@ -197,48 +231,48 @@

## 0.10.0 (2016-01-09)

- Added support for internationalized domain names in ``domain`` validator
- Added support for internationalized domain names in `domain` validator

## 0.9.0 (2015-10-10)

- Added new validator: ``domain``
- Added new validator: `domain`
- Added flake8 and isort checks in travis config

## 0.8.0 (2015-06-24)

- Added new validator: ``iban``
- Added new validator: `iban`

## 0.7.0 (2014-09-07)

- Fixed errors in code examples.
- Fixed ``TypeError`` when using ``between`` validator with ``datetime`` objects
- Fixed `TypeError` when using `between` validator with `datetime` objects
like in the code example.
- Changed validators to always return ``True`` instead of a truthy object when
- Changed validators to always return `True` instead of a truthy object when
the validation succeeds.
- Fixed ``truthy`` validator to work like it's name suggests. Previously it
worked like ``falsy``.
- Fixed `truthy` validator to work like it's name suggests. Previously it
worked like `falsy`.

## 0.6.0 (2014-06-25)

- Added new validator: ``slug``
- Added new validator: `slug`

## 0.5.0 (2013-10-31)

- Renamed ``finnish_business_id`` to ``fi_business_id``
- Added new validator: ``fi_ssn``
- Renamed `finnish_business_id` to `fi_business_id`
- Added new validator: `fi_ssn`

## 0.4.0 (2013-10-29)

- Added new validator: ``finnish_business_id``
- Added new validator: `finnish_business_id`

## 0.3.0 (2013-10-27)

- ``number_range`` -> ``between``
- `number_range` -> `between`

## 0.2.0 (2013-10-22)

- Various new validators: ``ipv4``, ``ipv6``, ``length``, ``number_range``,
``mac_address``, ``url``, ``uuid``
- Various new validators: `ipv4`, `ipv6`, `length`, `number_range`,
`mac_address`, `url`, `uuid`

## 0.1.0 (2013-10-18)

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

| Version | Supported |
| ---------- | ------------------ |
| `>=0.21.2` | :white_check_mark: |
| `>=0.22.0` | :white_check_mark: |

## Reporting a Vulnerability

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "validators"
version = "0.21.2"
version = "0.22.0"
description = "Python Data Validation for Humans™"
authors = [{ name = "Konsta Vesterinen", email = "[email protected]" }]
license = { text = "MIT" }
Expand Down
2 changes: 1 addition & 1 deletion src/validators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,4 @@
"validator",
)

__version__ = "0.21.2"
__version__ = "0.22.0"
36 changes: 21 additions & 15 deletions src/validators/ip_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


@validator
def ipv4(value: str, /, *, cidr: bool = True, strict: bool = False):
def ipv4(value: str, /, *, cidr: bool = True, strict: bool = False, host_bit: bool = True):
"""Returns whether a given value is a valid IPv4 address.
From Python version 3.9.5 leading zeros are no longer tolerated
Expand All @@ -36,11 +36,12 @@ def ipv4(value: str, /, *, cidr: bool = True, strict: bool = False):
value:
IP address string to validate.
cidr:
IP address string may contain CIDR annotation
IP address string may contain CIDR notation
strict:
If strict is True and host bits are set in the supplied address.
Otherwise, the host bits are masked out to determine the
appropriate network address. ref [IPv4Network][2].
IP address string is strictly in CIDR notation
host_bit:
If `False` and host bits (along with network bits) _are_ set in the supplied
address, this function raises a validation error. ref [IPv4Network][2].
[2]: https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Network
Returns:
Expand All @@ -58,15 +59,17 @@ def ipv4(value: str, /, *, cidr: bool = True, strict: bool = False):
if not value:
return False
try:
if cidr and value.count("/") == 1:
return IPv4Network(value, strict=strict)
if cidr:
if strict and value.count("/") != 1:
raise ValueError("IPv4 address was expected in CIDR notation")
return IPv4Network(value, strict=not host_bit)
return IPv4Address(value)
except (AddressValueError, NetmaskValueError):
except (ValueError, AddressValueError, NetmaskValueError):
return False


@validator
def ipv6(value: str, /, *, cidr: bool = True, strict: bool = False):
def ipv6(value: str, /, *, cidr: bool = True, strict: bool = False, host_bit: bool = True):
"""Returns if a given value is a valid IPv6 address.
Including IPv4-mapped IPv6 addresses. The initial version of ipv6 validator
Expand All @@ -88,9 +91,10 @@ def ipv6(value: str, /, *, cidr: bool = True, strict: bool = False):
cidr:
IP address string may contain CIDR annotation
strict:
If strict is True and host bits are set in the supplied address.
Otherwise, the host bits are masked out to determine the
appropriate network address. ref [IPv6Network][2].
IP address string is strictly in CIDR notation
host_bit:
If `False` and host bits (along with network bits) _are_ set in the supplied
address, this function raises a validation error. ref [IPv6Network][2].
[2]: https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Network
Returns:
Expand All @@ -108,8 +112,10 @@ def ipv6(value: str, /, *, cidr: bool = True, strict: bool = False):
if not value:
return False
try:
if cidr and value.count("/") == 1:
return IPv6Network(value, strict=strict)
if cidr:
if strict and value.count("/") != 1:
raise ValueError("IPv6 address was expected in CIDR notation")
return IPv6Network(value, strict=not host_bit)
return IPv6Address(value)
except (AddressValueError, NetmaskValueError):
except (ValueError, AddressValueError, NetmaskValueError):
return False
88 changes: 68 additions & 20 deletions tests/test_ip_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
("127.0.0.1",),
("123.5.77.88",),
("12.12.12.12",),
# w/ cidr
("127.0.0.1/0",),
("123.5.77.88/8",),
("12.12.12.12/32",),
],
)
def test_returns_true_on_valid_ipv4_address(address: str):
Expand All @@ -25,6 +21,22 @@ def test_returns_true_on_valid_ipv4_address(address: str):
assert not ipv6(address)


@pytest.mark.parametrize(
("address", "cidr", "strict", "host_bit"),
[
("127.0.0.1/0", True, True, True),
("123.5.77.88", True, False, True),
("12.12.12.0/24", True, True, False),
],
)
def test_returns_true_on_valid_ipv4_cidr_address(
address: str, cidr: bool, strict: bool, host_bit: bool
):
"""Test returns true on valid ipv4 CIDR address."""
assert ipv4(address, cidr=cidr, strict=strict, host_bit=host_bit)
assert not ipv6(address, cidr=cidr, strict=strict, host_bit=host_bit)


@pytest.mark.parametrize(
("address",),
[
Expand All @@ -33,17 +45,29 @@ def test_returns_true_on_valid_ipv4_address(address: str):
("900.200.100.75",),
("0127.0.0.1",),
("abc.0.0.1",),
# w/ cidr
("1.1.1.1/-1",),
("1.1.1.1/33",),
("1.1.1.1/foo",),
],
)
def test_returns_failed_validation_on_invalid_ipv4_address(address: str):
"""Test returns failed validation on invalid ipv4 address."""
assert isinstance(ipv4(address), ValidationError)


@pytest.mark.parametrize(
("address", "cidr", "strict", "host_bit"),
[
("1.1.1.1/1", False, True, True),
("1.1.1.1/33", True, False, True),
("1.1.1.1/24", True, True, False),
("1.1.1.1/-1", True, True, True),
],
)
def test_returns_failed_validation_on_invalid_ipv4_cidr_address(
address: str, cidr: bool, strict: bool, host_bit: bool
):
"""Test returns failed validation on invalid ipv4 CIDR address."""
assert isinstance(ipv4(address, cidr=cidr, strict=strict, host_bit=host_bit), ValidationError)


@pytest.mark.parametrize(
("address",),
[
Expand All @@ -56,14 +80,6 @@ def test_returns_failed_validation_on_invalid_ipv4_address(address: str):
("::192.168.30.2",),
("0000:0000:0000:0000:0000::",),
("0:a:b:c:d:e:f::",),
# w/ cidr
("::1/128",),
("::1/0",),
("dead:beef:0:0:0:0:42:1/8",),
("abcd:ef::42:1/32",),
("0:0:0:0:0:ffff:1.2.3.4/16",),
("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64",),
("::192.168.30.2/128",),
],
)
def test_returns_true_on_valid_ipv6_address(address: str):
Expand All @@ -72,6 +88,26 @@ def test_returns_true_on_valid_ipv6_address(address: str):
assert not ipv4(address)


@pytest.mark.parametrize(
("address", "cidr", "strict", "host_bit"),
[
("::1/128", True, True, True),
("::1/0", True, True, True),
("dead:beef:0:0:0:0:42:1/8", True, True, True),
("abcd:ef::42:1/32", True, True, True),
("0:0:0:0:0:ffff:1.2.3.4/16", True, True, True),
("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", True, True, True),
("::192.168.30.2/128", True, True, True),
],
)
def test_returns_true_on_valid_ipv6_cidr_address(
address: str, cidr: bool, strict: bool, host_bit: bool
):
"""Test returns true on valid ipv6 CIDR address."""
assert ipv6(address, cidr=cidr, strict=strict, host_bit=host_bit)
assert not ipv4(address, cidr=cidr, strict=strict, host_bit=host_bit)


@pytest.mark.parametrize(
("address",),
[
Expand All @@ -91,12 +127,24 @@ def test_returns_true_on_valid_ipv6_address(address: str):
("::1:2::",),
("8::1:2::9",),
("02001:0000:1234:0000:0000:C1C0:ABCD:0876",),
# w/ cidr
("::1/129",),
("::1/-1",),
("::1/foo",),
],
)
def test_returns_failed_validation_on_invalid_ipv6_address(address: str):
"""Test returns failed validation on invalid ipv6 address."""
assert isinstance(ipv6(address), ValidationError)


@pytest.mark.parametrize(
("address", "cidr", "strict", "host_bit"),
[
("::1/128", False, True, True),
("::1/129", True, False, True),
("dead:beef:0:0:0:0:42:1/8", True, True, False),
("::1/-130", True, True, True),
],
)
def test_returns_failed_validation_on_invalid_ipv6_cidr_address(
address: str, cidr: bool, strict: bool, host_bit: bool
):
"""Test returns failed validation on invalid ipv6 CIDR address."""
assert isinstance(ipv6(address, cidr=cidr, strict=strict, host_bit=host_bit), ValidationError)

0 comments on commit 71b40bd

Please sign in to comment.