Skip to content

Commit dbca714

Browse files
committed
improve minimize performance
1 parent 3cfb484 commit dbca714

File tree

2 files changed

+54
-25
lines changed

2 files changed

+54
-25
lines changed

policy_sentry/writing/minimize.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,59 +21,56 @@
2121
* For managed policies: You can add up to 10 managed policies to a user, role, or group.
2222
* The size of each managed policy cannot exceed 6,144 characters.
2323
"""
24+
from __future__ import annotations
25+
2426
import logging
2527
import functools
2628

27-
# from policyuniverse.expander_minimizer import _get_prefixes_for_action
28-
2929
logger = logging.getLogger(__name__)
3030

3131

3232
# Borrowed from policyuniverse to reduce size
3333
# https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L45
3434
@functools.lru_cache(maxsize=1024)
35-
def _get_prefixes_for_action(action):
35+
def _get_prefixes_for_action(action: str) -> list[str]:
3636
"""
3737
:param action: iam:cat
3838
:return: [ "iam:", "iam:c", "iam:ca", "iam:cat" ]
3939
"""
40-
(technology, permission) = action.split(":")
41-
retval = ["{}:".format(technology)]
42-
phrase = ""
43-
for char in permission:
44-
newphrase = "{}{}".format(phrase, char)
45-
retval.append("{}:{}".format(technology, newphrase))
46-
phrase = newphrase
40+
technology, permission = action.split(":")
41+
retval = [f"{technology}:{permission[:i]}" for i in range(len(permission) + 1)]
42+
4743
return retval
4844

4945

5046
# Adapted version of policyuniverse's _get_denied_prefixes_from_desired, here:
5147
# https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L101
5248
def get_denied_prefixes_from_desired(
53-
desired_actions, all_actions
54-
): # pylint: disable=missing-function-docstring
49+
desired_actions: list[str], all_actions: set[str]
50+
) -> set[str]: # pylint: disable=missing-function-docstring
5551
"""
5652
Adapted version of policyuniverse's _get_denied_prefixes_from_desired, here: https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L101
5753
"""
5854
denied_actions = all_actions.difference(desired_actions)
59-
denied_prefixes = set()
60-
for denied_action in denied_actions:
61-
for denied_prefix in _get_prefixes_for_action(denied_action):
62-
denied_prefixes.add(denied_prefix)
55+
denied_prefixes = {
56+
denied_prefix
57+
for denied_action in denied_actions
58+
for denied_prefix in _get_prefixes_for_action(denied_action)
59+
}
6360

6461
return denied_prefixes
6562

6663

6764
# Adapted version of policyuniverse's _check_permission_length. We are commenting out the skipping prefix message
6865
# https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L111
6966
def check_min_permission_length(
70-
permission, minchars=None
71-
): # pylint: disable=missing-function-docstring
67+
permission: str, minchars: int | None = None
68+
) -> bool: # pylint: disable=missing-function-docstring
7269
"""
7370
Adapted version of policyuniverse's _check_permission_length. We are commenting out the skipping prefix message
7471
https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L111
7572
"""
76-
if minchars and len(permission) < int(minchars) and permission != "":
73+
if minchars and permission and len(permission) < int(minchars):
7774
# print(
7875
# "Skipping prefix {} because length of {}".format(
7976
# permission, len(permission)
@@ -87,8 +84,8 @@ def check_min_permission_length(
8784
# This is a condensed version of policyuniverse's minimize_statement_actions, changed for our purposes.
8885
# https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L123
8986
def minimize_statement_actions(
90-
desired_actions, all_actions, minchars=None
91-
): # pylint: disable=missing-function-docstring
87+
desired_actions: list[str], all_actions: set[str], minchars: int | None = None
88+
) -> list[str]: # pylint: disable=missing-function-docstring
9289
"""
9390
This is a condensed version of policyuniverse's minimize_statement_actions, changed for our purposes.
9491
https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L123
@@ -110,16 +107,16 @@ def minimize_statement_actions(
110107
continue
111108
# If the action name is not empty
112109
if prefix not in denied_prefixes:
113-
if permission != "":
110+
if permission:
114111
if prefix not in desired_actions:
115-
prefix = "{}*".format(prefix)
112+
prefix = f"{prefix}*"
116113
minimized_actions.add(prefix)
117114
found_prefix = True
118115
break
119116

120117
if not found_prefix:
121118
logger.debug(
122-
"Could not suitable prefix. Defaulting to %s".format(prefixes[-1])
119+
f"Could not find suitable prefix. Defaulting to {prefixes[-1]}"
123120
)
124121
minimized_actions.add(prefixes[-1])
125122
# sort the actions

test/writing/test_minimize.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import unittest
22
import json
33
from policy_sentry.writing.sid_group import SidGroup
4-
from policy_sentry.writing.minimize import minimize_statement_actions
4+
from policy_sentry.writing.minimize import (
5+
minimize_statement_actions,
6+
check_min_permission_length,
7+
)
58
from policy_sentry.querying.all import get_all_actions
69
from policy_sentry.util.policy_files import get_sid_names_from_policy, get_statement_from_policy_using_sid
710

@@ -45,6 +48,35 @@ def test_minimize_statement_actions_funky_case(self):
4548
sorted(desired_result),
4649
)
4750

51+
def test_minimize_statement_actions_with_min_chars(self):
52+
actions_to_minimize = [
53+
"ec2:AuthorizeSecurityGroupEgress",
54+
"ec2:AuthorizeSecurityGroupIngress",
55+
]
56+
desired_result = ["ec2:authorizesecurity*"]
57+
all_actions = get_all_actions(lowercase=True)
58+
minchars = 17
59+
self.maxDiff = None
60+
self.assertListEqual(
61+
sorted(
62+
minimize_statement_actions(actions_to_minimize, all_actions, minchars)
63+
),
64+
sorted(desired_result),
65+
)
66+
67+
def test_minimize_statement_actions_with_wildcard(self):
68+
actions_to_minimize = ["ec2:*"]
69+
desired_result = ["ec2:*"]
70+
all_actions = get_all_actions(lowercase=True)
71+
minchars = None
72+
self.maxDiff = None
73+
self.assertListEqual(
74+
sorted(
75+
minimize_statement_actions(actions_to_minimize, all_actions, minchars)
76+
),
77+
sorted(desired_result),
78+
)
79+
4880
def test_minimize_rw_same_one(self):
4981
cfg = {
5082
"mode": "crud",

0 commit comments

Comments
 (0)