From 43f4ed2e0e2386add20226665c85947ead8a0b29 Mon Sep 17 00:00:00 2001 From: Tanmay Satam Date: Thu, 8 Feb 2024 17:42:50 -0500 Subject: [PATCH] Update az aro permissions validation to mirror RP frontend validation --- .../az/aro/azext_aro/_dynamic_validators.py | 23 ++++-- .../latest/unit/test_dynamic_validators.py | 76 ++++++++++++++++++- 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/python/az/aro/azext_aro/_dynamic_validators.py b/python/az/aro/azext_aro/_dynamic_validators.py index 3dda7b78404..3494c1b0864 100644 --- a/python/az/aro/azext_aro/_dynamic_validators.py +++ b/python/az/aro/azext_aro/_dynamic_validators.py @@ -27,16 +27,27 @@ def can_do_action(perms, action): for perm in perms: - for not_action in perm.not_actions: - match = re.escape(not_action) - match = re.match("(?i)^" + match.replace(r"\*", ".*") + "$", action) - if match: - return f"{action} permission is disabled" + matched = False + for perm_action in perm.actions: match = re.escape(perm_action) match = re.match("(?i)^" + match.replace(r"\*", ".*") + "$", action) if match: - return None + matched = True + break + + if not matched: + continue + + for not_action in perm.not_actions: + match = re.escape(not_action) + match = re.match("(?i)^" + match.replace(r"\*", ".*") + "$", action) + if match: + matched = False + break + + if matched: + return None return f"{action} permission is missing" diff --git a/python/az/aro/azext_aro/tests/latest/unit/test_dynamic_validators.py b/python/az/aro/azext_aro/tests/latest/unit/test_dynamic_validators.py index a71b64fbc02..8e5b64abe0d 100644 --- a/python/az/aro/azext_aro/tests/latest/unit/test_dynamic_validators.py +++ b/python/az/aro/azext_aro/tests/latest/unit/test_dynamic_validators.py @@ -3,12 +3,82 @@ from unittest.mock import Mock, patch from azext_aro._dynamic_validators import ( - dyn_validate_cidr_ranges, dyn_validate_subnet_and_route_tables, dyn_validate_vnet, dyn_validate_resource_permissions, dyn_validate_version + can_do_action, + dyn_validate_cidr_ranges, + dyn_validate_subnet_and_route_tables, + dyn_validate_vnet, + dyn_validate_resource_permissions, + dyn_validate_version ) from azure.mgmt.authorization.models import Permission import pytest +test_can_do_action_data = [ + ( + "empty permissions list", + [], + "Microsoft.Network/virtualNetworks/subnets/join/action", + "Microsoft.Network/virtualNetworks/subnets/join/action permission is missing" + ), + ( + "has permission - exact", + [ + Permission(actions=["Microsoft.Compute/virtualMachines/*"], not_actions=[]), + Permission(actions=["Microsoft.Network/virtualNetworks/subnets/join/action"], not_actions=[]), + ], + "Microsoft.Network/virtualNetworks/subnets/join/action", + None + ), + ( + "has permission - wildcard", + [ + Permission(actions=["Microsoft.Network/virtualNetworks/subnets/*/action"], not_actions=[]), + ], + "Microsoft.Network/virtualNetworks/subnets/join/action", + None + ), + ( + "has permission - exact, conflict", + [ + Permission(actions=[], not_actions=["Microsoft.Network/virtualNetworks/subnets/join/action"]), + Permission(actions=["Microsoft.Network/virtualNetworks/subnets/join/action"], not_actions=[]), + ], + "Microsoft.Network/virtualNetworks/subnets/join/action", + None + ), + ( + "has permission excluded - exact", + [ + Permission(actions=["Microsoft.Network/*"], not_actions=["Microsoft.Network/virtualNetworks/subnets/join/action"]), + ], + "Microsoft.Network/virtualNetworks/subnets/join/action", + "Microsoft.Network/virtualNetworks/subnets/join/action permission is missing" + ), + ( + "has permission excluded - wildcard", + [ + Permission(actions=["Microsoft.Network/*"], not_actions=["Microsoft.Network/virtualNetworks/subnets/*/action"]), + ], + "Microsoft.Network/virtualNetworks/subnets/join/action", + "Microsoft.Network/virtualNetworks/subnets/join/action permission is missing" + ) +] + + +@pytest.mark.parametrize( + "test_description, perms, action, expected_error", + test_can_do_action_data, + ids=[i[0] for i in test_can_do_action_data] +) +def test_can_do_action( + test_description, perms, action, expected_error +): + error = can_do_action(perms, action) + + if error != expected_error: + raise Exception(f"Error mismatch, expected: {expected_error}, actual: {error}") + test_validate_cidr_data = [ ( @@ -166,7 +236,7 @@ def test_validate_cidr( "child_name_1": None }, Mock(), - "Microsoft.Network/routeTables/join/action permission is disabled" + "Microsoft.Network/routeTables/join/action permission is missing" ), ( "should return missing permission when actions are not present", @@ -301,7 +371,7 @@ def test_validate_subnets( "child_name_1": None }, Mock(), - "Microsoft.Network/virtualNetworks/join/action permission is disabled" + "Microsoft.Network/virtualNetworks/join/action permission is missing" ), ( "should return missing permission when actions are not present",