iam-policy-validator 1.10.1__py3-none-any.whl → 1.10.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/METADATA +1 -1
- {iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/RECORD +11 -11
- iam_validator/__version__.py +2 -2
- iam_validator/checks/wildcard_resource.py +29 -7
- iam_validator/core/aws_service/fetcher.py +24 -7
- iam_validator/core/aws_service/validators.py +3 -5
- iam_validator/core/config/defaults.py +28 -0
- iam_validator/sdk/policy_utils.py +3 -3
- {iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iam-policy-validator
|
|
3
|
-
Version: 1.10.
|
|
3
|
+
Version: 1.10.3
|
|
4
4
|
Summary: Validate AWS IAM policies for correctness and security using AWS Service Reference API
|
|
5
5
|
Project-URL: Homepage, https://github.com/boogy/iam-policy-validator
|
|
6
6
|
Project-URL: Documentation, https://github.com/boogy/iam-policy-validator/tree/main/docs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
iam_validator/__init__.py,sha256=xHdUASOxFHwEXfT_GSr_KrkLlnxZ-pAAr1wW1PwAGko,693
|
|
2
2
|
iam_validator/__main__.py,sha256=to_nz3n_IerJpVVZZ6WSFlFR5s_06J0csfPOTfQZG8g,197
|
|
3
|
-
iam_validator/__version__.py,sha256=
|
|
3
|
+
iam_validator/__version__.py,sha256=UMITyOhvLRTs5TZWk4U4b0IKHWjVN05qKIVWOKq-Gx8,374
|
|
4
4
|
iam_validator/checks/__init__.py,sha256=OTkPnmlelu4YjMO8krjhu2wXiTV72RzopA5u1SfPQA0,1990
|
|
5
5
|
iam_validator/checks/action_condition_enforcement.py,sha256=0dCH_xX-Xc0uLxtNeRjrpNjWYbdWQRzO1XNcLTSn6sI,51698
|
|
6
6
|
iam_validator/checks/action_resource_matching.py,sha256=WiGJmCIJfx5yituMjZxpKmk-99N6nK20ueN02ddy9oM,19296
|
|
@@ -20,7 +20,7 @@ iam_validator/checks/set_operator_validation.py,sha256=FyxZ7qWlp9-ABzZaRRkxRP_Hw
|
|
|
20
20
|
iam_validator/checks/sid_uniqueness.py,sha256=vfpk88b9G9OApxtrotABI2mPXvGd_C_X4gJKeqIURlk,5968
|
|
21
21
|
iam_validator/checks/trust_policy_validation.py,sha256=a8Sm2xu3gFOHLd7rXDl-ibqiLEmg5c-dyWv1lK2i6HA,17816
|
|
22
22
|
iam_validator/checks/wildcard_action.py,sha256=CyURgURDt2fQT2468LK813RupQ3WWvpmvLVLjUZf9QQ,1960
|
|
23
|
-
iam_validator/checks/wildcard_resource.py,sha256=
|
|
23
|
+
iam_validator/checks/wildcard_resource.py,sha256=lRNZN7f3ZQrvnbGdVDCefUQF8lESIMoXVfhIgpln3mM,6679
|
|
24
24
|
iam_validator/checks/utils/__init__.py,sha256=j0X4ibUB6RGx2a-kNoJnlVZwHfoEvzZsIeTmJIAoFzA,45
|
|
25
25
|
iam_validator/checks/utils/policy_level_checks.py,sha256=2V60C0zhKfsFPjQ-NMlD3EemtwA9S6-4no8nETgXdQE,5274
|
|
26
26
|
iam_validator/checks/utils/sensitive_action_matcher.py,sha256=qDXcJa_2sCJu9pBbjDlI7x5lPtLRc6jQCpKPMheCOJQ,11215
|
|
@@ -50,18 +50,18 @@ iam_validator/core/report.py,sha256=kzSeWnT1LqWZVA5pqKKz-maVowXVj0djdoShfRhhpz4,
|
|
|
50
50
|
iam_validator/core/aws_service/__init__.py,sha256=UqMh4HUdGlx2QF5OoueJJ2UlCnhX4QW_x3KeE_bxRQc,735
|
|
51
51
|
iam_validator/core/aws_service/cache.py,sha256=DPuOOPPJC867KAYgV1e0RyQs_k3mtefMdYli3jPaN64,3589
|
|
52
52
|
iam_validator/core/aws_service/client.py,sha256=Zv7rIpEFdUCDXKGp3migPDkj8L5eZltgrGe64M2t2Ko,7336
|
|
53
|
-
iam_validator/core/aws_service/fetcher.py,sha256=
|
|
53
|
+
iam_validator/core/aws_service/fetcher.py,sha256=s_o8h6ua9gPdiV9-ElNs7YY0HlyoP0Ewtl71hTrhsZA,23340
|
|
54
54
|
iam_validator/core/aws_service/parsers.py,sha256=gJzR7HCD8ItCWCCbguTQIZpPEdj2rdMwC7LPhu7ve14,5174
|
|
55
55
|
iam_validator/core/aws_service/patterns.py,sha256=gGc55Tn-EJ3cmcWtmYAZROUajKYz7DaMchYWGEhHpC0,1726
|
|
56
56
|
iam_validator/core/aws_service/storage.py,sha256=PrfKdvF60IL7E_8xYs_XwFoAJPRcVYw57FVLHCoqwVk,10429
|
|
57
|
-
iam_validator/core/aws_service/validators.py,sha256=
|
|
57
|
+
iam_validator/core/aws_service/validators.py,sha256=L9XRJdGmR-vZ1r0bj5SCznULyKEY_G1OAjij7-kOZPM,16463
|
|
58
58
|
iam_validator/core/config/__init__.py,sha256=CWSyIA7kEyzrskEenjYbs9Iih10BXRpiY9H2dHg61rU,2671
|
|
59
59
|
iam_validator/core/config/aws_api.py,sha256=HLIzOItQ0A37wxHcgWck6ZFO0wmNY8JNTiWMMK6JKYU,1248
|
|
60
60
|
iam_validator/core/config/aws_global_conditions.py,sha256=gdmMxXGBy95B3uYUG-J7rnM6Ixgc6L7Y9Pcd2XAMb60,7170
|
|
61
61
|
iam_validator/core/config/category_suggestions.py,sha256=QlrYi4BTkxDSTlL7NZGE9BWN-atWetZ6XjkI9F_7YzI,4370
|
|
62
62
|
iam_validator/core/config/condition_requirements.py,sha256=qauIP73HFnOw1dchUeFpg1x7Y7QWkILo3GfxV_dxdQo,7696
|
|
63
63
|
iam_validator/core/config/config_loader.py,sha256=qKD8aR8YAswaFf68pnYJLFNwKznvcc6lNxSQWU3i6SY,17713
|
|
64
|
-
iam_validator/core/config/defaults.py,sha256=
|
|
64
|
+
iam_validator/core/config/defaults.py,sha256=bI0MC3x7q6TVDxJxFs0MeyVRMmANGyfOOdvOWQQAuKc,30103
|
|
65
65
|
iam_validator/core/config/principal_requirements.py,sha256=VCX7fBDgeDTJQyoz7_x7GI7Kf9O1Eu-sbihoHOrKv6o,15105
|
|
66
66
|
iam_validator/core/config/sensitive_actions.py,sha256=uATDIp_TD3OQQlsYTZp79qd1mSK2Bf9hJ0JwcqLBr84,25344
|
|
67
67
|
iam_validator/core/config/service_principals.py,sha256=8pys5H_yycVJ9KTyimAKFYBg83Aol2Iri53wiHjtnEM,3959
|
|
@@ -83,14 +83,14 @@ iam_validator/sdk/arn_matching.py,sha256=HSDpLltOYISq-SoPebAlM89mKOaUaghq_04urch
|
|
|
83
83
|
iam_validator/sdk/context.py,sha256=FvAEyUa_s7tHWoSdgjSkzHf1CLlYpAEmLZANxs2IJ4A,6826
|
|
84
84
|
iam_validator/sdk/exceptions.py,sha256=tm91TxIwU157U_UHN7w5qICf_OhU11agj6pV5W_YP-4,1023
|
|
85
85
|
iam_validator/sdk/helpers.py,sha256=sjfK0na_Fo7O8GhEVhl44rVHqOdw6nAKkBL4FVL-QdU,5697
|
|
86
|
-
iam_validator/sdk/policy_utils.py,sha256=
|
|
86
|
+
iam_validator/sdk/policy_utils.py,sha256=bGdJ1X1aC72dVXXpAnAwyBpAiiX-qXvblpetY5BsjKU,13658
|
|
87
87
|
iam_validator/sdk/shortcuts.py,sha256=EVNSYV7rv4TFH03ulsZ3mS1UVmTSp2jKpc2AXs4j1q4,8531
|
|
88
88
|
iam_validator/utils/__init__.py,sha256=NveA2F3G1E6-ANZzFr7J6Q6u5mogvMp862iFokmYuCs,1021
|
|
89
89
|
iam_validator/utils/cache.py,sha256=wOQKOBeoG6QqC5f0oXcHz63Cjtu_-SsSS-0pTSwyAiM,3254
|
|
90
90
|
iam_validator/utils/regex.py,sha256=xHoMECttb7qaMhts-c9b0GIxdhHNZTt-UBr7wNhWfzg,6219
|
|
91
91
|
iam_validator/utils/terminal.py,sha256=FsRaRMH_JAyDgXWBCOgOEhbS89cs17HCmKYoughq5io,724
|
|
92
|
-
iam_policy_validator-1.10.
|
|
93
|
-
iam_policy_validator-1.10.
|
|
94
|
-
iam_policy_validator-1.10.
|
|
95
|
-
iam_policy_validator-1.10.
|
|
96
|
-
iam_policy_validator-1.10.
|
|
92
|
+
iam_policy_validator-1.10.3.dist-info/METADATA,sha256=TNwd0AdEvphwtPx0E8AoHsNNyYzTcl6QUDT6dRqqyEE,19070
|
|
93
|
+
iam_policy_validator-1.10.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
94
|
+
iam_policy_validator-1.10.3.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
|
|
95
|
+
iam_policy_validator-1.10.3.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
|
|
96
|
+
iam_policy_validator-1.10.3.dist-info/RECORD,,
|
iam_validator/__version__.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This file is the single source of truth for the package version.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
__version__ = "1.10.
|
|
6
|
+
__version__ = "1.10.3"
|
|
7
7
|
# Parse version, handling pre-release suffixes like -rc, -alpha, -beta
|
|
8
|
-
_version_base = __version__.split("-")[0] # Remove pre-release suffix if present
|
|
8
|
+
_version_base = __version__.split("-", maxsplit=1)[0] # Remove pre-release suffix if present
|
|
9
9
|
__version_info__ = tuple(int(part) for part in _version_base.split("."))
|
|
@@ -39,22 +39,44 @@ class WildcardResourceCheck(PolicyCheck):
|
|
|
39
39
|
# to all matching AWS actions using the AWS API, then checking if the policy's
|
|
40
40
|
# actions are in that expanded list. This ensures only validated AWS actions
|
|
41
41
|
# are allowed with Resource: "*".
|
|
42
|
+
allowed_wildcards_config = config.config.get("allowed_wildcards", [])
|
|
42
43
|
allowed_wildcards_expanded = await self._get_expanded_allowed_wildcards(config, fetcher)
|
|
43
44
|
|
|
44
45
|
# Check if ALL actions (excluding full wildcard "*") are in the expanded list
|
|
45
46
|
non_wildcard_actions = [a for a in actions if a != "*"]
|
|
46
47
|
|
|
47
|
-
if allowed_wildcards_expanded and non_wildcard_actions:
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
if (allowed_wildcards_config or allowed_wildcards_expanded) and non_wildcard_actions:
|
|
49
|
+
# Strategy 1: Check literal pattern match (fast path)
|
|
50
|
+
# If policy action matches config pattern literally, allow it
|
|
51
|
+
# Example: Policy has "iam:Get*", config has "iam:Get*" -> match
|
|
52
|
+
all_actions_allowed_literal = all(
|
|
53
|
+
action in allowed_wildcards_config for action in non_wildcard_actions
|
|
51
54
|
)
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
# All actions are safe, Resource: "*" is acceptable
|
|
56
|
+
if all_actions_allowed_literal:
|
|
57
|
+
# All actions match literally, Resource: "*" is acceptable
|
|
56
58
|
return issues
|
|
57
59
|
|
|
60
|
+
# Strategy 2: Check expanded pattern match (comprehensive path)
|
|
61
|
+
# Expand both policy actions and config patterns, then compare
|
|
62
|
+
# Example: Policy has "iam:Get*" -> ["iam:GetUser", ...],
|
|
63
|
+
# config has "iam:Get*" -> ["iam:GetUser", ...] -> all match
|
|
64
|
+
if allowed_wildcards_expanded:
|
|
65
|
+
expanded_statement_actions = await expand_wildcard_actions(
|
|
66
|
+
non_wildcard_actions, fetcher
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Check if all expanded actions are in the expanded allowed list (exact match)
|
|
70
|
+
all_actions_allowed_expanded = all(
|
|
71
|
+
action in allowed_wildcards_expanded
|
|
72
|
+
for action in expanded_statement_actions
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# If all actions are in the expanded list, skip the wildcard resource warning
|
|
76
|
+
if all_actions_allowed_expanded:
|
|
77
|
+
# All actions are safe, Resource: "*" is acceptable
|
|
78
|
+
return issues
|
|
79
|
+
|
|
58
80
|
# Flag the issue if actions are not all allowed or no allowed_wildcards configured
|
|
59
81
|
message = config.config.get(
|
|
60
82
|
"message", 'Statement applies to all resources `"*"` (wildcard resource).'
|
|
@@ -233,8 +233,16 @@ class AWSServiceFetcher:
|
|
|
233
233
|
await self._cache.set(services_cache_key, loaded_services)
|
|
234
234
|
return loaded_services
|
|
235
235
|
|
|
236
|
-
# Not in parsed cache,
|
|
237
|
-
data = await self.
|
|
236
|
+
# Not in parsed cache, check disk cache then fetch from API
|
|
237
|
+
data = await self._cache.get(
|
|
238
|
+
f"raw:{self.BASE_URL}", url=self.BASE_URL, base_url=self.BASE_URL
|
|
239
|
+
)
|
|
240
|
+
if data is None:
|
|
241
|
+
data = await self._client.fetch(self.BASE_URL)
|
|
242
|
+
# Cache the raw data
|
|
243
|
+
await self._cache.set(
|
|
244
|
+
f"raw:{self.BASE_URL}", data, url=self.BASE_URL, base_url=self.BASE_URL
|
|
245
|
+
)
|
|
238
246
|
|
|
239
247
|
if not isinstance(data, list):
|
|
240
248
|
raise ValueError("Expected list of services from root endpoint")
|
|
@@ -247,7 +255,7 @@ class AWSServiceFetcher:
|
|
|
247
255
|
if service and url:
|
|
248
256
|
services.append(ServiceInfo(service=str(service), url=str(url)))
|
|
249
257
|
|
|
250
|
-
# Cache the parsed services list (memory only
|
|
258
|
+
# Cache the parsed services list (memory only)
|
|
251
259
|
await self._cache.set(services_cache_key, services)
|
|
252
260
|
|
|
253
261
|
# Log only on first fetch (when parsed cache was empty)
|
|
@@ -312,13 +320,22 @@ class AWSServiceFetcher:
|
|
|
312
320
|
|
|
313
321
|
for service in services:
|
|
314
322
|
if service.service.lower() == service_name_lower:
|
|
315
|
-
#
|
|
316
|
-
data = await self.
|
|
323
|
+
# Check disk cache first, then fetch from API
|
|
324
|
+
data = await self._cache.get(
|
|
325
|
+
f"raw:{service.url}", url=service.url, base_url=self.BASE_URL
|
|
326
|
+
)
|
|
327
|
+
if data is None:
|
|
328
|
+
# Fetch service detail from API
|
|
329
|
+
data = await self._client.fetch(service.url)
|
|
330
|
+
# Cache the raw data
|
|
331
|
+
await self._cache.set(
|
|
332
|
+
f"raw:{service.url}", data, url=service.url, base_url=self.BASE_URL
|
|
333
|
+
)
|
|
317
334
|
|
|
318
335
|
# Validate and parse
|
|
319
336
|
service_detail = ServiceDetail.model_validate(data)
|
|
320
337
|
|
|
321
|
-
# Cache with service name as key (memory only
|
|
338
|
+
# Cache with service name as key (memory only)
|
|
322
339
|
await self._cache.set(cache_key, service_detail)
|
|
323
340
|
|
|
324
341
|
return service_detail
|
|
@@ -550,7 +567,7 @@ class AWSServiceFetcher:
|
|
|
550
567
|
if action_pattern in ("*", "*:*"):
|
|
551
568
|
return ["*"]
|
|
552
569
|
|
|
553
|
-
service_prefix,
|
|
570
|
+
service_prefix, _ = self._parser.parse_action(action_pattern)
|
|
554
571
|
service_detail = await self.fetch_service_by_name(service_prefix)
|
|
555
572
|
available = list(service_detail.actions.keys())
|
|
556
573
|
return self._parser.expand_wildcard_to_actions(action_pattern, available, service_prefix)
|
|
@@ -94,9 +94,7 @@ class ServiceValidator:
|
|
|
94
94
|
if not allow_wildcards:
|
|
95
95
|
return False, "Wildcard actions are not allowed", True
|
|
96
96
|
|
|
97
|
-
has_matches,
|
|
98
|
-
action_name, available_actions
|
|
99
|
-
)
|
|
97
|
+
has_matches, _ = self._parser.match_wildcard_action(action_name, available_actions)
|
|
100
98
|
|
|
101
99
|
if has_matches:
|
|
102
100
|
# Wildcard is valid and matches at least one action
|
|
@@ -161,7 +159,7 @@ class ServiceValidator:
|
|
|
161
159
|
get_global_conditions,
|
|
162
160
|
)
|
|
163
161
|
|
|
164
|
-
|
|
162
|
+
_, action_name = self._parser.parse_action(action)
|
|
165
163
|
|
|
166
164
|
# Check if it's a global condition key
|
|
167
165
|
is_global_key = False
|
|
@@ -323,7 +321,7 @@ class ServiceValidator:
|
|
|
323
321
|
>>> resources = validator.get_resources_for_action("s3:GetObject", service)
|
|
324
322
|
"""
|
|
325
323
|
try:
|
|
326
|
-
_, action_name = self._parser.parse_action(action)
|
|
324
|
+
_, action_name = self._parser.parse_action(action) # pylint: disable=unused-variable
|
|
327
325
|
|
|
328
326
|
# Find the action (case-insensitive)
|
|
329
327
|
action_detail = service_detail.actions.get(action_name)
|
|
@@ -344,13 +344,41 @@ DEFAULT_CONFIG = {
|
|
|
344
344
|
# Check for wildcard resources (Resource: "*")
|
|
345
345
|
# Flags statements that apply to all resources
|
|
346
346
|
# Exception: Allowed if ALL actions are in allowed_wildcards list
|
|
347
|
+
#
|
|
348
|
+
# DUAL MATCHING STRATEGY:
|
|
349
|
+
# The check uses two complementary matching strategies for maximum flexibility:
|
|
350
|
+
#
|
|
351
|
+
# 1. LITERAL MATCH (Fast Path - no AWS API calls):
|
|
352
|
+
# Policy actions match config patterns exactly as strings
|
|
353
|
+
# Example: Policy "iam:Get*" matches config "iam:Get*" → PASS
|
|
354
|
+
#
|
|
355
|
+
# 2. EXPANDED MATCH (Comprehensive Path - uses AWS API):
|
|
356
|
+
# Both policy actions and config patterns expand to actual AWS actions
|
|
357
|
+
# Example: Policy "iam:GetUser" matches config "iam:Get*" (expanded) → PASS
|
|
358
|
+
#
|
|
359
|
+
# SUPPORTED SCENARIOS:
|
|
360
|
+
# Policy Action Config Pattern Match Type Result
|
|
361
|
+
# iam:Get* iam:Get* Literal ✅ Pass
|
|
362
|
+
# iam:GetUser iam:Get* Expanded ✅ Pass
|
|
363
|
+
# iam:Get*, iam:List* iam:Get*, iam:List* Literal ✅ Pass
|
|
364
|
+
# iam:Get*, iam:GetUser iam:Get* Literal ✅ Pass
|
|
365
|
+
# iam:Delete* iam:Get* None ❌ Fail
|
|
366
|
+
#
|
|
367
|
+
# PERFORMANCE TIP: Literal matching is faster (no AWS API expansion)
|
|
347
368
|
"wildcard_resource": {
|
|
348
369
|
"enabled": True,
|
|
349
370
|
"severity": "medium", # Security issue
|
|
350
371
|
"description": "Checks for wildcard resources (*)",
|
|
351
372
|
# Allowed wildcard patterns for actions that can be used with Resource: "*"
|
|
373
|
+
# Supports BOTH literal matching and pattern expansion via AWS API
|
|
374
|
+
#
|
|
352
375
|
# Default: 25 read-only patterns (Describe*, List*, Get*)
|
|
353
376
|
# See: iam_validator/core/config/wildcards.py
|
|
377
|
+
#
|
|
378
|
+
# Examples:
|
|
379
|
+
# ["ec2:Describe*"] # Matches: ec2:Describe* (literal) OR ec2:DescribeInstances (expanded)
|
|
380
|
+
# ["iam:GetUser"] # Matches: iam:GetUser only
|
|
381
|
+
# ["s3:List*"] # Matches: s3:List* (literal) OR s3:ListBucket (expanded)
|
|
354
382
|
"allowed_wildcards": list(DEFAULT_ALLOWED_WILDCARDS),
|
|
355
383
|
"message": "Statement applies to all resources (*)",
|
|
356
384
|
"suggestion": "Replace wildcard with specific resource ARNs",
|
|
@@ -199,7 +199,7 @@ def extract_condition_keys(policy: IAMPolicy) -> list[str]:
|
|
|
199
199
|
for stmt in policy.statement:
|
|
200
200
|
if stmt.condition:
|
|
201
201
|
# Condition format: {"StringEquals": {"aws:username": "johndoe"}}
|
|
202
|
-
for
|
|
202
|
+
for _, key_values in stmt.condition.items():
|
|
203
203
|
if isinstance(key_values, dict):
|
|
204
204
|
condition_keys.update(key_values.keys())
|
|
205
205
|
|
|
@@ -225,7 +225,7 @@ def find_statements_with_action(policy: IAMPolicy, action: str) -> list[Statemen
|
|
|
225
225
|
>>> for stmt in stmts:
|
|
226
226
|
... print(f"Statement {stmt.sid} allows s3:GetObject")
|
|
227
227
|
"""
|
|
228
|
-
import fnmatch
|
|
228
|
+
import fnmatch # pylint: disable=import-outside-toplevel
|
|
229
229
|
|
|
230
230
|
matching_statements = []
|
|
231
231
|
|
|
@@ -262,7 +262,7 @@ def find_statements_with_resource(policy: IAMPolicy, resource: str) -> list[Stat
|
|
|
262
262
|
>>> stmts = find_statements_with_resource(policy, "arn:aws:s3:::my-bucket/*")
|
|
263
263
|
>>> print(f"Found {len(stmts)} statements with this resource")
|
|
264
264
|
"""
|
|
265
|
-
import fnmatch
|
|
265
|
+
import fnmatch # pylint: disable=import-outside-toplevel
|
|
266
266
|
|
|
267
267
|
matching_statements = []
|
|
268
268
|
|
|
File without changes
|
{iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{iam_policy_validator-1.10.1.dist-info → iam_policy_validator-1.10.3.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|