iam-policy-validator 1.14.4__py3-none-any.whl → 1.14.5__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.14.4
3
+ Version: 1.14.5
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=K_xnaUWCmwON5ETAsNuzottXYU-HSz_ojv0wjnlbS0U,374
3
+ iam_validator/__version__.py,sha256=8ouM89pP7JLVFY6dwrTsOuZeWcu_xuQ3YwT7-1g9xn8,374
4
4
  iam_validator/checks/__init__.py,sha256=OTkPnmlelu4YjMO8krjhu2wXiTV72RzopA5u1SfPQA0,1990
5
5
  iam_validator/checks/action_condition_enforcement.py,sha256=2-XUMbof9tQ7SHZNmAHMkR1DgbOIzY2eFWlp9S9dwLk,60625
6
6
  iam_validator/checks/action_resource_matching.py,sha256=qND0hfDgNoxFEdLWwrxOPVDfdj3k50nzedT2qF7nK7o,19428
@@ -49,11 +49,11 @@ iam_validator/core/finding_fingerprint.py,sha256=NJIlu8NhdenWbLS7ww8LyWFasJgpKWN
49
49
  iam_validator/core/ignore_patterns.py,sha256=pZqDJBtkbck-85QK5eFPM5ZOPEKs3McRh3avqiCT5z0,10398
50
50
  iam_validator/core/ignore_processor.py,sha256=zgWfS-4BU4c_W6VxUxHIHorMtB5XzB410wZ3bbzVgH8,10686
51
51
  iam_validator/core/ignored_findings.py,sha256=b4PySz46so1rGKNt4prg2dkysHPfTJP4wsHYorVn1FA,12756
52
- iam_validator/core/label_manager.py,sha256=48CRASWg98wyjfVF_1pUzj6dm9itzmG7SeIWf0TSUfc,7502
52
+ iam_validator/core/label_manager.py,sha256=qKQ60shsW8yJELkHgd9rXgzLW9oKErPd4hFTTQkHjbI,8776
53
53
  iam_validator/core/models.py,sha256=lXUadIsTpp_j0Vt89Ez7aJkTKs2GD2ty3Ukl2NeY9Zo,15680
54
54
  iam_validator/core/policy_checks.py,sha256=FNVuS2GTffwCjjrlupVIazC172gSxKYAAT_ObV6Apbo,8803
55
55
  iam_validator/core/policy_loader.py,sha256=iid3mGfDzSXASzKDqbLnrqJHBdVQvvebofVqNImsGKM,29201
56
- iam_validator/core/pr_commenter.py,sha256=F5ql60E-etGYOIDUSacvlhjsx5E-2hgGqhPbXmYfHqE,35021
56
+ iam_validator/core/pr_commenter.py,sha256=IZu2FQqzw73U_8ugTUq197ECLqk9mRCQpTWXPu5qk0k,35490
57
57
  iam_validator/core/report.py,sha256=IEHjNe6v_9nvcGA8_FNbXdG0AoV-yHVjiP1KQKnpEys,41376
58
58
  iam_validator/core/aws_service/__init__.py,sha256=UqMh4HUdGlx2QF5OoueJJ2UlCnhX4QW_x3KeE_bxRQc,735
59
59
  iam_validator/core/aws_service/cache.py,sha256=DPuOOPPJC867KAYgV1e0RyQs_k3mtefMdYli3jPaN64,3589
@@ -85,7 +85,7 @@ iam_validator/core/formatters/json.py,sha256=A7gZ8P32GEdbDvrSn6v56yQ4fOP_kyMaoFV
85
85
  iam_validator/core/formatters/markdown.py,sha256=dk4STeY-tOEZsVrlmolIEqZvWYP9JhRtygxxNA49DEE,2293
86
86
  iam_validator/core/formatters/sarif.py,sha256=03MHSyuZm9FlzaPeWg7wH-UTzzCDhSy6vMPrFpFNkS8,18884
87
87
  iam_validator/integrations/__init__.py,sha256=7Hlor_X9j0NZaEjFuSvoXAAuSKQ-zgY19Rk-Dz3JpKo,616
88
- iam_validator/integrations/github_integration.py,sha256=OZjVFkeEK0PYerqHFOuc0tFtTMmo78JhbqZgFduzq-8,67949
88
+ iam_validator/integrations/github_integration.py,sha256=IKhJW_v_lGZiuyPN_xWULzv2YBbaXHn8zBfaOdUm28g,69054
89
89
  iam_validator/integrations/ms_teams.py,sha256=t2PlWuTDb6GGH-eDU1jnOKd8D1w4FCB68bahGA7MJcE,14475
