iam-policy-validator 1.14.3__py3-none-any.whl → 1.14.4__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.14.3.dist-info → iam_policy_validator-1.14.4.dist-info}/METADATA +1 -1
- {iam_policy_validator-1.14.3.dist-info → iam_policy_validator-1.14.4.dist-info}/RECORD +8 -8
- iam_validator/__version__.py +1 -1
- iam_validator/core/pr_commenter.py +58 -3
- iam_validator/core/report.py +117 -7
- {iam_policy_validator-1.14.3.dist-info → iam_policy_validator-1.14.4.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.14.3.dist-info → iam_policy_validator-1.14.4.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.14.3.dist-info → iam_policy_validator-1.14.4.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.14.
|
|
3
|
+
Version: 1.14.4
|
|
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=K_xnaUWCmwON5ETAsNuzottXYU-HSz_ojv0wjnlbS0U,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
|
|
@@ -53,8 +53,8 @@ iam_validator/core/label_manager.py,sha256=48CRASWg98wyjfVF_1pUzj6dm9itzmG7SeIWf
|
|
|
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=
|
|
57
|
-
iam_validator/core/report.py,sha256=
|
|
56
|
+
iam_validator/core/pr_commenter.py,sha256=F5ql60E-etGYOIDUSacvlhjsx5E-2hgGqhPbXmYfHqE,35021
|
|
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
|
|
60
60
|
iam_validator/core/aws_service/client.py,sha256=Zv7rIpEFdUCDXKGp3migPDkj8L5eZltgrGe64M2t2Ko,7336
|
|
@@ -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.
|
|
103
|
-
iam_policy_validator-1.14.
|
|
104
|
-
iam_policy_validator-1.14.
|
|
105
|
-
iam_policy_validator-1.14.
|
|
106
|
-
iam_policy_validator-1.14.
|
|
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,,
|
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.14.
|
|
6
|
+
__version__ = "1.14.4"
|
|
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("."))
|
|
@@ -17,7 +17,7 @@ from iam_validator.core.diff_parser import DiffParser
|
|
|
17
17
|
from iam_validator.core.label_manager import LabelManager
|
|
18
18
|
from iam_validator.core.models import ValidationIssue, ValidationReport
|
|
19
19
|
from iam_validator.core.policy_loader import PolicyLineMap, PolicyLoader
|
|
20
|
-
from iam_validator.core.report import ReportGenerator
|
|
20
|
+
from iam_validator.core.report import IgnoredFindingInfo, ReportGenerator
|
|
21
21
|
from iam_validator.integrations.github_integration import GitHubIntegration, ReviewEvent
|
|
22
22
|
|
|
23
23
|
logger = logging.getLogger(__name__)
|
|
@@ -96,6 +96,8 @@ class PRCommenter:
|
|
|
96
96
|
self._context_issues: list[ContextIssue] = []
|
|
97
97
|
# Track ignored finding IDs for the current run
|
|
98
98
|
self._ignored_finding_ids: frozenset[str] = frozenset()
|
|
99
|
+
# Store full ignored findings for display in summary
|
|
100
|
+
self._ignored_findings: dict[str, Any] = {}
|
|
99
101
|
# Cache for PolicyLineMap per file (for field-level line detection)
|
|
100
102
|
self._policy_line_maps: dict[str, PolicyLineMap] = {}
|
|
101
103
|
|
|
@@ -155,8 +157,28 @@ class PRCommenter:
|
|
|
155
157
|
generator = ReportGenerator()
|
|
156
158
|
# Pass ignored count to show in summary
|
|
157
159
|
ignored_count = len(self._ignored_finding_ids) if self._ignored_finding_ids else 0
|
|
160
|
+
|
|
161
|
+
# Convert ignored findings to IgnoredFindingInfo for display
|
|
162
|
+
ignored_findings_info: list[IgnoredFindingInfo] = []
|
|
163
|
+
if self._ignored_findings:
|
|
164
|
+
for finding in self._ignored_findings.values():
|
|
165
|
+
ignored_findings_info.append(
|
|
166
|
+
IgnoredFindingInfo(
|
|
167
|
+
file_path=finding.file_path,
|
|
168
|
+
issue_type=finding.issue_type,
|
|
169
|
+
ignored_by=finding.ignored_by,
|
|
170
|
+
reason=finding.reason,
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Determine if all blocking issues are ignored
|
|
175
|
+
all_blocking_ignored = self._are_all_blocking_issues_ignored(report)
|
|
176
|
+
|
|
158
177
|
comment_parts = generator.generate_github_comment_parts(
|
|
159
|
-
report,
|
|
178
|
+
report,
|
|
179
|
+
ignored_count=ignored_count,
|
|
180
|
+
ignored_findings=ignored_findings_info if ignored_findings_info else None,
|
|
181
|
+
all_blocking_ignored=all_blocking_ignored,
|
|
160
182
|
)
|
|
161
183
|
|
|
162
184
|
# Post all parts using the multipart method
|
|
@@ -694,7 +716,10 @@ class PRCommenter:
|
|
|
694
716
|
)
|
|
695
717
|
|
|
696
718
|
store = IgnoredFindingsStore(self.github)
|
|
697
|
-
|
|
719
|
+
# Load full ignored findings for display in summary
|
|
720
|
+
self._ignored_findings = await store.load()
|
|
721
|
+
# Also get just the IDs for fast lookup
|
|
722
|
+
self._ignored_finding_ids = frozenset(self._ignored_findings.keys())
|
|
698
723
|
if self._ignored_finding_ids:
|
|
699
724
|
logger.debug(f"Loaded {len(self._ignored_finding_ids)} ignored finding(s)")
|
|
700
725
|
|
|
@@ -718,6 +743,36 @@ class PRCommenter:
|
|
|
718
743
|
fingerprint = FindingFingerprint.from_issue(issue, file_path)
|
|
719
744
|
return fingerprint.to_hash() in self._ignored_finding_ids
|
|
720
745
|
|
|
746
|
+
def _are_all_blocking_issues_ignored(self, report: ValidationReport) -> bool:
|
|
747
|
+
"""Check if all blocking issues (based on fail_on_severities) are ignored.
|
|
748
|
+
|
|
749
|
+
Args:
|
|
750
|
+
report: The validation report
|
|
751
|
+
|
|
752
|
+
Returns:
|
|
753
|
+
True if there are no unignored blocking issues (i.e., all blocking
|
|
754
|
+
issues have been ignored, or there were no blocking issues to begin with)
|
|
755
|
+
"""
|
|
756
|
+
if not self._ignored_finding_ids:
|
|
757
|
+
# No ignored findings - check if there are any blocking issues at all
|
|
758
|
+
for result in report.results:
|
|
759
|
+
for issue in result.issues:
|
|
760
|
+
if issue.severity in self.fail_on_severities:
|
|
761
|
+
return False
|
|
762
|
+
return True
|
|
763
|
+
|
|
764
|
+
# Check each blocking issue to see if it's ignored
|
|
765
|
+
for result in report.results:
|
|
766
|
+
relative_path = self._make_relative_path(result.policy_file)
|
|
767
|
+
if not relative_path:
|
|
768
|
+
continue
|
|
769
|
+
for issue in result.issues:
|
|
770
|
+
if issue.severity in self.fail_on_severities:
|
|
771
|
+
if not self._is_issue_ignored(issue, relative_path):
|
|
772
|
+
return False
|
|
773
|
+
|
|
774
|
+
return True
|
|
775
|
+
|
|
721
776
|
|
|
722
777
|
async def post_report_to_pr(
|
|
723
778
|
report_file: str,
|
iam_validator/core/report.py
CHANGED
|
@@ -5,6 +5,7 @@ including console output, JSON, and GitHub-flavored markdown for PR comments.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
+
from dataclasses import dataclass
|
|
8
9
|
|
|
9
10
|
from rich.console import Console
|
|
10
11
|
from rich.panel import Panel
|
|
@@ -29,6 +30,24 @@ from iam_validator.core.models import (
|
|
|
29
30
|
ValidationReport,
|
|
30
31
|
)
|
|
31
32
|
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class IgnoredFindingInfo:
|
|
36
|
+
"""Information about an ignored finding for display in summary.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
file_path: Path to the policy file
|
|
40
|
+
issue_type: Type of issue (e.g., "invalid_action")
|
|
41
|
+
ignored_by: Username who ignored the finding
|
|
42
|
+
reason: Optional reason provided by the user
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
file_path: str
|
|
46
|
+
issue_type: str
|
|
47
|
+
ignored_by: str
|
|
48
|
+
reason: str | None = None
|
|
49
|
+
|
|
50
|
+
|
|
32
51
|
logger = logging.getLogger(__name__)
|
|
33
52
|
|
|
34
53
|
|
|
@@ -239,6 +258,8 @@ class ReportGenerator:
|
|
|
239
258
|
report: ValidationReport,
|
|
240
259
|
max_length_per_part: int = constants.GITHUB_COMMENT_SPLIT_LIMIT,
|
|
241
260
|
ignored_count: int = 0,
|
|
261
|
+
ignored_findings: list[IgnoredFindingInfo] | None = None,
|
|
262
|
+
all_blocking_ignored: bool = False,
|
|
242
263
|
) -> list[str]:
|
|
243
264
|
"""Generate GitHub PR comment(s), splitting into multiple parts if needed.
|
|
244
265
|
|
|
@@ -246,6 +267,8 @@ class ReportGenerator:
|
|
|
246
267
|
report: Validation report
|
|
247
268
|
max_length_per_part: Maximum character length per comment part (default from GITHUB_COMMENT_SPLIT_LIMIT)
|
|
248
269
|
ignored_count: Number of findings that were ignored (will be shown in summary)
|
|
270
|
+
ignored_findings: List of ignored finding details for display in summary
|
|
271
|
+
all_blocking_ignored: True if all blocking issues were ignored (shows "Passed" status)
|
|
249
272
|
|
|
250
273
|
Returns:
|
|
251
274
|
List of comment parts (each under max_length_per_part)
|
|
@@ -257,13 +280,19 @@ class ReportGenerator:
|
|
|
257
280
|
if estimated_size <= max_length_per_part:
|
|
258
281
|
# Try single comment
|
|
259
282
|
single_comment = self.generate_github_comment(
|
|
260
|
-
report,
|
|
283
|
+
report,
|
|
284
|
+
max_length=max_length_per_part * 2,
|
|
285
|
+
ignored_count=ignored_count,
|
|
286
|
+
ignored_findings=ignored_findings,
|
|
287
|
+
all_blocking_ignored=all_blocking_ignored,
|
|
261
288
|
)
|
|
262
289
|
if len(single_comment) <= max_length_per_part:
|
|
263
290
|
return [single_comment]
|
|
264
291
|
|
|
265
292
|
# Need to split into multiple parts
|
|
266
|
-
return self._generate_split_comments(
|
|
293
|
+
return self._generate_split_comments(
|
|
294
|
+
report, max_length_per_part, ignored_count, ignored_findings, all_blocking_ignored
|
|
295
|
+
)
|
|
267
296
|
|
|
268
297
|
def _estimate_report_size(self, report: ValidationReport) -> int:
|
|
269
298
|
"""Estimate the size of the report in characters.
|
|
@@ -280,7 +309,12 @@ class ReportGenerator:
|
|
|
280
309
|
)
|
|
281
310
|
|
|
282
311
|
def _generate_split_comments(
|
|
283
|
-
self,
|
|
312
|
+
self,
|
|
313
|
+
report: ValidationReport,
|
|
314
|
+
max_length: int,
|
|
315
|
+
ignored_count: int = 0,
|
|
316
|
+
ignored_findings: list[IgnoredFindingInfo] | None = None,
|
|
317
|
+
all_blocking_ignored: bool = False,
|
|
284
318
|
) -> list[str]:
|
|
285
319
|
"""Split a large report into multiple comment parts.
|
|
286
320
|
|
|
@@ -288,6 +322,8 @@ class ReportGenerator:
|
|
|
288
322
|
report: Validation report
|
|
289
323
|
max_length: Maximum length per part
|
|
290
324
|
ignored_count: Number of ignored findings to show in summary
|
|
325
|
+
ignored_findings: List of ignored finding details for display
|
|
326
|
+
all_blocking_ignored: True if all blocking issues were ignored
|
|
291
327
|
|
|
292
328
|
Returns:
|
|
293
329
|
List of comment parts
|
|
@@ -295,7 +331,9 @@ class ReportGenerator:
|
|
|
295
331
|
parts: list[str] = []
|
|
296
332
|
|
|
297
333
|
# Generate header (will be in first part only)
|
|
298
|
-
header_lines = self._generate_header(
|
|
334
|
+
header_lines = self._generate_header(
|
|
335
|
+
report, ignored_count, ignored_findings, all_blocking_ignored
|
|
336
|
+
)
|
|
299
337
|
header_content = "\n".join(header_lines)
|
|
300
338
|
|
|
301
339
|
# Generate footer (will be in all parts)
|
|
@@ -388,17 +426,27 @@ class ReportGenerator:
|
|
|
388
426
|
|
|
389
427
|
return parts
|
|
390
428
|
|
|
391
|
-
def _generate_header(
|
|
429
|
+
def _generate_header(
|
|
430
|
+
self,
|
|
431
|
+
report: ValidationReport,
|
|
432
|
+
ignored_count: int = 0,
|
|
433
|
+
ignored_findings: list[IgnoredFindingInfo] | None = None,
|
|
434
|
+
all_blocking_ignored: bool = False,
|
|
435
|
+
) -> list[str]:
|
|
392
436
|
"""Generate the comment header with summary.
|
|
393
437
|
|
|
394
438
|
Args:
|
|
395
439
|
report: Validation report
|
|
396
440
|
ignored_count: Number of findings that were ignored
|
|
441
|
+
ignored_findings: List of ignored finding details for display
|
|
442
|
+
all_blocking_ignored: True if all blocking issues were ignored (shows "Passed" status)
|
|
397
443
|
"""
|
|
398
444
|
lines = []
|
|
399
445
|
|
|
400
446
|
# Title with emoji and status badge
|
|
401
|
-
if
|
|
447
|
+
# Pass if: no invalid policies, OR all blocking issues were ignored
|
|
448
|
+
is_passing = report.invalid_policies == 0 or all_blocking_ignored
|
|
449
|
+
if is_passing:
|
|
402
450
|
lines.append("# 🎉 IAM Policy Validation Passed!")
|
|
403
451
|
status_badge = (
|
|
404
452
|
""
|
|
@@ -456,6 +504,56 @@ class ReportGenerator:
|
|
|
456
504
|
lines.append(f"| 🔵 **Info** | {infos} |")
|
|
457
505
|
lines.append("")
|
|
458
506
|
|
|
507
|
+
# Ignored findings section
|
|
508
|
+
if ignored_findings:
|
|
509
|
+
lines.extend(self._generate_ignored_findings_section(ignored_findings))
|
|
510
|
+
|
|
511
|
+
return lines
|
|
512
|
+
|
|
513
|
+
def _generate_ignored_findings_section(
|
|
514
|
+
self, ignored_findings: list[IgnoredFindingInfo]
|
|
515
|
+
) -> list[str]:
|
|
516
|
+
"""Generate the ignored findings section for the summary comment.
|
|
517
|
+
|
|
518
|
+
Args:
|
|
519
|
+
ignored_findings: List of ignored finding details
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
List of markdown lines for the section
|
|
523
|
+
"""
|
|
524
|
+
lines = []
|
|
525
|
+
lines.append("### 🔕 Ignored Findings")
|
|
526
|
+
lines.append("")
|
|
527
|
+
lines.append(
|
|
528
|
+
"> The following findings were ignored by authorized users and are excluded from validation:"
|
|
529
|
+
)
|
|
530
|
+
lines.append("")
|
|
531
|
+
|
|
532
|
+
lines.append("<details>")
|
|
533
|
+
lines.append(f"<summary>View {len(ignored_findings)} ignored finding(s)</summary>")
|
|
534
|
+
lines.append("")
|
|
535
|
+
|
|
536
|
+
lines.append("| File | Issue Type | Ignored By | Reason |")
|
|
537
|
+
lines.append("|------|------------|------------|--------|")
|
|
538
|
+
|
|
539
|
+
for finding in ignored_findings:
|
|
540
|
+
# Truncate file path if too long
|
|
541
|
+
file_display = finding.file_path
|
|
542
|
+
if len(file_display) > 50:
|
|
543
|
+
file_display = "..." + file_display[-47:]
|
|
544
|
+
|
|
545
|
+
reason_display = finding.reason if finding.reason else "-"
|
|
546
|
+
if len(reason_display) > 30:
|
|
547
|
+
reason_display = reason_display[:27] + "..."
|
|
548
|
+
|
|
549
|
+
lines.append(
|
|
550
|
+
f"| `{file_display}` | `{finding.issue_type}` | @{finding.ignored_by} | {reason_display} |"
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
lines.append("")
|
|
554
|
+
lines.append("</details>")
|
|
555
|
+
lines.append("")
|
|
556
|
+
|
|
459
557
|
return lines
|
|
460
558
|
|
|
461
559
|
def _generate_footer(self) -> str:
|
|
@@ -540,6 +638,8 @@ class ReportGenerator:
|
|
|
540
638
|
report: ValidationReport,
|
|
541
639
|
max_length: int = constants.GITHUB_MAX_COMMENT_LENGTH,
|
|
542
640
|
ignored_count: int = 0,
|
|
641
|
+
ignored_findings: list[IgnoredFindingInfo] | None = None,
|
|
642
|
+
all_blocking_ignored: bool = False,
|
|
543
643
|
) -> str:
|
|
544
644
|
"""Generate a GitHub-flavored markdown comment for PR reviews.
|
|
545
645
|
|
|
@@ -547,6 +647,8 @@ class ReportGenerator:
|
|
|
547
647
|
report: Validation report
|
|
548
648
|
max_length: Maximum character length (default from GITHUB_MAX_COMMENT_LENGTH constant)
|
|
549
649
|
ignored_count: Number of findings that were ignored (will be shown in summary)
|
|
650
|
+
ignored_findings: List of ignored finding details for display in summary
|
|
651
|
+
all_blocking_ignored: True if all blocking issues were ignored (shows "Passed" status)
|
|
550
652
|
|
|
551
653
|
Returns:
|
|
552
654
|
Markdown formatted string
|
|
@@ -554,8 +656,12 @@ class ReportGenerator:
|
|
|
554
656
|
lines = []
|
|
555
657
|
|
|
556
658
|
# Header with emoji and status badge
|
|
659
|
+
# Pass if: no invalid policies, OR all blocking issues were ignored
|
|
557
660
|
has_parsing_errors = len(report.parsing_errors) > 0
|
|
558
|
-
|
|
661
|
+
is_passing = (
|
|
662
|
+
report.invalid_policies == 0 or all_blocking_ignored
|
|
663
|
+
) and not has_parsing_errors
|
|
664
|
+
if is_passing:
|
|
559
665
|
lines.append("# 🎉 IAM Policy Validation Passed!")
|
|
560
666
|
status_badge = (
|
|
561
667
|
""
|
|
@@ -613,6 +719,10 @@ class ReportGenerator:
|
|
|
613
719
|
lines.append(f"| 🔵 **Info** | {infos} |")
|
|
614
720
|
lines.append("")
|
|
615
721
|
|
|
722
|
+
# Ignored findings section
|
|
723
|
+
if ignored_findings:
|
|
724
|
+
lines.extend(self._generate_ignored_findings_section(ignored_findings))
|
|
725
|
+
|
|
616
726
|
# Parsing errors section (if any)
|
|
617
727
|
if report.parsing_errors:
|
|
618
728
|
lines.append("### ⚠️ Parsing Errors")
|
|
File without changes
|
{iam_policy_validator-1.14.3.dist-info → iam_policy_validator-1.14.4.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{iam_policy_validator-1.14.3.dist-info → iam_policy_validator-1.14.4.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|