diff --git a/_lastrevision b/_lastrevision index 1e0d9aa..1cf8c6b 100644 --- a/_lastrevision +++ b/_lastrevision @@ -1 +1 @@ -131b293221061447f0dc87b9b57ba29c1b8a7ae4 \ No newline at end of file +597049dd3d38cffb3d6e555ded591bc36ed09a58 \ No newline at end of file diff --git a/firewalld-normalize-new-rich-rules-before-comparing-.patch b/firewalld-normalize-new-rich-rules-before-comparing-.patch new file mode 100644 index 0000000..24f9281 --- /dev/null +++ b/firewalld-normalize-new-rich-rules-before-comparing-.patch @@ -0,0 +1,180 @@ +From 522b2331e6584758aeaefbf2d41f0c18cd1113d9 Mon Sep 17 00:00:00 2001 +From: Marek Czernek +Date: Tue, 23 Jul 2024 13:01:27 +0200 +Subject: [PATCH] firewalld: normalize new rich rules before comparing + to old (bsc#1222684) (#648) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +* Normalize new rich rules before comparing to old + +Firewallcmd rich rule output quotes each +assigned part of the rich rule, for example: +rule family="ipv4" source port port="161" ... +The firewalld module must first normalize +the user defined rich rules to match the +firewallcmd output before comparison to +ensure idempotency. + +* Add changelog entry + +* Enhance documentation for normalization function + +* Add unit tests to cover rich rules normalization + +--------- + +Co-authored-by: Pablo Suárez Hernández +--- + changelog/61235.fixed.md | 1 + + salt/states/firewalld.py | 38 +++++++++++- + tests/pytests/unit/states/test_firewalld.py | 64 +++++++++++++++++++++ + 3 files changed, 102 insertions(+), 1 deletion(-) + create mode 100644 changelog/61235.fixed.md + create mode 100644 tests/pytests/unit/states/test_firewalld.py + +diff --git a/changelog/61235.fixed.md b/changelog/61235.fixed.md +new file mode 100644 +index 00000000000..7ae9bb40800 +--- /dev/null ++++ b/changelog/61235.fixed.md +@@ -0,0 +1 @@ ++- firewalld: normalize new rich rules before comparing to old ones +diff --git a/salt/states/firewalld.py b/salt/states/firewalld.py +index 534b9dd62df..9ce0bfc61a8 100644 +--- a/salt/states/firewalld.py ++++ b/salt/states/firewalld.py +@@ -204,7 +204,6 @@ def present( + rich_rules=None, + prune_rich_rules=False, + ): +- + """ + Ensure a zone has specific attributes. + +@@ -378,6 +377,42 @@ def service(name, ports=None, protocols=None): + return ret + + ++def _normalize_rich_rules(rich_rules): ++ """ ++ Make sure rich rules are normalized and attributes ++ are quoted with double quotes so it matches the output ++ from firewall-cmd ++ ++ Example: ++ ++ rule family="ipv4" source address="192.168.0.0/16" port port=22 protocol=tcp accept ++ rule family="ipv4" source address="192.168.0.0/16" port port='22' protocol=tcp accept ++ rule family='ipv4' source address='192.168.0.0/16' port port='22' protocol=tcp accept ++ ++ normalized to: ++ ++ rule family="ipv4" source address="192.168.0.0/16" port port="22" protocol="tcp" accept ++ """ ++ normalized_rules = [] ++ for rich_rule in rich_rules: ++ normalized_rule = "" ++ for cmd in rich_rule.split(" "): ++ cmd_components = cmd.split("=", 1) ++ if len(cmd_components) == 2: ++ assigned_component = cmd_components[1] ++ if not assigned_component.startswith( ++ '"' ++ ) and not assigned_component.endswith('"'): ++ if assigned_component.startswith( ++ "'" ++ ) and assigned_component.endswith("'"): ++ assigned_component = assigned_component[1:-1] ++ cmd_components[1] = f'"{assigned_component}"' ++ normalized_rule = f"{normalized_rule} {'='.join(cmd_components)}" ++ normalized_rules.append(normalized_rule.lstrip()) ++ return normalized_rules ++ ++ + def _present( + name, + block_icmp=None, +@@ -761,6 +796,7 @@ def _present( + + if rich_rules or prune_rich_rules: + rich_rules = rich_rules or [] ++ rich_rules = _normalize_rich_rules(rich_rules) + try: + _current_rich_rules = __salt__["firewalld.get_rich_rules"]( + name, permanent=True +diff --git a/tests/pytests/unit/states/test_firewalld.py b/tests/pytests/unit/states/test_firewalld.py +new file mode 100644 +index 00000000000..0cbc59633bf +--- /dev/null ++++ b/tests/pytests/unit/states/test_firewalld.py +@@ -0,0 +1,64 @@ ++""" ++ :codeauthor: Hristo Voyvodov ++""" ++ ++import pytest ++ ++import salt.states.firewalld as firewalld ++from tests.support.mock import MagicMock, patch ++ ++ ++@pytest.fixture ++def configure_loader_modules(): ++ return {firewalld: {"__opts__": {"test": False}}} ++ ++ ++@pytest.mark.parametrize( ++ "rich_rule", ++ [ ++ ( ++ [ ++ 'rule family="ipv4" source address="192.168.0.0/16" port port=22 protocol=tcp accept' ++ ] ++ ), ++ ( ++ [ ++ 'rule family="ipv4" source address="192.168.0.0/16" port port=\'22\' protocol=tcp accept' ++ ] ++ ), ++ ( ++ [ ++ "rule family='ipv4' source address='192.168.0.0/16' port port='22' protocol=tcp accept" ++ ] ++ ), ++ ], ++) ++def test_present_rich_rules_normalized(rich_rule): ++ firewalld_reload_rules = MagicMock(return_value={}) ++ firewalld_rich_rules = [ ++ 'rule family="ipv4" source address="192.168.0.0/16" port port="22" protocol="tcp" accept', ++ ] ++ ++ firewalld_get_zones = MagicMock( ++ return_value=[ ++ "block", ++ "public", ++ ] ++ ) ++ firewalld_get_masquerade = MagicMock(return_value=False) ++ firewalld_get_rich_rules = MagicMock(return_value=firewalld_rich_rules) ++ ++ __salt__ = { ++ "firewalld.reload_rules": firewalld_reload_rules, ++ "firewalld.get_zones": firewalld_get_zones, ++ "firewalld.get_masquerade": firewalld_get_masquerade, ++ "firewalld.get_rich_rules": firewalld_get_rich_rules, ++ } ++ with patch.dict(firewalld.__dict__, {"__salt__": __salt__}): ++ ret = firewalld.present("public", rich_rules=rich_rule) ++ assert ret == { ++ "changes": {}, ++ "result": True, ++ "comment": "'public' is already in the desired state.", ++ "name": "public", ++ } +-- +2.45.2 + + diff --git a/salt.changes b/salt.changes index e1a7f3d..04f69a3 100644 --- a/salt.changes +++ b/salt.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Wed Jul 24 10:12:25 UTC 2024 - Pablo Suárez Hernández + +- Fix rich rule comparison in firewalld module (bsc#1222684) + +- Added: + * firewalld-normalize-new-rich-rules-before-comparing-.patch + ------------------------------------------------------------------- Tue Jul 9 11:23:20 UTC 2024 - Pablo Suárez Hernández diff --git a/salt.spec b/salt.spec index 4569c1d..374f1f8 100644 --- a/salt.spec +++ b/salt.spec @@ -408,6 +408,8 @@ Patch123: fix-user.list_groups-omits-remote-groups.patch Patch124: some-more-small-tests-fixes-enhancements-661.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/666 Patch125: test_vultrpy-adjust-test-expectation-to-prevent-fail.patch +# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/66698 +Patch126: firewalld-normalize-new-rich-rules-before-comparing-.patch ### IMPORTANT: The line below is used as a snippet marker. Do not touch it. ### SALT PATCHES LIST END