90
90
  iam_validator/sdk/__init__.py,sha256=AZLnfdn3A9AWb0pMhsbu3GAOAzt6rV7Fi3E3d9_3ZdI,6388
91
91
  iam_validator/sdk/arn_matching.py,sha256=HSDpLltOYISq-SoPebAlM89mKOaUaghq_04urchEFDA,12778
@@ -99,8 +99,8 @@ iam_validator/utils/__init__.py,sha256=NveA2F3G1E6-ANZzFr7J6Q6u5mogvMp862iFokmYu
99
99
  iam_validator/utils/cache.py,sha256=wOQKOBeoG6QqC5f0oXcHz63Cjtu_-SsSS-0pTSwyAiM,3254
100
100
  iam_validator/utils/regex.py,sha256=xHoMECttb7qaMhts-c9b0GIxdhHNZTt-UBr7wNhWfzg,6219
101
101
  iam_validator/utils/terminal.py,sha256=FsRaRMH_JAyDgXWBCOgOEhbS89cs17HCmKYoughq5io,724
102
- iam_policy_validator-1.14.4.dist-info/METADATA,sha256=YHZ8MSw6dCEyDQmQm5mdbRNcf75MT-zL3n13ipE-zOQ,34456
103
- iam_policy_validator-1.14.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
104
- iam_policy_validator-1.14.4.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
105
- iam_policy_validator-1.14.4.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
106
- iam_policy_validator-1.14.4.dist-info/RECORD,,
102
+ iam_policy_validator-1.14.5.dist-info/METADATA,sha256=h6M6__GqJW5fWPtV0cEDqZ4sK259K5ulz68Jgt6COQE,34456
103
+ iam_policy_validator-1.14.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
104
+ iam_policy_validator-1.14.5.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
105
+ iam_policy_validator-1.14.5.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
106
+ iam_policy_validator-1.14.5.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.14.4"
6
+ __version__ = "1.14.5"
7
7
  # Parse version, handling pre-release suffixes like -rc, -alpha, -beta
8
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("."))
@@ -6,10 +6,11 @@ When those severities are not found, it removes the labels if present.
6
6
  """
7
7
 
8
8
  import logging
9
+ from collections.abc import Callable
9
10
  from typing import TYPE_CHECKING
10
11
 
11
12
  if TYPE_CHECKING:
12
- from iam_validator.core.models import PolicyValidationResult, ValidationReport
13
+ from iam_validator.core.models import PolicyValidationResult, ValidationIssue, ValidationReport
13
14
  from iam_validator.integrations.github_integration import GitHubIntegration
14
15
 
15
16
  logger = logging.getLogger(__name__)
@@ -48,11 +49,17 @@ class LabelManager:
48
49
  """
49
50
  return bool(self.severity_labels) and self.github.is_configured()
50
51
 
51
- def _get_severities_in_results(self, results: list["PolicyValidationResult"]) -> set[str]:
52
+ def _get_severities_in_results(
53
+ self,
54
+ results: list["PolicyValidationResult"],
55
+ is_issue_ignored: Callable[["ValidationIssue", str], bool] | None = None,
56
+ ) -> set[str]:
52
57
  """Extract all severity levels found in validation results.
53
58
 
54
59
  Args:
55
60
  results: List of PolicyValidationResult objects
61
+ is_issue_ignored: Optional callback to check if an issue is ignored.
62
+ Takes (issue, file_path) and returns True if ignored.
56
63
 
57
64
  Returns:
58
65
  Set of severity levels found (e.g., {"error", "critical", "high"})
@@ -60,6 +67,9 @@ class LabelManager:
60
67
  severities = set()
61
68
  for result in results:
62
69
  for issue in result.issues:
70
+ # Skip ignored issues if a filter is provided
71
+ if is_issue_ignored and is_issue_ignored(issue, result.policy_file):
72
+ continue
63
73
  severities.add(issue.severity)
64
74
  return severities
65
75
 
@@ -113,17 +123,22 @@ class LabelManager:
113
123
  return labels_to_remove
114
124
 
115
125
  async def manage_labels_from_results(
116
- self, results: list["PolicyValidationResult"]
126
+ self,
127
+ results: list["PolicyValidationResult"],
128
+ is_issue_ignored: Callable[["ValidationIssue", str], bool] | None = None,
117
129
  ) -> tuple[bool, int, int]:
118
130
  """Manage PR labels based on validation results.
119
131
 
120
132
  This method will:
121
- 1. Determine which severity levels are present in the results
133
+ 1. Determine which severity levels are present in the results (excluding ignored issues)
122
134
  2. Add labels for severities that are found
