iam-policy-validator 1.10.1__py3-none-any.whl → 1.10.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iam-policy-validator
3
- Version: 1.10.1
3
+ Version: 1.10.2
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=SRRdMee5oIovcL25-xNSjSxoHM9bzGQhwmx_U4YhnXQ,362
3
+ iam_validator/__version__.py,sha256=Fz08JonmD1dXoibF83ZYkSo1e0IWJO9aJ4iIAfq64mI,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
@@ -50,11 +50,11 @@ 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=X4iI6fiLj4l9f3W6_J0E58lSP26UsBhE9gu2pzmx7Bw,22641
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=AY0BjydskXoesEzUShH4gZKp6gtSX7s1rCLP_iOZQMc,16493
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
@@ -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=Fh-QElhmPypzSJuF9rcrY7y46Gz3hQu3-yN5b1_mSHY,13579
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.1.dist-info/METADATA,sha256=lIMmE1Y6TX34sh3stfe9J2_q5ATb9fYZqVqOupYNcL8,19070
93
- iam_policy_validator-1.10.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- iam_policy_validator-1.10.1.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
95
- iam_policy_validator-1.10.1.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
96
- iam_policy_validator-1.10.1.dist-info/RECORD,,
92
+ iam_policy_validator-1.10.2.dist-info/METADATA,sha256=t5vzMawKVACC8uFWNJznjMBvw4xX9T7z1EduP8HbAQA,19070
93
+ iam_policy_validator-1.10.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ iam_policy_validator-1.10.2.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
95
+ iam_policy_validator-1.10.2.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
96
+ iam_policy_validator-1.10.2.dist-info/RECORD,,
@@ -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.1"
6
+ __version__ = "1.10.2"
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("."))
@@ -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, fetch the raw data from API
237
- data = await self._client.fetch(self.BASE_URL)
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 - raw JSON already cached by client)
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
- # Fetch service detail from API
316
- data = await self._client.fetch(service.url)
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 - raw JSON already cached by client)
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, action_name = self._parser.parse_action(action_pattern)
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, matched_actions = self._parser.match_wildcard_action(
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
- service_prefix, action_name = self._parser.parse_action(action)
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)
@@ -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 operator, key_values in stmt.condition.items():
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