From ea2bd1de65111e77cd19e11b8ab435109fd84d2b Mon Sep 17 00:00:00 2001 From: Stephen Doiron <53412380+sdoiron0330@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:28:04 -0500 Subject: [PATCH 1/3] replace capirca with aerleon --- nautobot_firewall_models/constants.py | 50 ++++++------- nautobot_firewall_models/utils/capirca.py | 4 +- poetry.lock | 89 +++++++++++------------ pyproject.toml | 2 +- 4 files changed, 71 insertions(+), 74 deletions(-) diff --git a/nautobot_firewall_models/constants.py b/nautobot_firewall_models/constants.py index d642c106..effc68e5 100644 --- a/nautobot_firewall_models/constants.py +++ b/nautobot_firewall_models/constants.py @@ -22,103 +22,103 @@ # This is used to provide hints (for type), and dotted string back (for lib) to Capirca CAPIRCA_MAPPER = { "arista": { - "lib": "capirca.lib.arista.Arista", + "lib": "aerleon.lib.arista.Arista", "type": "filter-name", }, "aruba": { - "lib": "capirca.lib.aruba.Aruba", + "lib": "aerleon.lib.aruba.Aruba", "type": "filter-name", }, "brocade": { - "lib": "capirca.lib.brocade.Brocade", + "lib": "aerleon.lib.brocade.Brocade", "type": "filter-name", }, "cisco": { - "lib": "capirca.lib.cisco.Cisco", + "lib": "aerleon.lib.cisco.Cisco", "type": "filter-name", }, "ciscoasa": { - "lib": "capirca.lib.ciscoasa.CiscoASA", + "lib": "aerleon.lib.ciscoasa.CiscoASA", "type": "filter-name", }, "cisconx": { - "lib": "capirca.lib.cisconx.ciscoNX", + "lib": "aerleon.lib.cisconx.ciscoNX", "type": "filter-name", }, "cloudarmor": { - "lib": "capirca.lib.cloudarmor.CloudArmor", + "lib": "aerleon.lib.cloudarmor.CloudArmor", "type": "filter_type", }, "gce": { - "lib": "capirca.lib.gce.GCE", + "lib": "aerleon.lib.gce.GCE", "type": "filter-name", }, "gcp_hf": { - "lib": "capirca.lib.gcp.GCP", + "lib": "aerleon.lib.gcp.GCP", "type": "filter-name", }, "ipset": { - "lib": "capirca.lib.ipset.Ipset", + "lib": "aerleon.lib.ipset.Ipset", "type": "direction", }, "iptables": { - "lib": "capirca.lib.iptables.Iptables", + "lib": "aerleon.lib.iptables.Iptables", "type": "direction", }, "juniper": { - "lib": "capirca.lib.juniper.Juniper", + "lib": "aerleon.lib.juniper.Juniper", "type": "filter-name", }, "juniperevo": { - "lib": "capirca.lib.juniperevo.JuniperEvo", + "lib": "aerleon.lib.juniperevo.JuniperEvo", "type": "filter-name", }, "junipermsmpc": { - "lib": "capirca.lib.junipermsmpc.JuniperMSMPC", + "lib": "aerleon.lib.junipermsmpc.JuniperMSMPC", "type": "filter-name", }, "srx": { - "lib": "capirca.lib.junipersrx.JuniperSRX", + "lib": "aerleon.lib.junipersrx.JuniperSRX", "type": "zone", }, "k8s": { - "lib": "capirca.lib.k8s.K8s", + "lib": "aerleon.lib.k8s.K8s", "type": "direction", }, "nftables": { - "lib": "capirca.lib.nftables.Nftables", + "lib": "aerleon.lib.nftables.Nftables", "type": "address_family", }, "nsxv": { - "lib": "capirca.lib.nsxv.Nsxv", + "lib": "aerleon.lib.nsxv.Nsxv", "type": "filter-name", }, "packetfilter": { - "lib": "capirca.lib.packetfilter.PacketFilter", + "lib": "aerleon.lib.packetfilter.PacketFilter", "type": "filter-name", }, "paloalto": { - "lib": "capirca.lib.paloaltofw.PaloAltoFW", + "lib": "aerleon.lib.paloaltofw.PaloAltoFW", "type": "zone", }, "pcap": { - "lib": "capirca.lib.pcap.PcapFilter", + "lib": "aerleon.lib.pcap.PcapFilter", "type": "filter-name", }, "speedway": { - "lib": "capirca.lib.speedway.Speedway", + "lib": "aerleon.lib.speedway.Speedway", "type": "direction", }, "srxlo": { - "lib": "capirca.lib.srxlo.SRXlo", + "lib": "aerleon.lib.srxlo.SRXlo", "type": "filter-name", }, "windows_advfirewall": { - "lib": "capirca.lib.windows_advfirewall.WindowsAdvFirewall", + "lib": "aerleon.lib.windows_advfirewall.WindowsAdvFirewall", "type": "direction", }, "windows_ipsec": { - "lib": "capirca.lib.windows_ipsec.WindowsIPSec", + "lib": "aerleon.lib.windows_ipsec.WindowsIPSec", "type": "filter-name", }, } diff --git a/nautobot_firewall_models/utils/capirca.py b/nautobot_firewall_models/utils/capirca.py index 712c01b5..7ad379f9 100644 --- a/nautobot_firewall_models/utils/capirca.py +++ b/nautobot_firewall_models/utils/capirca.py @@ -3,8 +3,8 @@ import logging import re import unicodedata -from capirca.lib.naming import Naming -from capirca.lib import policy +from aerleon.lib.naming import Naming +from aerleon.lib import policy from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError diff --git a/poetry.lock b/poetry.lock index 73d09ec0..5c68fe39 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,16 +1,34 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "absl-py" -version = "2.0.0" +version = "1.4.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "absl-py-2.0.0.tar.gz", hash = "sha256:d9690211c5fcfefcdd1a45470ac2b5c5acd45241c3af71eed96bc5441746c0d5"}, - {file = "absl_py-2.0.0-py3-none-any.whl", hash = "sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3"}, + {file = "absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d"}, + {file = "absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47"}, ] +[[package]] +name = "aerleon" +version = "1.7.0" +description = "A firewall generation tool" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "aerleon-1.7.0-py3-none-any.whl", hash = "sha256:9048050281df938b85083130215f05ea073c8aff6bbeaede5e0a87fcac79fa82"}, + {file = "aerleon-1.7.0.tar.gz", hash = "sha256:f3145c2a04f37c0463fbd80ee650f039bda9bc445e9c7fd4f18d8eeeda1b6ead"}, +] + +[package.dependencies] +absl-py = ">=1.2.0,<2.0.0" +importlib-metadata = {version = ">=4.2,<5.0", markers = "python_version <= \"3.10\""} +ply = ">=3.11,<4.0" +PyYAML = ">=6.0,<7.0" +typing_extensions = ">=4.4.0,<5.0.0" + [[package]] name = "amqp" version = "5.2.0" @@ -253,24 +271,6 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] -[[package]] -name = "capirca" -version = "2.0.9" -description = "Capirca" -optional = false -python-versions = ">=3.6" -files = [ - {file = "capirca-2.0.9-py3-none-any.whl", hash = "sha256:cf333ac9315f0d61890710f412f6b113950095ff71580530887b48b267fe2a6f"}, - {file = "capirca-2.0.9.tar.gz", hash = "sha256:48e33e5d06f3a877ff49fe7f3bea94757f8e421d3e2112a7bdc2d02c257ac987"}, -] - -[package.dependencies] -absl-py = "*" -mock = "*" -ply = "*" -PyYAML = "*" -six = "*" - [[package]] name = "celery" version = "5.3.6" @@ -1345,22 +1345,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "4.13.0" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, + {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "importlib-resources" @@ -1902,22 +1902,6 @@ files = [ griffe = ">=0.35" mkdocstrings = ">=0.20" -[[package]] -name = "mock" -version = "5.1.0" -description = "Rolling backport of unittest.mock for all Pythons" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744"}, - {file = "mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d"}, -] - -[package.extras] -build = ["blurb", "twine", "wheel"] -docs = ["sphinx"] -test = ["pytest", "pytest-cov"] - [[package]] name = "mypy-extensions" version = "1.0.0" @@ -2286,6 +2270,7 @@ files = [ {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, @@ -2294,6 +2279,8 @@ files = [ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, @@ -2659,6 +2646,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -2666,8 +2654,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -2684,6 +2679,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -2691,6 +2687,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3508,4 +3505,4 @@ all = [] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "2556ccc74ba2190be8368061393473586299f54e8594ff6993d48d5896e6d1e2" +content-hash = "23916fac6a17da974332e58939eba80f94014896cad0861b6941f2e94203dc7a" diff --git a/pyproject.toml b/pyproject.toml index e84070b7..c2ef8db5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ python = ">=3.8,<3.12" # Used for local development nautobot = "^2.0.0" netutils = "^1.0.0" -capirca = "^2.0.6" +aerleon = "^1.7.0" [tool.poetry.group.dev.dependencies] bandit = "*" From 1110a8c1e3f99c1d88dadc25ff038b8669064291 Mon Sep 17 00:00:00 2001 From: Stephen Doiron <53412380+sdoiron0330@users.noreply.github.com> Date: Sun, 7 Apr 2024 20:19:44 -0500 Subject: [PATCH 2/3] initial pass at aerleon refactor --- development/nautobot_config.py | 2 +- docs/admin/install.md | 6 +- docs/user/app_overview.md | 2 +- nautobot_firewall_models/__init__.py | 4 +- nautobot_firewall_models/api/serializers.py | 6 +- nautobot_firewall_models/api/urls.py | 2 +- nautobot_firewall_models/api/views.py | 10 +- .../app-config-schema.json | 4 +- nautobot_firewall_models/constants.py | 16 +- nautobot_firewall_models/filters.py | 6 +- nautobot_firewall_models/forms.py | 32 ++-- nautobot_firewall_models/homepage.py | 10 +- nautobot_firewall_models/jobs.py | 14 +- .../commands/create_test_firewall_data.py | 4 +- .../migrations/0021_auto_20240406_0053.py | 35 ++++ nautobot_firewall_models/models/__init__.py | 6 +- .../{capirca_policy.py => aerleon_policy.py} | 26 +-- nautobot_firewall_models/navigation.py | 8 +- nautobot_firewall_models/tables.py | 6 +- nautobot_firewall_models/template_content.py | 14 +- ...etails.html => aerleonpolicy_details.html} | 10 +- ...rieve.html => aerleonpolicy_retrieve.html} | 4 +- .../inc/aerleon_policy.html | 7 + .../inc/capirca_policy.html | 7 - nautobot_firewall_models/tests/fixtures.py | 6 +- .../{test_capirca.py => test_aerleon.py} | 154 +++++++++--------- .../tests/test_filters.py | 16 +- nautobot_firewall_models/tests/test_models.py | 10 +- .../tests/test_ui_views.py | 8 +- nautobot_firewall_models/urls.py | 4 +- .../utils/{capirca.py => aerleon.py} | 74 ++++----- nautobot_firewall_models/viewsets/__init__.py | 6 +- .../{capirca_policy.py => aerleon_policy.py} | 30 ++-- 33 files changed, 292 insertions(+), 257 deletions(-) create mode 100644 nautobot_firewall_models/migrations/0021_auto_20240406_0053.py rename nautobot_firewall_models/models/{capirca_policy.py => aerleon_policy.py} (68%) rename nautobot_firewall_models/templates/nautobot_firewall_models/{capircapolicy_details.html => aerleonpolicy_details.html} (73%) rename nautobot_firewall_models/templates/nautobot_firewall_models/{capircapolicy_retrieve.html => aerleonpolicy_retrieve.html} (84%) create mode 100644 nautobot_firewall_models/templates/nautobot_firewall_models/inc/aerleon_policy.html delete mode 100644 nautobot_firewall_models/templates/nautobot_firewall_models/inc/capirca_policy.html rename nautobot_firewall_models/tests/{test_capirca.py => test_aerleon.py} (80%) rename nautobot_firewall_models/utils/{capirca.py => aerleon.py} (91%) rename nautobot_firewall_models/viewsets/{capirca_policy.py => aerleon_policy.py} (58%) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index f83c96c8..f89dfb0d 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -132,7 +132,7 @@ # Each key in the dictionary is the name of an installed App and its value is a dictionary of settings. # PLUGINS_CONFIG = { # "nautobot_firewall_models": { -# "capirca_os_map": { +# "aerleon_os_map": { # "cisco_ios": "cisco", # "arista_eos": "arista", # } diff --git a/docs/admin/install.md b/docs/admin/install.md index 719fb191..d99af2e4 100644 --- a/docs/admin/install.md +++ b/docs/admin/install.md @@ -72,12 +72,12 @@ PLUGINS_CONFIG = { "nautobot_firewall_models": { "default_status": "Active", "allowed_status": ["Active"], # default shown, `[]` allows all - "capirca_remark_pass": True, - "capirca_os_map": { + "aerleon_remark_pass": True, + "aerleon_os_map": { "cisco_ios": "cisco", "arista_eos": "arista", }, - # "custom_capirca": "my.custom.func", # provides ability to overide capirca logic + # "custom_aerleon": "my.custom.func", # provides ability to overide aerleon logic } } ``` diff --git a/docs/user/app_overview.md b/docs/user/app_overview.md index 10024c26..49746e00 100644 --- a/docs/user/app_overview.md +++ b/docs/user/app_overview.md @@ -12,7 +12,7 @@ An app for [Nautobot](https://github.com/nautobot/nautobot) that is meant to mod - Layer 4 firewall policies - Extended access control lists - NAT policies -- Generation of firewall configurations, via Capirca +- Generation of firewall configurations, via Aerleon Future development will include the ability to onboard an existing access list from a device and the ability to generate device configuration. diff --git a/nautobot_firewall_models/__init__.py b/nautobot_firewall_models/__init__.py index e5676e33..256c8a4b 100644 --- a/nautobot_firewall_models/__init__.py +++ b/nautobot_firewall_models/__init__.py @@ -20,8 +20,8 @@ class NautobotFirewallModelsConfig(NautobotAppConfig): min_version = "2.0.0" max_version = "2.9999" default_settings = { - "capirca_remark_pass": True, - "capirca_os_map": {}, + "aerleon_remark_pass": True, + "aerleon_os_map": {}, "allowed_status": ["Active"], "protect_on_delete": True, } diff --git a/nautobot_firewall_models/api/serializers.py b/nautobot_firewall_models/api/serializers.py index 19f985f3..df2c171d 100644 --- a/nautobot_firewall_models/api/serializers.py +++ b/nautobot_firewall_models/api/serializers.py @@ -160,13 +160,13 @@ class Meta: fields = "__all__" -class CapircaPolicySerializer(NautobotModelSerializer): - """CapircaPolicy Serializer.""" +class AerleonPolicySerializer(NautobotModelSerializer): + """AerleonPolicy Serializer.""" class Meta: """Meta attributes.""" - model = models.CapircaPolicy + model = models.AerleonPolicy fields = "__all__" diff --git a/nautobot_firewall_models/api/urls.py b/nautobot_firewall_models/api/urls.py index e3eeb56e..afa50df1 100644 --- a/nautobot_firewall_models/api/urls.py +++ b/nautobot_firewall_models/api/urls.py @@ -10,7 +10,7 @@ router.register("address-object-group", views.AddressObjectGroupViewSet) router.register("application-object", views.ApplicationObjectViewSet) router.register("application-object-group", views.ApplicationObjectGroupViewSet) -router.register("capirca-policy", views.CapircaPolicyViewSet) +router.register("aerleon-policy", views.AerleonPolicyViewSet) router.register("fqdn", views.FQDNViewSet) router.register("ip-range", views.IPRangeViewSet) router.register("nat-policy-rule", views.NATPolicyRuleViewSet) diff --git a/nautobot_firewall_models/api/views.py b/nautobot_firewall_models/api/views.py index 1bf3de4e..b3453722 100644 --- a/nautobot_firewall_models/api/views.py +++ b/nautobot_firewall_models/api/views.py @@ -126,12 +126,12 @@ class NATPolicyViewSet(NautobotModelViewSet): filterset_class = filters.NATPolicyFilterSet -class CapircaPolicyViewSet(ModelViewSet): - """CapircaPolicy viewset.""" +class AerleonPolicyViewSet(ModelViewSet): + """AerleonPolicy viewset.""" - queryset = models.CapircaPolicy.objects.all() - serializer_class = serializers.CapircaPolicySerializer - filterset_class = filters.CapircaPolicyFilterSet + queryset = models.AerleonPolicy.objects.all() + serializer_class = serializers.AerleonPolicySerializer + filterset_class = filters.AerleonPolicyFilterSet ########################### diff --git a/nautobot_firewall_models/app-config-schema.json b/nautobot_firewall_models/app-config-schema.json index e4a2de16..7ca87315 100644 --- a/nautobot_firewall_models/app-config-schema.json +++ b/nautobot_firewall_models/app-config-schema.json @@ -13,11 +13,11 @@ "Active" ] }, - "capirca_remark_pass": { + "aerleon_remark_pass": { "type": "boolean", "default": true }, - "capirca_os_map": { + "caerleon_os_map": { "type": "object", "default": {} }, diff --git a/nautobot_firewall_models/constants.py b/nautobot_firewall_models/constants.py index effc68e5..98d69e71 100644 --- a/nautobot_firewall_models/constants.py +++ b/nautobot_firewall_models/constants.py @@ -1,26 +1,26 @@ """Constants file.""" from django.conf import settings -# This is used to map the slug of the platform in the customers environment to the expected name that Capirca is looking for -CAPIRCA_OS_MAPPER = {} +# This is used to map the slug of the platform in the customers environment to the expected name that Aerleon is looking for +AERLEON_OS_MAPPER = {} PLUGIN_CFG = settings.PLUGINS_CONFIG.get("nautobot_firewall_models", {}) -if PLUGIN_CFG.get("capirca_os_map"): - CAPIRCA_OS_MAPPER = PLUGIN_CFG["capirca_os_map"] +if PLUGIN_CFG.get("aerleon_os_map"): + AERLEON_OS_MAPPER = PLUGIN_CFG["aerleon_os_map"] # This is used to determine which status slug names are valid ALLOW_STATUS = ["Active"] if PLUGIN_CFG.get("allowed_status"): ALLOW_STATUS = PLUGIN_CFG["allowed_status"] -# This is used to whitelist actions that align with Capirca +# This is used to whitelist actions that align with Aerleon ACTION_MAP = {"allow": "accept", "deny": "deny", "drop": "reject"} # no next or reject-with-tcp-rst -# This is used to transpose string booleans to Capirca expectations +# This is used to transpose string booleans to Aerleon expectations LOGGING_MAP = {"true": "true", "false": "disable"} -# This is used to provide hints (for type), and dotted string back (for lib) to Capirca -CAPIRCA_MAPPER = { +# This is used to provide hints (for type), and dotted string back (for lib) to Aerleon +AERLEON_MAPPER = { "arista": { "lib": "aerleon.lib.arista.Arista", "type": "filter-name", diff --git a/nautobot_firewall_models/filters.py b/nautobot_firewall_models/filters.py index d1f4a873..fe8a1684 100644 --- a/nautobot_firewall_models/filters.py +++ b/nautobot_firewall_models/filters.py @@ -211,8 +211,8 @@ class Meta: fields = [i.name for i in model._meta.get_fields() if not isinstance(i, GenericRelation)] -class CapircaPolicyFilterSet(NautobotFilterSet): - """Filter for CapircaPolicy.""" +class AerleonPolicyFilterSet(NautobotFilterSet): + """Filter for AerleonPolicy.""" device = NaturalKeyOrPKMultipleChoiceFilter( field_name="device", @@ -224,7 +224,7 @@ class CapircaPolicyFilterSet(NautobotFilterSet): class Meta: """Meta attributes for filter.""" - model = models.CapircaPolicy + model = models.AerleonPolicy fields = [i.name for i in model._meta.get_fields() if not isinstance(i, GenericRelation)] diff --git a/nautobot_firewall_models/forms.py b/nautobot_firewall_models/forms.py index dd4c8104..56df7e8d 100644 --- a/nautobot_firewall_models/forms.py +++ b/nautobot_firewall_models/forms.py @@ -894,18 +894,18 @@ class Meta: ] -# CapircaPolicy +# AerleonPolicy -class CapircaPolicyForm(LocalContextModelForm, NautobotModelForm): - """Filter Form for CapircaPolicy instances.""" +class AerleonPolicyForm(LocalContextModelForm, NautobotModelForm): + """Filter Form for AerleonPolicy instances.""" device = DynamicModelChoiceField(queryset=Device.objects.all()) class Meta: """Boilerplate form Meta data for compliance rule.""" - model = models.CapircaPolicy + model = models.AerleonPolicy fields = ( "device", "pol", @@ -915,30 +915,30 @@ class Meta: ) -class CapircaPolicyFilterForm(LocalContextFilterForm, NautobotFilterForm): - """Form for CapircaPolicy instances.""" +class AerleonPolicyFilterForm(LocalContextFilterForm, NautobotFilterForm): + """Form for AerleonPolicy instances.""" - model = models.CapircaPolicy + model = models.AerleonPolicy q = forms.CharField(required=False, label="Search") -class CapircaPolicyBulkEditForm(LocalContextModelBulkEditForm, NautobotBulkEditForm): - """BulkEdit form for CapircaPolicy instances.""" +class AerleonPolicyBulkEditForm(LocalContextModelBulkEditForm, NautobotBulkEditForm): + """BulkEdit form for AerleonPolicy instances.""" - pk = forms.ModelMultipleChoiceField(queryset=models.CapircaPolicy.objects.all(), widget=forms.MultipleHiddenInput) + pk = forms.ModelMultipleChoiceField(queryset=models.AerleonPolicy.objects.all(), widget=forms.MultipleHiddenInput) class Meta: - """Boilerplate form Meta data for CapircaPolicy.""" + """Boilerplate form Meta data for AerleonPolicy.""" nullable_fields = [] -class CapircaPolicyCSVForm(CustomFieldModelCSVForm): - """CSV Form for CapircaPolicy instances.""" +class AerleonPolicyCSVForm(CustomFieldModelCSVForm): + """CSV Form for AerleonPolicy instances.""" class Meta: - """Boilerplate form Meta data for CapircaPolicy.""" + """Boilerplate form Meta data for AerleonPolicy.""" - model = models.CapircaPolicy - fields = models.CapircaPolicy.csv_headers + model = models.AerleonPolicy + fields = models.AerleonPolicy.csv_headers diff --git a/nautobot_firewall_models/homepage.py b/nautobot_firewall_models/homepage.py index 43fd948f..f85660ef 100644 --- a/nautobot_firewall_models/homepage.py +++ b/nautobot_firewall_models/homepage.py @@ -1,7 +1,7 @@ """Adds App items to homepage.""" from nautobot.core.apps import HomePageItem, HomePagePanel -from nautobot_firewall_models.models import Policy, PolicyRule, CapircaPolicy, NATPolicy, NATPolicyRule +from nautobot_firewall_models.models import Policy, PolicyRule, AerleonPolicy, NATPolicy, NATPolicyRule layout = ( HomePagePanel( @@ -25,12 +25,12 @@ permissions=["nautobot_firewall_models.view_natpolicy"], ), HomePageItem( - name="Capirca Policies", - model=CapircaPolicy, + name="Aerleon Policies", + model=AerleonPolicy, weight=300, - link="plugins:nautobot_firewall_models:capircapolicy_list", + link="plugins:nautobot_firewall_models:aerleonpolicy_list", description="Firewall Policies", - permissions=["nautobot_firewall_models.view_capircapolicy"], + permissions=["nautobot_firewall_models.view_aerleonpolicy"], ), HomePageItem( name="Security Rules", diff --git a/nautobot_firewall_models/jobs.py b/nautobot_firewall_models/jobs.py index 354d3cc3..31a280fa 100644 --- a/nautobot_firewall_models/jobs.py +++ b/nautobot_firewall_models/jobs.py @@ -3,16 +3,16 @@ from nautobot.core.celery import register_jobs from nautobot.dcim.models import Device -from nautobot_firewall_models.models import CapircaPolicy +from nautobot_firewall_models.models import AerleonPolicy from nautobot_firewall_models.models import Policy logger = get_task_logger(__name__) -name = "Capirca Jobs" # pylint: disable=invalid-name +name = "Aerleon Jobs" # pylint: disable=invalid-name -class RunCapircaJob(Job): # pylint disable=too-few-public-method +class RunAerleonJob(Job): # pylint disable=too-few-public-method """Class definition to use as Mixin for form definitions.""" device = MultiObjectVar(model=Device, required=False) @@ -20,8 +20,8 @@ class RunCapircaJob(Job): # pylint disable=too-few-public-method class Meta: """Meta object boilerplate for reservations.""" - name = "Generate FW Config via Capirca." - description = "Generate FW Config via Capirca and update the models." + name = "Generate FW Config via Aerleon." + description = "Generate FW Config via Aerleon and update the models." commit_default = True has_sensitive_variables = False @@ -48,9 +48,9 @@ def run(self, device): # pylint: disable=arguments-differ for dev in devices: device_obj = Device.objects.get(pk=dev) logger.debug("Running against Device: `%s`", str(device_obj)) - CapircaPolicy.objects.update_or_create(device=device_obj) + AerleonPolicy.objects.update_or_create(device=device_obj) logger.info(f"{device_obj} Updated", extra={"object": device_obj}) -jobs = [RunCapircaJob] +jobs = [RunAerleonJob] register_jobs(*jobs) diff --git a/nautobot_firewall_models/management/commands/create_test_firewall_data.py b/nautobot_firewall_models/management/commands/create_test_firewall_data.py index 86bf0d40..edfaa9a6 100644 --- a/nautobot_firewall_models/management/commands/create_test_firewall_data.py +++ b/nautobot_firewall_models/management/commands/create_test_firewall_data.py @@ -3,7 +3,7 @@ from django.core.management.base import BaseCommand from django.db.utils import IntegrityError -from nautobot_firewall_models.tests.fixtures import create_capirca_env +from nautobot_firewall_models.tests.fixtures import create_aerleon_env class Command(BaseCommand): @@ -13,7 +13,7 @@ def handle(self, *args, **options): """Publish command to bootstrap dummy data.""" self.stdout.write("Attempting to populate dummy data.") try: - create_capirca_env() + create_aerleon_env() self.stdout.write(self.style.SUCCESS("Successfully populated dummy data!")) except IntegrityError: self.stdout.write( diff --git a/nautobot_firewall_models/migrations/0021_auto_20240406_0053.py b/nautobot_firewall_models/migrations/0021_auto_20240406_0053.py new file mode 100644 index 00000000..c7d8ba47 --- /dev/null +++ b/nautobot_firewall_models/migrations/0021_auto_20240406_0053.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.21 on 2024-04-06 00:53 + +import django.core.serializers.json +from django.db import migrations, models +import django.db.models.deletion +import nautobot.core.models.fields +import nautobot.extras.models.mixins +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("extras", "0098_rename_data_jobresult_result"), + ("dcim", "0049_remove_slugs_and_change_device_primary_ip_fields"), + ("nautobot_firewall_models", "0020_field_cleanups"), + ] + + operations = [ + migrations.RenameModel("CapircaPolicy", "AerleonPolicy"), + migrations.AlterModelOptions( + name="aerleonpolicy", + options={"ordering": ["device"], "verbose_name_plural": "Aerleon Policies"}, + ), + migrations.AlterField( + model_name="aerleonpolicy", + name="device", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="aerleon_policy", + to="dcim.device", + ), + ), + ] diff --git a/nautobot_firewall_models/models/__init__.py b/nautobot_firewall_models/models/__init__.py index c68d476c..0f8b9ad0 100644 --- a/nautobot_firewall_models/models/__init__.py +++ b/nautobot_firewall_models/models/__init__.py @@ -6,8 +6,8 @@ FQDN, IPRange, ) -from .capirca_policy import ( - CapircaPolicy, +from .aerleon_policy import ( + AerleonPolicy, ) from .nat_policy import ( NATPolicy, @@ -33,9 +33,9 @@ __all__ = ( "AddressObject", "AddressObjectGroup", + "AerleonPolicy", "ApplicationObject", "ApplicationObjectGroup", - "CapircaPolicy", "FQDN", "IPRange", "NATPolicy", diff --git a/nautobot_firewall_models/models/capirca_policy.py b/nautobot_firewall_models/models/aerleon_policy.py similarity index 68% rename from nautobot_firewall_models/models/capirca_policy.py rename to nautobot_firewall_models/models/aerleon_policy.py index c48ac661..c802ce0c 100644 --- a/nautobot_firewall_models/models/capirca_policy.py +++ b/nautobot_firewall_models/models/aerleon_policy.py @@ -1,4 +1,4 @@ -"""Models for the Capirca Configurations.""" +"""Models for the Aerleon Configurations.""" # pylint: disable=duplicate-code import logging @@ -8,7 +8,7 @@ from nautobot.extras.utils import extras_features from nautobot_firewall_models.constants import PLUGIN_CFG -from nautobot_firewall_models.utils.capirca import DevicePolicyToCapirca +from nautobot_firewall_models.utils.aerleon import DevicePolicyToAerleon LOGGER = logging.getLogger(__name__) @@ -23,11 +23,11 @@ "statuses", "webhooks", ) -class CapircaPolicy(PrimaryModel): - """CapircaPolicy model.""" +class AerleonPolicy(PrimaryModel): + """AerleonPolicy model.""" device = models.OneToOneField( - to="dcim.Device", blank=True, null=True, on_delete=models.CASCADE, related_name="capirca_policy" + to="dcim.Device", blank=True, null=True, on_delete=models.CASCADE, related_name="aerleon_policy" ) pol = models.TextField(blank=True) net = models.TextField(blank=True) @@ -40,24 +40,24 @@ class Meta: """Meta class.""" ordering = ["device"] - verbose_name_plural = "Capirca Policies" + verbose_name_plural = "Aerleon Policies" def __str__(self): """Stringify instance.""" - return f"Capirca Policy -> {self.device.name}" + return f"Aerleon Policy -> {self.device.name}" def save(self, *args, **kwargs): """Update the firewall rules as updates are made.""" - if not PLUGIN_CFG.get("custom_capirca"): - LOGGER.debug("Running standard Capirca conversion") - cap_obj = DevicePolicyToCapirca(self.device) - cap_obj.get_all_capirca_cfg() + if not PLUGIN_CFG.get("custom_aerleon"): + LOGGER.debug("Running standard Aerleon conversion") + cap_obj = DevicePolicyToAerleon(self.device) + cap_obj.get_all_aerleon_cfg() self.pol = cap_obj.pol_file self.svc = cap_obj.svc_file self.net = cap_obj.net_file self.cfg = cap_obj.cfg_file else: - LOGGER.debug("Running custom conversion from function: `%s`", str(PLUGIN_CFG["custom_capirca"])) - self.pol, self.svc, self.net, self.cfg = import_string(PLUGIN_CFG["custom_capirca"])(self.device) + LOGGER.debug("Running custom conversion from function: `%s`", str(PLUGIN_CFG["custom_aerleon"])) + self.pol, self.svc, self.net, self.cfg = import_string(PLUGIN_CFG["custom_aerleon"])(self.device) super().save(*args, **kwargs) diff --git a/nautobot_firewall_models/navigation.py b/nautobot_firewall_models/navigation.py index a7bd280c..7065b287 100644 --- a/nautobot_firewall_models/navigation.py +++ b/nautobot_firewall_models/navigation.py @@ -209,13 +209,13 @@ ], ), NavMenuGroup( - name="Capirca", + name="Aerleon", weight=200, items=[ NavMenuItem( - link="plugins:nautobot_firewall_models:capircapolicy_list", - name="Capirca Policy Rules", - permissions=["nautobot_firewall_models.view_capircapolicy"], + link="plugins:nautobot_firewall_models:aerleonpolicy_list", + name="Aerleon Policy Rules", + permissions=["nautobot_firewall_models.view_aerleonpolicy"], ), ], ), diff --git a/nautobot_firewall_models/tables.py b/nautobot_firewall_models/tables.py index 048b9f27..2576e123 100644 --- a/nautobot_firewall_models/tables.py +++ b/nautobot_firewall_models/tables.py @@ -331,16 +331,16 @@ class Meta(BaseTable.Meta): ) -class CapircaPolicyTable(BaseTable): +class AerleonPolicyTable(BaseTable): """Table for list view.""" pk = ToggleColumn() device = tables.TemplateColumn( - template_code="""{{ record.device }} """ + template_code="""{{ record.device }} """ ) class Meta(BaseTable.Meta): """Meta attributes.""" - model = models.CapircaPolicy + model = models.AerleonPolicy fields = ("pk", "device") diff --git a/nautobot_firewall_models/template_content.py b/nautobot_firewall_models/template_content.py index f6dd2231..aaa03018 100644 --- a/nautobot_firewall_models/template_content.py +++ b/nautobot_firewall_models/template_content.py @@ -1,7 +1,7 @@ """Extensions of baseline Nautobot views.""" from nautobot.apps.ui import TemplateExtension -from nautobot_firewall_models.models import CapircaPolicy +from nautobot_firewall_models.models import AerleonPolicy class DevicePolicies(TemplateExtension): # pylint: disable=abstract-method @@ -49,7 +49,7 @@ def right_page(self): ) -class CapircaPolicies(TemplateExtension): # pylint: disable=abstract-method +class AerleonPolicies(TemplateExtension): # pylint: disable=abstract-method """Add Policy to the right side of the Device page.""" model = "dcim.device" @@ -57,13 +57,13 @@ class CapircaPolicies(TemplateExtension): # pylint: disable=abstract-method def right_page(self): """Add content to the right side of the Devices detail view.""" try: - obj = CapircaPolicy.objects.get(device=self.context["object"]) + obj = AerleonPolicy.objects.get(device=self.context["object"]) return self.render( - "nautobot_firewall_models/inc/capirca_policy.html", - extra_context={"capirca_object": obj}, + "nautobot_firewall_models/inc/aerleon_policy.html", + extra_context={"aerleon_object": obj}, ) - except CapircaPolicy.DoesNotExist: + except AerleonPolicy.DoesNotExist: return "" -template_extensions = [DynamicGroupDevicePolicies, DevicePolicies, DynamicGroupPolicies, CapircaPolicies] +template_extensions = [DynamicGroupDevicePolicies, DevicePolicies, DynamicGroupPolicies, AerleonPolicies] diff --git a/nautobot_firewall_models/templates/nautobot_firewall_models/capircapolicy_details.html b/nautobot_firewall_models/templates/nautobot_firewall_models/aerleonpolicy_details.html similarity index 73% rename from nautobot_firewall_models/templates/nautobot_firewall_models/capircapolicy_details.html rename to nautobot_firewall_models/templates/nautobot_firewall_models/aerleonpolicy_details.html index de5614c3..be1dcf04 100644 --- a/nautobot_firewall_models/templates/nautobot_firewall_models/capircapolicy_details.html +++ b/nautobot_firewall_models/templates/nautobot_firewall_models/aerleonpolicy_details.html @@ -3,31 +3,31 @@ {% block content %} -

Capirca - {{ object.device }}

+

Aerleon - {{ object.device }}

-
Capirca Configuration +
Aerleon Configuration
{{ object.cfg }}
-
Capirca Policy +
Aerleon Policy
{{ object.pol }}
-
Capirca Networks +
Aerleon Networks
{{ object.net }}
-
Capirca Services +
Aerleon Services
{{ object.svc }}
diff --git a/nautobot_firewall_models/templates/nautobot_firewall_models/capircapolicy_retrieve.html b/nautobot_firewall_models/templates/nautobot_firewall_models/aerleonpolicy_retrieve.html similarity index 84% rename from nautobot_firewall_models/templates/nautobot_firewall_models/capircapolicy_retrieve.html rename to nautobot_firewall_models/templates/nautobot_firewall_models/aerleonpolicy_retrieve.html index c9a1f4fd..21781472 100644 --- a/nautobot_firewall_models/templates/nautobot_firewall_models/capircapolicy_retrieve.html +++ b/nautobot_firewall_models/templates/nautobot_firewall_models/aerleonpolicy_retrieve.html @@ -6,7 +6,7 @@ {% block buttons %} {% plugin_buttons object %} - {% if perms.nautobot_firewall_models.delete_capircapolicy %} + {% if perms.nautobot_firewall_models.delete_aerleonpolicy %} {% delete_button object %} {% endif %} {% endblock buttons %} @@ -14,7 +14,7 @@ {% block content_left_page %}
- Capirca Object + Aerleon Object
diff --git a/nautobot_firewall_models/templates/nautobot_firewall_models/inc/aerleon_policy.html b/nautobot_firewall_models/templates/nautobot_firewall_models/inc/aerleon_policy.html new file mode 100644 index 00000000..4b02f5c2 --- /dev/null +++ b/nautobot_firewall_models/templates/nautobot_firewall_models/inc/aerleon_policy.html @@ -0,0 +1,7 @@ +
+
+ Aerleon Firewall Configurations - + + +
+
\ No newline at end of file diff --git a/nautobot_firewall_models/templates/nautobot_firewall_models/inc/capirca_policy.html b/nautobot_firewall_models/templates/nautobot_firewall_models/inc/capirca_policy.html deleted file mode 100644 index ba13b666..00000000 --- a/nautobot_firewall_models/templates/nautobot_firewall_models/inc/capirca_policy.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
- Capirca Firewall Configurations - - - -
-
\ No newline at end of file diff --git a/nautobot_firewall_models/tests/fixtures.py b/nautobot_firewall_models/tests/fixtures.py index 9fc157e7..9fad5b73 100644 --- a/nautobot_firewall_models/tests/fixtures.py +++ b/nautobot_firewall_models/tests/fixtures.py @@ -396,8 +396,8 @@ def assign_policies(): # pylint: disable=too-many-locals NATPolicyDynamicGroupM2M.objects.get_or_create(nat_policy=nat_policy_3, dynamic_group=dynamic_group, weight=1000) -def create_capirca_env(): - """Create objects that are Capirca Ready.""" # pylint: disable=too-many-locals, too-many-statements +def create_aerleon_env(): + """Create objects that are Aerleon Ready.""" # pylint: disable=too-many-locals, too-many-statements assign_policies() namespace, _ = Namespace.objects.get_or_create(name="global") status = Status.objects.get(name="Active") @@ -433,6 +433,6 @@ def create_capirca_env(): addr_obj4.prefix = prefix addr_obj4.validated_save() - job = Job.objects.get(name="Generate FW Config via Capirca.") + job = Job.objects.get(name="Generate FW Config via Aerleon.") job.enabled = True job.validated_save() diff --git a/nautobot_firewall_models/tests/test_capirca.py b/nautobot_firewall_models/tests/test_aerleon.py similarity index 80% rename from nautobot_firewall_models/tests/test_capirca.py rename to nautobot_firewall_models/tests/test_aerleon.py index a0e9356e..cc750c0d 100644 --- a/nautobot_firewall_models/tests/test_capirca.py +++ b/nautobot_firewall_models/tests/test_aerleon.py @@ -1,4 +1,4 @@ -"""Test Capirca Utils.""" +"""Test Aerleon Utils.""" # flake8: noqa: F403,405 # pylint: disable=protected-access from unittest import skip @@ -10,9 +10,9 @@ from nautobot.ipam.models import IPAddress, Namespace from nautobot_firewall_models.models import * # pylint: disable=unused-wildcard-import, wildcard-import -from nautobot_firewall_models.utils.capirca import generate_capirca_config, PolicyToCapirca, DevicePolicyToCapirca +from nautobot_firewall_models.utils.aerleon import generate_aerleon_config, PolicyToAerleon, DevicePolicyToAerleon -from .fixtures import create_capirca_env +from .fixtures import create_aerleon_env POLICY = """header { target:: cisco 150 extended @@ -261,29 +261,29 @@ ] -class TestBasicCapirca(TestCase): +class TestBasicAerleon(TestCase): """Test models.""" def setUp(self) -> None: """Setup test data.""" - create_capirca_env() + create_aerleon_env() - def test_generate_capirca_config(self): - """Test the implementation of capirca.""" + def test_generate_aerleon_config(self): + """Test the implementation of aerleon.""" # This partially tests the underlying library, but kept since it helps ensure that overloading # ParseServiceList and ParseNetworkList continue to work. As well as provides an easy place to test locally. - # Such as running `invoke unittest -l nautobot_firewall_models.tests.test_capirca.TestBasicCapirca` and + # Such as running `invoke unittest -l nautobot_firewall_models.tests.test_aerleon.TestBasicAerleon` and # modifying data within test - actual_cfg = generate_capirca_config(SERVICES.split("\n"), NETWORKS.split("\n"), POLICY, "cisco") + actual_cfg = generate_aerleon_config(SERVICES.split("\n"), NETWORKS.split("\n"), POLICY, "cisco") self.assertEqual(actual_cfg, CFG) -class TestPolicyToCapirca(TestCase): # pylint: disable=too-many-public-methods,too-many-instance-attributes +class TestPolicyToAerleon(TestCase): # pylint: disable=too-many-public-methods,too-many-instance-attributes """Test models.""" def setUp(self) -> None: """Setup test data.""" - create_capirca_env() + create_aerleon_env() self.active = Status.objects.get(name="Active") self.decomm = Status.objects.get(name="Decommissioned") self.device_obj = Device.objects.get(name="DFW02-WAN00") @@ -313,12 +313,12 @@ def test_address_skip(self): """Check that address objects are found with status active and not found when other.""" self.pol_rule6.source_addresses.set([self.addr_obj4, self.addr_obj5]) self.pol_rule6.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-name", networkdata) self.addr_obj5.status = self.decomm self.addr_obj5.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("test-name", networkdata) self.pol_rule6.source_addresses.clear() @@ -327,12 +327,12 @@ def test_address_skip(self): self.pol_rule6.destination_addresses.set([self.addr_obj4, self.addr_obj5]) self.pol_rule6.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-name", networkdata) self.addr_obj5.status = self.decomm self.addr_obj5.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("test-name", networkdata) def test_address_empty(self): @@ -341,42 +341,42 @@ def test_address_empty(self): self.addr_obj5.status = self.decomm self.addr_obj5.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.pol_rule6.source_addresses.clear() self.pol_rule6.destination_addresses.set([self.addr_obj5]) with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_address_fqdn(self): - """Test that validation fails on creating an FQDN when using capirca.""" + """Test that validation fails on creating an FQDN when using aerleon.""" fqdn1 = FQDN.objects.create(name="test.other", status=self.active) self.addr_obj5.ip_address = None self.addr_obj5.fqdn = fqdn1 self.addr_obj5.validated_save() self.pol_rule6.source_addresses.set([self.addr_obj5]) with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_address_ip_range(self): - """Test that validation fails on creating an IP range when using capirca.""" + """Test that validation fails on creating an IP range when using aerleon.""" iprange1 = IPRange.objects.create(start_address="192.168.0.21", end_address="192.168.0.30", status=self.active) self.addr_obj5.ip_address = None self.addr_obj5.ip_range = iprange1 self.addr_obj5.validated_save() self.pol_rule6.source_addresses.set([self.addr_obj5]) with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_address_group_skip(self): """Check that address group objects are found with status active and not found when other.""" self.pol_rule6.source_address_groups.set([self.addr_grp3, self.addr_grp4]) self.pol_rule6.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-group", networkdata) self.addr_grp4.status = self.decomm self.addr_grp4.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("test-group", networkdata) self.pol_rule6.source_address_groups.clear() @@ -385,12 +385,12 @@ def test_address_group_skip(self): self.pol_rule6.destination_address_groups.set([self.addr_grp3, self.addr_grp4]) self.pol_rule6.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-group", networkdata) self.addr_grp4.status = self.decomm self.addr_grp4.validated_save() - _, networkdata, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, networkdata, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("test-group", networkdata) def test_address_group_empty(self): @@ -399,20 +399,20 @@ def test_address_group_empty(self): self.addr_grp4.status = self.decomm self.addr_grp4.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_policy_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_policy_data() self.pol_rule6.source_addresses.set([self.addr_obj5]) self.pol_rule6.validated_save() - obj = PolicyToCapirca(self.dev_name, self.pol1) + obj = PolicyToAerleon(self.dev_name, self.pol1) obj.validate_policy_data() self.assertIn("test-name", obj.address) self.pol_rule6.destination_address_groups.clear() self.pol_rule6.destination_address_groups.set([self.addr_grp4]) self.pol_rule6.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_policy_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_policy_data() self.pol_rule6.destination_addresses.set([self.addr_obj5]) self.pol_rule6.validated_save() - obj = PolicyToCapirca(self.dev_name, self.pol1) + obj = PolicyToAerleon(self.dev_name, self.pol1) obj.validate_policy_data() self.assertIn("test-name", obj.address) @@ -426,25 +426,25 @@ def test_address_group_skipped_member(self): self.pol_rule6.source_address_groups.set([addr_grp6]) self.pol_rule6.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.pol_rule6.source_address_groups.clear() self.pol_rule6.destination_address_groups.set([addr_grp6]) self.pol_rule6.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_svcs_skip(self): """Check that service objects are found with status active and not found when other.""" svc_obj2 = ServiceObject.objects.get(name="SSH") self.pol_rule6.destination_services.set([self.svc_obj4, svc_obj2]) self.pol_rule6.validated_save() - _, _, servicedata = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, _, servicedata = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-service", servicedata) self.svc_obj4.status = self.decomm self.svc_obj4.validated_save() - _, _, servicedata = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, _, servicedata = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("test-service", servicedata) def test_svcs_skip_empty(self): @@ -453,19 +453,19 @@ def test_svcs_skip_empty(self): self.svc_obj4.status = self.decomm self.svc_obj4.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_svcs_group_skip(self): """Check that service objects are found with status active and not found when other.""" svc_grp1 = ServiceObjectGroup.objects.get(name="svc group1") self.pol_rule6.destination_service_groups.set([self.svc_grp4, svc_grp1]) self.pol_rule6.validated_save() - _, _, servicedata = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, _, servicedata = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-service-group", servicedata) self.svc_grp4.status = self.decomm self.svc_grp4.validated_save() - _, _, servicedata = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + _, _, servicedata = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("test-service-group", servicedata) def test_svcs_group_skip_empty(self): @@ -474,7 +474,7 @@ def test_svcs_group_skip_empty(self): self.svc_grp4.status = self.decomm self.svc_grp4.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_svcs_group_skipped_member(self): """Check that a service group whose members are all inactive gets cleared.""" @@ -483,11 +483,11 @@ def test_svcs_group_skipped_member(self): self.pol_rule6.destination_service_groups.set([self.svc_grp4]) self.pol_rule6.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() svc_obj2 = ServiceObject.objects.get(name="SSH") self.pol_rule6.destination_services.set([svc_obj2]) self.pol_rule6.validated_save() - cap_obj = PolicyToCapirca(self.dev_name, self.pol1) + cap_obj = PolicyToAerleon(self.dev_name, self.pol1) cap_obj.validate_policy_data() self.assertIn("SSH", cap_obj.service) @@ -497,7 +497,7 @@ def test_svcs_ip_protocol_not_expected(self): self.pol_rule6.destination_services.set([self.svc_obj4, svc_obj5]) self.pol_rule6.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_svcs_multi_proto_no_port(self): """Check that you can mix and match tcp/udp with other protocols, as long as no port.""" @@ -505,7 +505,7 @@ def test_svcs_multi_proto_no_port(self): svc_obj6 = ServiceObject.objects.create(name="TCP", ip_protocol="TCP", status=self.active) self.pol_rule6.destination_services.set([svc_obj5, svc_obj6]) self.pol_rule6.validated_save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertEqual(len(pol[1]["terms"]["destination-port"]), 0) self.assertEqual(pol[1]["terms"]["protocol"], ["icmp", "tcp"]) @@ -513,12 +513,12 @@ def test_policy_skip(self): """Check that policy rules are found with status active and not found when other.""" pol_rule5 = PolicyRule.objects.get(name="DENY ALL") self.pol1.policy_rules.add(pol_rule5) - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("Test", [i["rule-name"] for i in pol]) self.pol_rule6.status = self.decomm self.pol_rule6.validated_save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("Test", [i["rule-name"] for i in pol]) def test_policy_skip_empty(self): @@ -529,46 +529,46 @@ def test_policy_skip_empty(self): pol1.status = self.decomm pol1.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_policy_remark_skipped(self): """Test when remaek is skipped over.""" - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("Test", [i["rule-name"] for i in pol]) self.pol_rule6.action = "remark" self.pol_rule6.validated_save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertNotIn("Test", [i["rule-name"] for i in pol]) - @patch("nautobot_firewall_models.utils.capirca.PLUGIN_CFG", {"capirca_remark_pass": False}) + @patch("nautobot_firewall_models.utils.aerleon.PLUGIN_CFG", {"aerleon_remark_pass": False}) def test_policy_remark_fail(self): """Test when user configures to fail on remark.""" self.pol_rule6.action = "remark" self.pol_rule6.validated_save() with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() def test_policy_chd(self): """Test ability to inject custom headers.""" self.pol_rule6._custom_field_data = {"chd_test-custom": "unique-value"} self.pol_rule6.save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("unique-value", pol[1]["headers"]) def test_policy_ctd(self): """Test ability to inject custom terms.""" self.pol_rule6._custom_field_data = {"ctd_test-custom": "unique-value"} self.pol_rule6.save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-custom", pol[1]["terms"]) def test_policy_chd_allow_list(self): """Test headers can be allowed and not allowed based on custom field.""" self.pol_rule6._custom_field_data = {"chd_test-custom": "unique-value", "chd_test-other": "other-value"} self.pol_rule6.save() - self.device_obj.platform._custom_field_data = {"capirca_allow": ["chd_test-custom"]} + self.device_obj.platform._custom_field_data = {"aerleon_allow": ["chd_test-custom"]} self.device_obj.platform.save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("unique-value", pol[1]["headers"]) self.assertNotIn("other-value", pol[1]["headers"]) @@ -576,78 +576,78 @@ def test_policy_ctd_allow_list(self): """Test terms can be allowed and not allowed based on custom field.""" self.pol_rule6._custom_field_data = {"ctd_test-custom": "unique-value", "ctd_test-other": "other-value"} self.pol_rule6.save() - self.device_obj.platform._custom_field_data = {"capirca_allow": ["ctd_test-custom"]} + self.device_obj.platform._custom_field_data = {"aerleon_allow": ["ctd_test-custom"]} self.device_obj.platform.save() - pol, _, _ = PolicyToCapirca(self.dev_name, self.pol1).validate_capirca_data() + pol, _, _ = PolicyToAerleon(self.dev_name, self.pol1).validate_aerleon_data() self.assertIn("test-custom", pol[1]["terms"]) self.assertNotIn("test-other", pol[1]["terms"]) def test_validate_policy_data(self): """Test validate_policy_data produces consistent results.""" - cap_obj = PolicyToCapirca(self.dev_name, self.pol1) + cap_obj = PolicyToAerleon(self.dev_name, self.pol1) cap_obj.validate_policy_data() self.assertEqual(cap_obj.policy, POLICY_DATA) def test_validate_policy_data_no_policy(self): """Test that it fails when you do not provied ability to get policy_detail obj.""" with self.assertRaises(ValidationError): - PolicyToCapirca(self.dev_name).validate_policy_data() + PolicyToAerleon(self.dev_name).validate_policy_data() - def test_alt_capirca_type(self): - """Test non-zone Capirca config generation.""" + def test_alt_aerleon_type(self): + """Test non-zone Aerleon config generation.""" Platform.objects.create(name="Cisco", network_driver="cisco") - cap_obj = PolicyToCapirca("cisco", self.pol1) - cap_obj.get_capirca_cfg() + cap_obj = PolicyToAerleon("cisco", self.pol1) + cap_obj.get_aerleon_cfg() self.assertIn("cisco", cap_obj.pol_file) - def test_validate_capirca_data_bad_platform(self): + def test_validate_aerleon_data_bad_platform(self): """Ensure that an error is raised if platform is not found.""" Platform.objects.create(name="Fake Platform", network_driver="fake") with self.assertRaises(ValidationError): - PolicyToCapirca("fake", self.pol1).validate_capirca_data() + PolicyToAerleon("fake", self.pol1).validate_aerleon_data() - @patch("nautobot_firewall_models.utils.capirca.CAPIRCA_OS_MAPPER", {"srx": "paloaltofw"}) - def test_capirca_os_map(self): + @patch("nautobot_firewall_models.utils.aerleon.AERLEON_OS_MAPPER", {"srx": "paloaltofw"}) + def test_aerleon_os_map(self): """Verify the os config map solution works.""" - cap_obj = PolicyToCapirca(self.dev_name, self.pol1) + cap_obj = PolicyToAerleon(self.dev_name, self.pol1) self.assertEqual(cap_obj.platform, "paloaltofw") - def test_capirca_conversion(self): + def test_aerleon_conversion(self): """Verify that generating full config for a polucy is as expected.""" - cap_obj = PolicyToCapirca(self.dev_name, self.pol1) - cap_obj.get_capirca_cfg() + cap_obj = PolicyToAerleon(self.dev_name, self.pol1) + cap_obj.get_aerleon_cfg() self.assertEqual(cap_obj.net_file, NETWORKS2) self.assertEqual(cap_obj.svc_file, SERVICES2) self.assertEqual(cap_obj.pol_file, POLICY2) -class TestDevicePolicyToCapirca(TestCase): +class TestDevicePolicyToAerleon(TestCase): """Test models.""" def setUp(self) -> None: """Setup test data.""" - create_capirca_env() + create_aerleon_env() self.device_obj = Device.objects.get(name="DFW02-WAN00") @skip("Not implemented until policy method provided to merge queries provided") def test_dynamic_group_and_device(self): """Test that dynamic groups are created and device is added to it, disabled.""" - def test_multi_policy_capirca_config(self): + def test_multi_policy_aerleon_config(self): """Verify that generating full config for a device is as expected.""" - cap_obj = DevicePolicyToCapirca(self.device_obj) - cap_obj.get_all_capirca_cfg() + cap_obj = DevicePolicyToAerleon(self.device_obj) + cap_obj.get_all_aerleon_cfg() self.assertEqual(cap_obj.pol_file, POLICYALL) def test_multi_policy_skipped(self): """Ensure that when a policy is not active, it is removed from consideration.""" - cap_obj = DevicePolicyToCapirca(self.device_obj) - cap_obj.get_all_capirca_cfg() + cap_obj = DevicePolicyToAerleon(self.device_obj) + cap_obj.get_all_aerleon_cfg() self.assertEqual(len(cap_obj.policy), 7) decomm = Status.objects.get(name="Decommissioned") pol3 = Policy.objects.get(name="Policy 3") pol3.status = decomm pol3.validated_save() - cap_obj = DevicePolicyToCapirca(self.device_obj) - cap_obj.get_all_capirca_cfg() + cap_obj = DevicePolicyToAerleon(self.device_obj) + cap_obj.get_all_aerleon_cfg() self.assertEqual(len(cap_obj.policy), 3) diff --git a/nautobot_firewall_models/tests/test_filters.py b/nautobot_firewall_models/tests/test_filters.py index b69b96ef..0321e9aa 100644 --- a/nautobot_firewall_models/tests/test_filters.py +++ b/nautobot_firewall_models/tests/test_filters.py @@ -6,22 +6,22 @@ from nautobot.dcim.models import Device from nautobot_firewall_models import filters, models -from .fixtures import create_capirca_env +from .fixtures import create_aerleon_env -class CapircaPolicyModelTestCase(TestCase): - """Test filtering operations for CapircaPolicy Model.""" +class AerleonPolicyModelTestCase(TestCase): + """Test filtering operations for AerleonPolicy Model.""" - queryset = models.CapircaPolicy.objects.all() - filterset = filters.CapircaPolicyFilterSet + queryset = models.AerleonPolicy.objects.all() + filterset = filters.AerleonPolicyFilterSet def setUp(self): """Set up base objects.""" - create_capirca_env() + create_aerleon_env() self.dev01 = Device.objects.get(name="DFW02-WAN00") dev02 = Device.objects.get(name="HOU02-WAN00") - models.CapircaPolicy.objects.create(device=self.dev01) - models.CapircaPolicy.objects.create(device=dev02) + models.AerleonPolicy.objects.create(device=self.dev01) + models.AerleonPolicy.objects.create(device=dev02) def test_id(self): """Test filtering by ID (primary key).""" diff --git a/nautobot_firewall_models/tests/test_models.py b/nautobot_firewall_models/tests/test_models.py index b77f29a4..179f44dd 100644 --- a/nautobot_firewall_models/tests/test_models.py +++ b/nautobot_firewall_models/tests/test_models.py @@ -337,17 +337,17 @@ def test_policy_to_json(self): ) -class TestCapircaModels(TestCase): - """Test the Capirca model.""" +class TestAerleonModels(TestCase): + """Test the Aerleon model.""" def setUp(self) -> None: """Create the data.""" - fixtures.create_capirca_env() + fixtures.create_aerleon_env() - def test_capirca_creates_model(self): + def test_aerleon_creates_model(self): """Test method to create model.""" device_obj = Device.objects.get(name="DFW02-WAN00") - cap_obj = CapircaPolicy.objects.create(device=device_obj) + cap_obj = AerleonPolicy.objects.create(device=device_obj) svc = "PGSQL = 5432/tcp" self.assertIn(svc, cap_obj.svc) net = "printer = 10.0.0.100/32" diff --git a/nautobot_firewall_models/tests/test_ui_views.py b/nautobot_firewall_models/tests/test_ui_views.py index e9a14f57..55c2153c 100644 --- a/nautobot_firewall_models/tests/test_ui_views.py +++ b/nautobot_firewall_models/tests/test_ui_views.py @@ -387,14 +387,14 @@ def setUpTestData(cls): ) -class CapircaPolicyUIViewTest(ViewTestCases.GetObjectViewTestCase, ViewTestCases.ListObjectsViewTestCase): +class AerleonPolicyUIViewTest(ViewTestCases.GetObjectViewTestCase, ViewTestCases.ListObjectsViewTestCase): """Test the Policy viewsets.""" - model = CapircaPolicy + model = AerleonPolicy @classmethod def setUpTestData(cls): """Create test data.""" - fixtures.create_capirca_env() + fixtures.create_aerleon_env() for device in Device.objects.all(): - CapircaPolicy.objects.create(device=device) + AerleonPolicy.objects.create(device=device) diff --git a/nautobot_firewall_models/urls.py b/nautobot_firewall_models/urls.py index 6b9c8bf0..f15fa7fe 100644 --- a/nautobot_firewall_models/urls.py +++ b/nautobot_firewall_models/urls.py @@ -12,8 +12,8 @@ router.register("address-object-group", viewsets.AddressObjectGroupUIViewSet) router.register("application-object", viewsets.ApplicationObjectUIViewSet) router.register("application-object-group", viewsets.ApplicationObjectGroupUIViewSet) -router.register("capirca-policy", viewsets.CapircaPolicyUIViewSet) -router.register("capirca-policy-device", viewsets.CapircaPolicyDeviceUIViewSet, basename="capircapolicy_devicedetail") +router.register("aerleon-policy", viewsets.AerleonPolicyUIViewSet) +router.register("aerleon-policy-device", viewsets.AerleonPolicyDeviceUIViewSet, basename="aerleonpolicy_devicedetail") router.register("fqdn", viewsets.FQDNUIViewSet) router.register("ip-range", viewsets.IPRangeUIViewSet) router.register("nat-policy", viewsets.NATPolicyUIViewSet) diff --git a/nautobot_firewall_models/utils/capirca.py b/nautobot_firewall_models/utils/aerleon.py similarity index 91% rename from nautobot_firewall_models/utils/capirca.py rename to nautobot_firewall_models/utils/aerleon.py index 7ad379f9..246e4770 100644 --- a/nautobot_firewall_models/utils/capirca.py +++ b/nautobot_firewall_models/utils/aerleon.py @@ -14,10 +14,10 @@ from nautobot_firewall_models.constants import ( ALLOW_STATUS, - CAPIRCA_OS_MAPPER, + AERLEON_OS_MAPPER, ACTION_MAP, LOGGING_MAP, - CAPIRCA_MAPPER, + AERLEON_MAPPER, PLUGIN_CFG, ) from nautobot_firewall_models.utils import model_to_json @@ -70,8 +70,8 @@ def _check_status(status): return False -def generate_capirca_config(servicedata, networkdata, pol, platform): - """Given platform with pol, net, svc files have Capirca generate config.""" +def generate_aerleon_config(servicedata, networkdata, pol, platform): + """Given platform with pol, net, svc files have Aerleon generate config.""" defs = Naming(None) LOGGER.debug("Parsing Service List") defs.ParseServiceList(servicedata) @@ -81,18 +81,18 @@ def generate_capirca_config(servicedata, networkdata, pol, platform): pol = policy.ParsePolicy(pol, defs, optimize=True) LOGGER.debug("Parsing Policy Completed") - LOGGER.debug("Running Capirca Against: %s", str(CAPIRCA_MAPPER[platform]["lib"])) - return str(import_string(CAPIRCA_MAPPER[platform]["lib"])(pol, 0)) + LOGGER.debug("Running Aerleon Against: %s", str(AERLEON_MAPPER[platform]["lib"])) + return str(import_string(AERLEON_MAPPER[platform]["lib"])(pol, 0)) -class PolicyToCapirca: - """Class object to convert Policy orm object to Capirca object.""" +class PolicyToAerleon: + """Class object to convert Policy orm object to Aerleon object.""" def __init__(self, platform, policy_obj=None, **kwargs): """Overload init to account for computed field.""" self.policy_name = str(policy_obj) self.platform_obj = Platform.objects.get(network_driver=platform) - self.platform = CAPIRCA_OS_MAPPER.get(platform, platform) + self.platform = AERLEON_OS_MAPPER.get(platform, platform) self.policy_details = None if policy_obj: self.policy_details = policy_obj.policy_details @@ -110,13 +110,13 @@ def __init__(self, platform, policy_obj=None, **kwargs): self.cfg_file = "" # TODO: Evaluate if this is the best way to manage # Currently this hints as to when to use additional terms or headers - _allow_list = self.platform_obj.custom_field_data.get("capirca_allow") - self.cf_allow_list_enabled = bool("capirca_allow" in self.platform_obj.custom_field_data) + _allow_list = self.platform_obj.custom_field_data.get("aerleon_allow") + self.cf_allow_list_enabled = bool("aerleon_allow" in self.platform_obj.custom_field_data) self.cf_allow_list = _allow_list if _allow_list else [] LOGGER.debug("Processing Policy: `%s`", str(self.policy_name)) LOGGER.debug("Original Platform Name: `%s`", str(platform)) - LOGGER.debug("Capirca Platform Name: `%s`", str(self.platform)) + LOGGER.debug("Aerleon Platform Name: `%s`", str(self.platform)) LOGGER.debug("cf_allow_list_enabled: `%s`", str(self.cf_allow_list_enabled)) LOGGER.debug("cf_allow_list: `%s`", str(self.cf_allow_list)) @@ -130,7 +130,7 @@ def _check_for_empty(_type, start1, start2, end1, end2): raise ValidationError( f"{_type} with values of `{data}` had all instances removed." "The likely cause of this is either the status was not active or " - "Capirca does not support the value you provided, and was removed from consideration" + "Aerleon does not support the value you provided, and was removed from consideration" ) def _format_data(self, data, _type): @@ -219,7 +219,7 @@ def validate_policy_data(self): # pylint: disable=too-many-branches,too-many-st if _check_status(rule["rule"].status.name): LOGGER.debug("Skipped due to status: `%s`", str(rule["rule"])) continue - if rule["action"] == "remark" and PLUGIN_CFG["capirca_remark_pass"] is True: + if rule["action"] == "remark" and PLUGIN_CFG["aerleon_remark_pass"] is True: continue rule_src_addr = [] rule_src_addr_group = [] @@ -374,10 +374,10 @@ def validate_policy_data(self): # pylint: disable=too-many-branches,too-many-st " is empty or the status of all rules was not active." ) - def validate_capirca_data(self): # pylint: disable=too-many-statements,too-many-branches - """Helper method to get data in format required for Capirca. + def validate_aerleon_data(self): # pylint: disable=too-many-statements,too-many-branches + """Helper method to get data in format required for Aerleon. - This provides the Capirca checking that should, specifically + This provides the Aerleon checking that should, specifically * Combine address|address group, service|service group objects * Lowercase the protocol * Nomalize port format @@ -394,9 +394,9 @@ def validate_capirca_data(self): # pylint: disable=too-many-statements,too-many if not self.policy: self.validate_policy_data() - if not CAPIRCA_MAPPER.get(self.platform): + if not AERLEON_MAPPER.get(self.platform): raise ValidationError( - f"The platform network driver {self.platform} was not one of the supported options {list(CAPIRCA_MAPPER.keys())}." + f"The platform network driver {self.platform} was not one of the supported options {list(AERLEON_MAPPER.keys())}." ) networkdata = {} @@ -404,11 +404,11 @@ def validate_capirca_data(self): # pylint: disable=too-many-statements,too-many name = _slugify(name) if addresses.get("ip_range"): raise ValidationError( - f"The ip_range object `{addresses['ip_range']}` was attempted which is not supported by Capirca." + f"The ip_range object `{addresses['ip_range']}` was attempted which is not supported by Aerleon." ) if addresses.get("fqdn"): raise ValidationError( - f"The fqdn object `{addresses['fqdn']}` was attempted which is not supported by Capirca." + f"The fqdn object `{addresses['fqdn']}` was attempted which is not supported by Aerleon." ) if addresses.get("ip_address"): networkdata[name] = [addresses["ip_address"]] @@ -435,7 +435,7 @@ def validate_capirca_data(self): # pylint: disable=too-many-statements,too-many for name, services in self.service_group.items(): name = _slugify(name) services = _clean_list(services, True) - # A service in Capirca is TCP/UDP, What if all child services + # A service in Aerleon is TCP/UDP, What if all child services # had not TCP/UDP Ports. Since servicedata is only populated if # in fact there is a port, procede if any of the child objects # have a port, otherwise pass @@ -486,12 +486,12 @@ def validate_capirca_data(self): # pylint: disable=too-many-statements,too-many ) rule_details["headers"].append(self.platform) - if CAPIRCA_MAPPER[self.platform]["type"] == "zone": + if AERLEON_MAPPER[self.platform]["type"] == "zone": from_zone = _slugify(pol["from-zone"]) to_zone = _slugify(pol["to-zone"]) rule_details["headers"].extend(["from-zone", from_zone, "to-zone", to_zone]) LOGGER.debug("Zone Logic hit, from-zone: `%s` to-zone: `%s`", from_zone, to_zone) - if CAPIRCA_MAPPER[self.platform]["type"] == "filter-name": + if AERLEON_MAPPER[self.platform]["type"] == "filter-name": rule_details["headers"].append(rule_details["rule-name"]) LOGGER.debug("Filter Name Logic hit for: `%s`", str(rule_details["rule-name"])) @@ -513,8 +513,8 @@ def validate_capirca_data(self): # pylint: disable=too-many-statements,too-many return cap_policy, networkdata, servicedata @staticmethod - def _get_capirca_files(cap_policy, networkdata, servicedata): # pylint: disable=too-many-branches - """Convert the data structures taken in by method to Capirca configs.""" + def _get_aerleon_files(cap_policy, networkdata, servicedata): # pylint: disable=too-many-branches + """Convert the data structures taken in by method to Aerleon configs.""" pol = [] for index, rule in enumerate(cap_policy): LOGGER.debug("Index `%s` for rule `%s`", str(index), str(rule)) @@ -553,27 +553,27 @@ def _get_capirca_files(cap_policy, networkdata, servicedata): # pylint: disable servicecfg.append(" " * (len(name) + 3) + service) return pol, networkcfg, servicecfg - def get_capirca_cfg(self): - """Generate Capirca formatted data structure, convert that into Capirca text config, run Capirca.""" - cap_policy, networkdata, servicedata = self.validate_capirca_data() - pol, networkcfg, servicecfg = self._get_capirca_files(cap_policy, networkdata, servicedata) + def get_aerleon_cfg(self): + """Generate Aerleon formatted data structure, convert that into Aerleon text config, run Aerleon.""" + cap_policy, networkdata, servicedata = self.validate_aerleon_data() + pol, networkcfg, servicecfg = self._get_aerleon_files(cap_policy, networkdata, servicedata) self.pol_file = "\n".join(pol) self.net_file = "\n".join(networkcfg) self.svc_file = "\n".join(servicecfg) - self.cfg_file = generate_capirca_config(servicecfg, networkcfg, self.pol_file, self.platform) + self.cfg_file = generate_aerleon_config(servicecfg, networkcfg, self.pol_file, self.platform) -class DevicePolicyToCapirca(PolicyToCapirca): - """Class object to convert Policy orm object to Capirca object for a whole device.""" +class DevicePolicyToAerleon(PolicyToAerleon): + """Class object to convert Policy orm object to Aerleon object for a whole device.""" def __init__(self, device_obj, **kwargs): # pylint: disable=super-init-not-called """Overload init.""" super().__init__(device_obj.platform.network_driver, **kwargs) self.policy_objs = [] policy_name = [] - LOGGER.debug("Capirca Platform Name: `%s`", str(self.platform)) + LOGGER.debug("Aerleon Platform Name: `%s`", str(self.platform)) LOGGER.debug("Original Platform Name: `%s`", str(device_obj.platform.network_driver)) LOGGER.debug("cf_allow_list_enabled: `%s`", str(self.cf_allow_list_enabled)) LOGGER.debug("cf_allow_list: `%s`", str(self.cf_allow_list)) @@ -590,8 +590,8 @@ def __init__(self, device_obj, **kwargs): # pylint: disable=super-init-not-call self.policy_name = "__".join(policy_name) - def get_all_capirca_cfg(self): - """Aggregate off of the Capirca Configurations for a device.""" + def get_all_aerleon_cfg(self): + """Aggregate off of the Aerleon Configurations for a device.""" for pol in self.policy_objs: if _check_status(pol.status.name): LOGGER.debug("Policy Skipped due to status: `%s`", str(pol)) @@ -599,4 +599,4 @@ def get_all_capirca_cfg(self): self.policy_details = pol.policy_details self.validate_policy_data() - self.get_capirca_cfg() + self.get_aerleon_cfg() diff --git a/nautobot_firewall_models/viewsets/__init__.py b/nautobot_firewall_models/viewsets/__init__.py index 9b9a4c5e..23f45642 100644 --- a/nautobot_firewall_models/viewsets/__init__.py +++ b/nautobot_firewall_models/viewsets/__init__.py @@ -5,7 +5,7 @@ FQDNUIViewSet, IPRangeUIViewSet, ) -from nautobot_firewall_models.viewsets.capirca_policy import CapircaPolicyUIViewSet, CapircaPolicyDeviceUIViewSet +from nautobot_firewall_models.viewsets.aerleon_policy import AerleonPolicyUIViewSet, AerleonPolicyDeviceUIViewSet from nautobot_firewall_models.viewsets.nat_policy import NATPolicyRuleUIViewSet, NATPolicyUIViewSet from nautobot_firewall_models.viewsets.security_policy import PolicyUIViewSet, PolicyRuleUIViewSet from nautobot_firewall_models.viewsets.service import ( @@ -21,10 +21,10 @@ __all__ = ( "AddressObjectUIViewSet", "AddressObjectGroupUIViewSet", + "AerleonPolicyUIViewSet", + "AerleonPolicyDeviceUIViewSet", "ApplicationObjectUIViewSet", "ApplicationObjectGroupUIViewSet", - "CapircaPolicyUIViewSet", - "CapircaPolicyDeviceUIViewSet", "FQDNUIViewSet", "IPRangeUIViewSet", "NATPolicyRuleUIViewSet", diff --git a/nautobot_firewall_models/viewsets/capirca_policy.py b/nautobot_firewall_models/viewsets/aerleon_policy.py similarity index 58% rename from nautobot_firewall_models/viewsets/capirca_policy.py rename to nautobot_firewall_models/viewsets/aerleon_policy.py index ff0c4151..88615881 100644 --- a/nautobot_firewall_models/viewsets/capirca_policy.py +++ b/nautobot_firewall_models/viewsets/aerleon_policy.py @@ -1,4 +1,4 @@ -"""Capirca Policy Object Viewsets.""" +"""Aerleon Policy Object Viewsets.""" from nautobot.apps.views import ( ObjectListViewMixin, @@ -14,41 +14,41 @@ from nautobot_firewall_models import forms, models, tables, filters -class CapircaPolicyUIViewSet( +class AerleonPolicyUIViewSet( ObjectListViewMixin, ObjectBulkDestroyViewMixin, ObjectDetailViewMixin, ObjectChangeLogViewMixin, ObjectDestroyViewMixin, ): # pylint: disable=abstract-method - """ViewSet for the CapircaPolicy model.""" - - bulk_update_form_class = forms.CapircaPolicyBulkEditForm - filterset_class = filters.CapircaPolicyFilterSet - filterset_form_class = forms.CapircaPolicyFilterForm - form_class = forms.CapircaPolicyForm - queryset = models.CapircaPolicy.objects.all() - serializer_class = serializers.CapircaPolicySerializer - table_class = tables.CapircaPolicyTable + """ViewSet for the AerleonPolicy model.""" + + bulk_update_form_class = forms.AerleonPolicyBulkEditForm + filterset_class = filters.AerleonPolicyFilterSet + filterset_form_class = forms.AerleonPolicyFilterForm + form_class = forms.AerleonPolicyForm + queryset = models.AerleonPolicy.objects.all() + serializer_class = serializers.AerleonPolicySerializer + table_class = tables.AerleonPolicyTable action_buttons = None lookup_field = "pk" -class CapircaPolicyDeviceUIViewSet(ObjectDetailViewMixin): # pylint: disable=abstract-method - """ViewSet for the CapircaPolicy Device Details.""" +class AerleonPolicyDeviceUIViewSet(ObjectDetailViewMixin): # pylint: disable=abstract-method + """ViewSet for the AerleonPolicy Device Details.""" queryset = Device.objects.all() lookup_field = "pk" def get_template_name(self): """Set template name.""" - return "nautobot_firewall_models/capircapolicy_details.html" + return "nautobot_firewall_models/aerleonpolicy_details.html" def retrieve(self, request, *args, **kwargs): """Retrieve a model instance.""" device = self.get_object() - policy = models.CapircaPolicy.objects.get(device=device) + policy = models.AerleonPolicy.objects.get(device=device) context = {"object": policy, "device": device} context["use_new_ui"] = True return Response(context) From 19ccb89b5f23ba58c225eeff682e703931b1ea04 Mon Sep 17 00:00:00 2001 From: Stephen Doiron <53412380+sdoiron0330@users.noreply.github.com> Date: Fri, 12 Apr 2024 16:50:20 -0500 Subject: [PATCH 3/3] add change fragments --- changes/236.changed | 1 + changes/236.dependencies | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 changes/236.changed create mode 100644 changes/236.dependencies diff --git a/changes/236.changed b/changes/236.changed new file mode 100644 index 00000000..f0a68926 --- /dev/null +++ b/changes/236.changed @@ -0,0 +1 @@ +Updated all references of `capirca` to `aerleon`. \ No newline at end of file diff --git a/changes/236.dependencies b/changes/236.dependencies new file mode 100644 index 00000000..08c60008 --- /dev/null +++ b/changes/236.dependencies @@ -0,0 +1,2 @@ +Removed capirca dependency. +Added aerleon dependency. \ No newline at end of file