123
135
  3. Remove labels for severities that are not found
124
136
 
125
137
  Args:
126
138
  results: List of PolicyValidationResult objects
139
+ is_issue_ignored: Optional callback to check if an issue is ignored.
140
+ Takes (issue, file_path) and returns True if ignored.
141
+ Ignored issues are excluded from label determination.
127
142
 
128
143
  Returns:
129
144
  Tuple of (success, labels_added, labels_removed)
@@ -132,8 +147,8 @@ class LabelManager:
132
147
  logger.debug("Label management not enabled (no severity_labels configured)")
133
148
  return (True, 0, 0)
134
149
 
135
- # Get all severities found in results
136
- found_severities = self._get_severities_in_results(results)
150
+ # Get all severities found in results (excluding ignored issues)
151
+ found_severities = self._get_severities_in_results(results, is_issue_ignored)
137
152
  logger.debug(f"Found severities in results: {found_severities}")
138
153
 
139
154
  # Determine which labels to apply/remove
@@ -182,7 +197,11 @@ class LabelManager:
182
197
 
183
198
  return (success, added_count, removed_count)
184
199
 
185
- async def manage_labels_from_report(self, report: "ValidationReport") -> tuple[bool, int, int]:
200
+ async def manage_labels_from_report(
201
+ self,
202
+ report: "ValidationReport",
203
+ is_issue_ignored: Callable[["ValidationIssue", str], bool] | None = None,
204
+ ) -> tuple[bool, int, int]:
186
205
  """Manage PR labels based on validation report.
187
206
 
188
207
  This is a convenience method that extracts results from the report
@@ -190,8 +209,11 @@ class LabelManager:
190
209
 
191
210
  Args:
192
211
  report: ValidationReport object
212
+ is_issue_ignored: Optional callback to check if an issue is ignored.
213
+ Takes (issue, file_path) and returns True if ignored.
214
+ Ignored issues are excluded from label determination.
193
215
 
194
216
  Returns:
195
217
  Tuple of (success, labels_added, labels_removed)
196
218
  """
197
- return await self.manage_labels_from_results(report.results)
219
+ return await self.manage_labels_from_results(report.results, is_issue_ignored)
@@ -196,7 +196,17 @@ class PRCommenter:
196
196
  # Manage PR labels based on severity findings
197
197
  if manage_labels and self.severity_labels:
198
198
  label_manager = LabelManager(self.github, self.severity_labels)
199
- label_success, added, removed = await label_manager.manage_labels_from_report(report)
199
+
200
+ # Create a filter function that uses relative paths for ignored finding lookup
201
+ def is_issue_ignored_for_labels(issue: ValidationIssue, file_path: str) -> bool:
202
+ relative_path = self._make_relative_path(file_path)
203
+ if not relative_path:
204
+ return False
205
+ return self._is_issue_ignored(issue, relative_path)
206
+
207
+ label_success, added, removed = await label_manager.manage_labels_from_report(
208
+ report, is_issue_ignored=is_issue_ignored_for_labels
209
+ )
200
210
 
201
211
  if not label_success:
202
212
  logger.error("Failed to manage PR labels")
@@ -1265,6 +1265,26 @@ class GitHubIntegration:
1265
1265
  f"{created_count} created, {deleted_count} deleted (resolved)"
1266
1266
  )
1267
1267
 
1268
+ # Step 4: If no new comments were created but we need to submit APPROVE/REQUEST_CHANGES,
1269
+ # submit a review without inline comments to update the PR review state.
1270
+ # This is important when all issues are ignored/resolved - we need to dismiss
1271
+ # the previous REQUEST_CHANGES review by submitting an APPROVE review.
1272
+ if not new_comments_for_review and event in (
1273
+ ReviewEvent.APPROVE,
1274
+ ReviewEvent.REQUEST_CHANGES,
1275
+ ):
1276
+ # Only submit if there's a meaningful state change to make
1277
+ # (submitting APPROVE when all issues are resolved/ignored)
1278
+ logger.info(f"Submitting {event.value} review (no inline comments)")
1279
+ success = await self.create_review_with_comments(
1280
+ comments=[],
1281
+ body=body or f"<!-- {identifier} -->\nValidation complete.",
1282
+ event=event,
1283
+ )
1284
+ if not success:
1285
+ logger.warning(f"Failed to submit {event.value} review")
1286
+ # Don't fail the whole operation - comments were managed successfully
1287
+
1268
1288
  return True
1269
1289
 
1270
1290
  def _extract_finding_id(self, body: str) -> str | None: