diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 257dc5a..a5d9cae 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,7 +23,7 @@ instead of permit host 10.0.0.1 -3.2.2 (2024-02-01) +3.2.3 (2024-02-01) ------------------ **Fixed:** ip access-list standard, permit A.B.C.D (without host keyword) diff --git a/README.rst b/README.rst index 2b16639..4417120 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,7 @@ or install the package from github.com release .. code:: bash - pip install https://github.com/vladimirs-git/cisco-acl/archive/refs/tags/3.2.2.tar.gz + pip install https://github.com/vladimirs-git/cisco-acl/archive/refs/tags/3.2.3.tar.gz or install the package from github.com repository diff --git a/cisco_acl/option.py b/cisco_acl/option.py index 201b7d1..3f5f795 100644 --- a/cisco_acl/option.py +++ b/cisco_acl/option.py @@ -1,6 +1,7 @@ """ACE. Option.""" from __future__ import annotations +import string from functools import total_ordering from cisco_acl import helpers as h @@ -70,10 +71,14 @@ def line(self, line: str) -> None: line = h.init_line(line) self._line = line - items: LStr = [s.strip() for s in line.split()] - items = [s for s in items if s] - self._flags = [s for s in items if s not in LOGS] - self._logs = [s for s in items if s in LOGS] + options: LStr = [s.strip() for s in line.split()] + options = [s for s in options if s] + for option in options: + if option[0] not in string.ascii_lowercase: + raise ValueError(f"invalid {option=}") + + self._flags = [s for s in options if s not in LOGS] + self._logs = [s for s in options if s in LOGS] @property def logs(self) -> LStr: diff --git a/examples/examples_acl_standard.py b/examples/examples_acl_standard.py index 8eae5ba..e350b89 100644 --- a/examples/examples_acl_standard.py +++ b/examples/examples_acl_standard.py @@ -6,8 +6,9 @@ ip access-list standard ACL1 permit 10.0.0.1 permit host 10.0.0.2 - permit host 10.0.0.3 0.0.0.0 + permit 10.0.0.3 0.0.0.0 permit 10.0.0.4 0.0.0.3 + permit 10.0.0.5 0.0.0.3 """ # Create ACL. @@ -16,7 +17,8 @@ # ip access-list standard ACL1 # permit host 10.0.0.1 # permit host 10.0.0.2 -# permit host 10.0.0.3 0.0.0.0 +# permit host 10.0.0.3 +# permit 10.0.0.4 0.0.0.3 # permit 10.0.0.4 0.0.0.3 # todo @@ -25,5 +27,6 @@ # ip access-list standard ACL1 # permit 10.0.0.1 # permit 10.0.0.2 -# permit 10.0.0.3 0.0.0.0 +# permit 10.0.0.3 +# permit 10.0.0.4 0.0.0.3 # permit 10.0.0.4 0.0.0.3 diff --git a/pyproject.toml b/pyproject.toml index 2f67114..702a775 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cisco_acl" -version = "3.2.2" +version = "3.2.3" description = "Python package to parse and manage Cisco ACL (Access Control List)" authors = ["Vladimirs Prusakovs "] readme = "README.rst" @@ -40,7 +40,7 @@ test = ["pytest"] [tool.poetry.urls] "Bug Tracker" = "https://github.com/vladimirs-git/cisco-acl/issues" -"Download URL" = "https://github.com/vladimirs-git/cisco-acl/archive/refs/tags/3.2.2.tar.gz" +"Download URL" = "https://github.com/vladimirs-git/cisco-acl/archive/refs/tags/3.2.3.tar.gz" [tool.pylint] max-line-length = 100 diff --git a/tests/test__ace.py b/tests/test__ace.py index 59ee6d9..ebcea4c 100644 --- a/tests/test__ace.py +++ b/tests/test__ace.py @@ -1141,6 +1141,25 @@ def test_valid__ungroup_ports(self): result = [o.line for o in aces] self.assertEqual(result, req, msg=f"{line=}") + def test_valid__check_parsed_elements(self): + """Ace._check_parsed_elements()""" + for data, req, in [ + (dict(protocol="ip", srcport="", dstport=""), True), + ]: + result = Ace._check_parsed_elements(line="", data=data) + self.assertEqual(result, req, msg=f"{data=}") + + def test_invalid__check_parsed_elements(self): + """Ace._check_parsed_elements()""" + for data, error, in [ + (dict(protocol="", srcport="", dstport=""), ValueError), + (dict(protocol="ip", srcport="1", dstport=""), ValueError), + (dict(protocol="ip", srcport="", dstport="1"), ValueError), + (dict(protocol="ip", srcport="1", dstport="1"), ValueError), + ]: + with self.assertRaises(error, msg=f"{data=}"): + Ace._check_parsed_elements(line="", data=data) + if __name__ == "__main__": unittest.main() diff --git a/tests/test__acl.py b/tests/test__acl.py index 8b37290..2dd4fc9 100644 --- a/tests/test__acl.py +++ b/tests/test__acl.py @@ -213,12 +213,23 @@ def test_valid__line(self): obj.line = kwargs["line"] self._test_attrs(obj=obj, req_d=req_d, msg=f"{kwargs=}") - def test_invalid__line(self): - """Acl.line""" + def test_invalid__line__skip(self): + """Acl.line skip invalid line""" + expected = ACL_NAME_IOS + for line in [ + f"{ACL_NAME_IOS}\npermit ip any any 0.0.0.0" # option + f"{ACL_NAME_IOS_STD}\npermit host 10.0.0.1 0.0.0.0" # option + ]: + obj = Acl(line, platform="ios") + result = str(obj).strip() + self.assertEqual(result, expected, msg=f"{line=}") + + def test_invalid__line__error(self): + """Acl.line raise error""" for line, error, in [ ("ip access-list extended\n permit ip any any", ValueError), # no name ("ip access-listy\n permit ip any any", ValueError), # no name - ("ip access-list extended NAME NAME\n permit ip any any", ValueError), # 2 names + (f"{ACL_NAME_IOS} NAME\n permit ip any any", ValueError), # 2 names (PERMIT_IP, ValueError), ]: with self.assertRaises(error, msg=f"{line=}"): @@ -341,12 +352,15 @@ def test_valid__type(self): host_ext = f"{ACL_NAME_IOS}\n" \ f" {REMARK}\n" \ f" permit tcp host 10.0.0.1 eq 1 host 10.0.0.2 eq 2 ack log" - host_std = f"{ACL_NAME_IOS_STD}\n" \ - f" {REMARK}\n" \ - f" permit host 10.0.0.1" - host_std_ = f"{ACL_NAME_IOS_STD}\n" \ + host1_std = f"{ACL_NAME_IOS_STD}\n" \ + f" {REMARK}\n" \ + f" permit host 10.0.0.1" + host2_std = f"{ACL_NAME_IOS_STD}\n" \ f" {REMARK}\n" \ f" permit 10.0.0.1" + host3_std = f"{ACL_NAME_IOS_STD}\n" \ + f" {REMARK}\n" \ + f" permit 10.0.0.1 0.0.0.0" host_ext_ = f"{ACL_NAME_IOS}\n" \ f" {REMARK}\n permit ip host 10.0.0.1 any" wild_ext = f"{ACL_NAME_IOS}\n" \ @@ -379,17 +393,19 @@ def test_valid__type(self): ("extended", "extended", wild_ext, wild_ext), ("extended", "extended", aceg_ext, aceg_ext), # extended to standard - ("extended", "standard", host_ext, host_std), + ("extended", "standard", host_ext, host1_std), ("extended", "standard", wild_ext, wild_std), ("extended", "standard", aceg_ext, aceg_std), # standard to standard - ("standard", "standard", host_std, host_std), - ("standard", "standard", host_std_, host_std), + ("standard", "standard", host1_std, host1_std), + ("standard", "standard", host2_std, host1_std), + ("standard", "standard", host3_std, host1_std), ("standard", "standard", wild_std, wild_std), ("standard", "standard", aceg_std, aceg_std), # standard to extended - ("standard", "extended", host_std, host_ext_), - ("standard", "extended", host_std_, host_ext_), + ("standard", "extended", host1_std, host_ext_), + ("standard", "extended", host2_std, host_ext_), + ("standard", "extended", host3_std, host_ext_), ("standard", "extended", wild_std, wild_ext_), ("standard", "extended", aceg_std, aceg_ext_), ]: diff --git a/tests/test__option.py b/tests/test__option.py index bc3d1e6..7ce4f49 100644 --- a/tests/test__option.py +++ b/tests/test__option.py @@ -67,6 +67,15 @@ def test_valid__line(self): obj1.line = line self._test_attrs(obj=obj1, req_d=req_d, msg=f"{line=}") + def test_invalid__line(self): + """Option.line()""" + for platform in h.PLATFORMS: + for line, error in [ + ("1", ValueError), + ]: + with self.assertRaises(error, msg=f"{line=}"): + Option(line=line, platform=platform) + def test_valid__platform(self): """Option.platform()""" option_d = dict(line="syn")