iam-policy-validator 1.14.5__py3-none-any.whl → 1.14.7__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.5.dist-info → iam_policy_validator-1.14.7.dist-info}/METADATA +19 -13
- {iam_policy_validator-1.14.5.dist-info → iam_policy_validator-1.14.7.dist-info}/RECORD +10 -10
- iam_validator/__version__.py +1 -1
- iam_validator/core/report.py +106 -28
- iam_validator/integrations/github_integration.py +1 -1
- iam_validator/sdk/__init__.py +62 -63
- iam_validator/sdk/context.py +3 -2
- {iam_policy_validator-1.14.5.dist-info → iam_policy_validator-1.14.7.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.14.5.dist-info → iam_policy_validator-1.14.7.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.14.5.dist-info → iam_policy_validator-1.14.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iam-policy-validator
|
|
3
|
-
Version: 1.14.
|
|
3
|
+
Version: 1.14.7
|
|
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
|
-
Project-URL: Documentation, https://github.
|
|
6
|
+
Project-URL: Documentation, https://boogy.github.io/iam-policy-validator
|
|
7
7
|
Project-URL: Repository, https://github.com/boogy/iam-policy-validator
|
|
8
8
|
Project-URL: Issues, https://github.com/boogy/iam-policy-validator/issues
|
|
9
|
-
Project-URL: Changelog, https://github.com/boogy/iam-policy-validator/blob/main/
|
|
9
|
+
Project-URL: Changelog, https://github.com/boogy/iam-policy-validator/blob/main/CHANGELOG.md
|
|
10
10
|
Author-email: boogy <0xboogy@gmail.com>
|
|
11
11
|
License: MIT
|
|
12
12
|
License-File: LICENSE
|
|
@@ -38,11 +38,17 @@ Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
|
38
38
|
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
39
39
|
Requires-Dist: types-boto3; extra == 'dev'
|
|
40
40
|
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
41
|
+
Provides-Extra: docs
|
|
42
|
+
Requires-Dist: mkdocs-gen-files>=0.5.0; extra == 'docs'
|
|
43
|
+
Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == 'docs'
|
|
44
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
45
|
+
Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
|
|
46
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
|
|
41
47
|
Description-Content-Type: text/markdown
|
|
42
48
|
|
|
43
49
|
# IAM Policy Validator
|
|
44
50
|
|
|
45
|
-
**
|
|
51
|
+
**Stop IAM misconfigurations before they become breaches** — Catch overprivileged permissions, dangerous wildcards, and policy errors before deployment.
|
|
46
52
|
|
|
47
53
|
[](https://github.com/marketplace/actions/iam-policy-validator)
|
|
48
54
|
[](https://www.python.org/downloads/)
|
|
@@ -120,7 +126,7 @@ iam-validator validate --path examples/quick-start/ --format enhanced
|
|
|
120
126
|
```
|
|
121
127
|
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
122
128
|
│ │
|
|
123
|
-
│ IAM Policy Validation Report (v1.
|
|
129
|
+
│ IAM Policy Validation Report (v1.14.1) │
|
|
124
130
|
│ │
|
|
125
131
|
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
126
132
|
───────────────────────────────────────── Detailed Results ─────────────────────────────────────────
|
|
@@ -294,7 +300,7 @@ sensitive_action:
|
|
|
294
300
|
message: "CloudFormation + PassRole enables infrastructure privilege escalation"
|
|
295
301
|
```
|
|
296
302
|
|
|
297
|
-
See [
|
|
303
|
+
See [Security Checks Documentation](docs/user-guide/checks/security-checks.md) for all built-in patterns and custom configuration.
|
|
298
304
|
|
|
299
305
|
**Comparison:**
|
|
300
306
|
|
|
@@ -635,7 +641,7 @@ sensitive_action:
|
|
|
635
641
|
|
|
636
642
|
For more details, see:
|
|
637
643
|
|
|
638
|
-
- [
|
|
644
|
+
- [Configuration Guide](docs/user-guide/configuration.md) - How to configure condition requirements
|
|
639
645
|
- [examples/configs/full-reference-config.yaml](examples/configs/full-reference-config.yaml) - Complete configuration reference
|
|
640
646
|
|
|
641
647
|
---
|
|
@@ -710,12 +716,12 @@ iam-validator analyze --path new-policy.json \
|
|
|
710
716
|
|
|
711
717
|
**Guides:**
|
|
712
718
|
|
|
713
|
-
- [Check Reference](docs/
|
|
714
|
-
- [Configuration Guide](docs/configuration.md) - Customize checks and behavior
|
|
715
|
-
- [GitHub Actions Guide](docs/github-actions
|
|
716
|
-
- [Python Library Guide](docs/
|
|
717
|
-
- [Trust Policy
|
|
718
|
-
- [
|
|
719
|
+
- [Check Reference](docs/user-guide/checks/) - All checks with examples
|
|
720
|
+
- [Configuration Guide](docs/user-guide/configuration.md) - Customize checks and behavior
|
|
721
|
+
- [GitHub Actions Guide](docs/integrations/github-actions.md) - CI/CD integration
|
|
722
|
+
- [Python Library Guide](docs/developer-guide/sdk/) - Use as Python package
|
|
723
|
+
- [Trust Policy Examples](examples/trust-policies/) - Trust policy validation examples
|
|
724
|
+
- [Changelog](CHANGELOG.md) - Version history and migration guides
|
|
719
725
|
|
|
720
726
|
**Examples:**
|
|
721
727
|
|
|
@@ -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=gzNFhw4Ir0RuOpe7hw6D6K-mQnE1zvBtL7jSlcAUnrE,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
|
|
@@ -54,7 +54,7 @@ iam_validator/core/models.py,sha256=lXUadIsTpp_j0Vt89Ez7aJkTKs2GD2ty3Ukl2NeY9Zo,
|
|
|
54
54
|
iam_validator/core/policy_checks.py,sha256=FNVuS2GTffwCjjrlupVIazC172gSxKYAAT_ObV6Apbo,8803
|
|
55
55
|
iam_validator/core/policy_loader.py,sha256=iid3mGfDzSXASzKDqbLnrqJHBdVQvvebofVqNImsGKM,29201
|
|
56
56
|
iam_validator/core/pr_commenter.py,sha256=IZu2FQqzw73U_8ugTUq197ECLqk9mRCQpTWXPu5qk0k,35490
|
|
57
|
-
iam_validator/core/report.py,sha256=
|
|
57
|
+
iam_validator/core/report.py,sha256=IDjBjSrzrE_JdkA8eTiSxyUL3g36sJMhTkxehEYzuBQ,45476
|
|
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
|
|
@@ -85,11 +85,11 @@ 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=
|
|
88
|
+
iam_validator/integrations/github_integration.py,sha256=0aeQ_RPTZf5ij7dsBjmtIDz4oHl0BXLno9GperFzTbc,69004
|
|
89
89
|
iam_validator/integrations/ms_teams.py,sha256=t2PlWuTDb6GGH-eDU1jnOKd8D1w4FCB68bahGA7MJcE,14475
|
|
90
|
-
iam_validator/sdk/__init__.py,sha256=
|
|
90
|
+
iam_validator/sdk/__init__.py,sha256=1voMXldzhLJ0mZ4AxwYPXwJd_kKFjQ-zp_tN8eWvkP4,6209
|
|
91
91
|
iam_validator/sdk/arn_matching.py,sha256=HSDpLltOYISq-SoPebAlM89mKOaUaghq_04urchEFDA,12778
|
|
92
|
-
iam_validator/sdk/context.py,sha256=
|
|
92
|
+
iam_validator/sdk/context.py,sha256=b2XXlvsnqxl42d1wsdoynTqsZOy8nRjV73RgxIdKdPQ,6940
|
|
93
93
|
iam_validator/sdk/exceptions.py,sha256=tm91TxIwU157U_UHN7w5qICf_OhU11agj6pV5W_YP-4,1023
|
|
94
94
|
iam_validator/sdk/helpers.py,sha256=sjfK0na_Fo7O8GhEVhl44rVHqOdw6nAKkBL4FVL-QdU,5697
|
|
95
95
|
iam_validator/sdk/policy_utils.py,sha256=bGdJ1X1aC72dVXXpAnAwyBpAiiX-qXvblpetY5BsjKU,13658
|
|
@@ -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.7.dist-info/METADATA,sha256=l4PstdoYzO1kqFBTI2M7UDbvoQMAcVC9sHamKl43x9Y,34741
|
|
103
|
+
iam_policy_validator-1.14.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
104
|
+
iam_policy_validator-1.14.7.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
|
|
105
|
+
iam_policy_validator-1.14.7.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
|
|
106
|
+
iam_policy_validator-1.14.7.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.7"
|
|
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("."))
|
iam_validator/core/report.py
CHANGED
|
@@ -478,13 +478,14 @@ class ReportGenerator:
|
|
|
478
478
|
|
|
479
479
|
# Issue breakdown
|
|
480
480
|
if report.total_issues > 0:
|
|
481
|
-
# Count issues -
|
|
482
|
-
|
|
483
|
-
1
|
|
484
|
-
for r in report.results
|
|
485
|
-
for i in r.issues
|
|
486
|
-
if i.severity in constants.HIGH_SEVERITY_LEVELS
|
|
481
|
+
# Count issues - separate validity errors from security findings
|
|
482
|
+
validity_errors = sum(
|
|
483
|
+
1 for r in report.results for i in r.issues if i.severity == "error"
|
|
487
484
|
)
|
|
485
|
+
critical_findings = sum(
|
|
486
|
+
1 for r in report.results for i in r.issues if i.severity == "critical"
|
|
487
|
+
)
|
|
488
|
+
high_findings = sum(1 for r in report.results for i in r.issues if i.severity == "high")
|
|
488
489
|
warnings = sum(
|
|
489
490
|
1 for r in report.results for i in r.issues if i.severity in ("warning", "medium")
|
|
490
491
|
)
|
|
@@ -496,8 +497,12 @@ class ReportGenerator:
|
|
|
496
497
|
lines.append("")
|
|
497
498
|
lines.append("| Severity | Count |")
|
|
498
499
|
lines.append("|----------|------:|")
|
|
499
|
-
if
|
|
500
|
-
lines.append(f"| 🔴 **Errors** | {
|
|
500
|
+
if validity_errors > 0:
|
|
501
|
+
lines.append(f"| 🔴 **Errors** | {validity_errors} |")
|
|
502
|
+
if critical_findings > 0:
|
|
503
|
+
lines.append(f"| 🟣 **Critical** | {critical_findings} |")
|
|
504
|
+
if high_findings > 0:
|
|
505
|
+
lines.append(f"| 🔶 **High** | {high_findings} |")
|
|
501
506
|
if warnings > 0:
|
|
502
507
|
lines.append(f"| 🟡 **Warnings** | {warnings} |")
|
|
503
508
|
if infos > 0:
|
|
@@ -578,15 +583,31 @@ class ReportGenerator:
|
|
|
578
583
|
)
|
|
579
584
|
lines.append("")
|
|
580
585
|
|
|
581
|
-
# Group issues by severity -
|
|
582
|
-
|
|
586
|
+
# Group issues by severity - separate validity errors from security findings
|
|
587
|
+
validity_errors = [i for i in result.issues if i.severity == "error"]
|
|
588
|
+
critical_findings = [i for i in result.issues if i.severity == "critical"]
|
|
589
|
+
high_findings = [i for i in result.issues if i.severity == "high"]
|
|
583
590
|
warnings = [i for i in result.issues if i.severity in constants.MEDIUM_SEVERITY_LEVELS]
|
|
584
591
|
infos = [i for i in result.issues if i.severity in constants.LOW_SEVERITY_LEVELS]
|
|
585
592
|
|
|
586
|
-
if
|
|
593
|
+
if validity_errors:
|
|
587
594
|
lines.append("### 🔴 Errors")
|
|
588
595
|
lines.append("")
|
|
589
|
-
for issue in
|
|
596
|
+
for issue in validity_errors:
|
|
597
|
+
lines.append(self._format_issue_markdown(issue, result.policy_file))
|
|
598
|
+
lines.append("")
|
|
599
|
+
|
|
600
|
+
if critical_findings:
|
|
601
|
+
lines.append("### 🟣 Critical")
|
|
602
|
+
lines.append("")
|
|
603
|
+
for issue in critical_findings:
|
|
604
|
+
lines.append(self._format_issue_markdown(issue, result.policy_file))
|
|
605
|
+
lines.append("")
|
|
606
|
+
|
|
607
|
+
if high_findings:
|
|
608
|
+
lines.append("### 🔶 High")
|
|
609
|
+
lines.append("")
|
|
610
|
+
for issue in high_findings:
|
|
590
611
|
lines.append(self._format_issue_markdown(issue, result.policy_file))
|
|
591
612
|
lines.append("")
|
|
592
613
|
|
|
@@ -693,13 +714,14 @@ class ReportGenerator:
|
|
|
693
714
|
|
|
694
715
|
# Issue breakdown
|
|
695
716
|
if report.total_issues > 0:
|
|
696
|
-
# Count issues -
|
|
697
|
-
|
|
698
|
-
1
|
|
699
|
-
for r in report.results
|
|
700
|
-
for i in r.issues
|
|
701
|
-
if i.severity in constants.HIGH_SEVERITY_LEVELS
|
|
717
|
+
# Count issues - separate validity errors from security findings
|
|
718
|
+
validity_errors = sum(
|
|
719
|
+
1 for r in report.results for i in r.issues if i.severity == "error"
|
|
702
720
|
)
|
|
721
|
+
critical_findings = sum(
|
|
722
|
+
1 for r in report.results for i in r.issues if i.severity == "critical"
|
|
723
|
+
)
|
|
724
|
+
high_findings = sum(1 for r in report.results for i in r.issues if i.severity == "high")
|
|
703
725
|
warnings = sum(
|
|
704
726
|
1 for r in report.results for i in r.issues if i.severity in ("warning", "medium")
|
|
705
727
|
)
|
|
@@ -711,8 +733,12 @@ class ReportGenerator:
|
|
|
711
733
|
lines.append("")
|
|
712
734
|
lines.append("| Severity | Count |")
|
|
713
735
|
lines.append("|----------|------:|")
|
|
714
|
-
if
|
|
715
|
-
lines.append(f"| 🔴 **Errors** | {
|
|
736
|
+
if validity_errors > 0:
|
|
737
|
+
lines.append(f"| 🔴 **Errors** | {validity_errors} |")
|
|
738
|
+
if critical_findings > 0:
|
|
739
|
+
lines.append(f"| 🟣 **Critical** | {critical_findings} |")
|
|
740
|
+
if high_findings > 0:
|
|
741
|
+
lines.append(f"| 🔶 **High** | {high_findings} |")
|
|
716
742
|
if warnings > 0:
|
|
717
743
|
lines.append(f"| 🟡 **Warnings** | {warnings} |")
|
|
718
744
|
if infos > 0:
|
|
@@ -789,15 +815,21 @@ class ReportGenerator:
|
|
|
789
815
|
|
|
790
816
|
policy_lines = []
|
|
791
817
|
|
|
792
|
-
# Group issues by severity -
|
|
793
|
-
|
|
818
|
+
# Group issues by severity - separate validity errors from security findings
|
|
819
|
+
validity_errors = [i for i in result.issues if i.severity == "error"]
|
|
820
|
+
critical_findings = [i for i in result.issues if i.severity == "critical"]
|
|
821
|
+
high_findings = [i for i in result.issues if i.severity == "high"]
|
|
794
822
|
warnings = [i for i in result.issues if i.severity in ("warning", "medium")]
|
|
795
823
|
infos = [i for i in result.issues if i.severity in ("info", "low")]
|
|
796
824
|
|
|
797
825
|
# Build severity summary for header
|
|
798
826
|
severity_parts = []
|
|
799
|
-
if
|
|
800
|
-
severity_parts.append(f"🔴 {len(
|
|
827
|
+
if validity_errors:
|
|
828
|
+
severity_parts.append(f"🔴 {len(validity_errors)}")
|
|
829
|
+
if critical_findings:
|
|
830
|
+
severity_parts.append(f"🟣 {len(critical_findings)}")
|
|
831
|
+
if high_findings:
|
|
832
|
+
severity_parts.append(f"🔶 {len(high_findings)}")
|
|
801
833
|
if warnings:
|
|
802
834
|
severity_parts.append(f"🟡 {len(warnings)}")
|
|
803
835
|
if infos:
|
|
@@ -812,11 +844,57 @@ class ReportGenerator:
|
|
|
812
844
|
)
|
|
813
845
|
policy_lines.append("")
|
|
814
846
|
|
|
815
|
-
# Add errors (prioritized)
|
|
816
|
-
if
|
|
847
|
+
# Add validity errors (prioritized)
|
|
848
|
+
if validity_errors:
|
|
817
849
|
policy_lines.append("### 🔴 Errors")
|
|
818
850
|
policy_lines.append("")
|
|
819
|
-
for i, issue in enumerate(
|
|
851
|
+
for i, issue in enumerate(validity_errors):
|
|
852
|
+
issue_content = self._format_issue_markdown(issue, result.policy_file)
|
|
853
|
+
test_length = len("\n".join(details_lines + policy_lines)) + len(
|
|
854
|
+
issue_content
|
|
855
|
+
)
|
|
856
|
+
if test_length > available_length:
|
|
857
|
+
truncated = True
|
|
858
|
+
break
|
|
859
|
+
policy_lines.append(issue_content)
|
|
860
|
+
issues_shown += 1
|
|
861
|
+
# Add separator between issues within same severity
|
|
862
|
+
if i < len(validity_errors) - 1:
|
|
863
|
+
policy_lines.append("---")
|
|
864
|
+
policy_lines.append("")
|
|
865
|
+
policy_lines.append("")
|
|
866
|
+
|
|
867
|
+
if truncated:
|
|
868
|
+
break
|
|
869
|
+
|
|
870
|
+
# Add critical security findings
|
|
871
|
+
if critical_findings:
|
|
872
|
+
policy_lines.append("### 🟣 Critical")
|
|
873
|
+
policy_lines.append("")
|
|
874
|
+
for i, issue in enumerate(critical_findings):
|
|
875
|
+
issue_content = self._format_issue_markdown(issue, result.policy_file)
|
|
876
|
+
test_length = len("\n".join(details_lines + policy_lines)) + len(
|
|
877
|
+
issue_content
|
|
878
|
+
)
|
|
879
|
+
if test_length > available_length:
|
|
880
|
+
truncated = True
|
|
881
|
+
break
|
|
882
|
+
policy_lines.append(issue_content)
|
|
883
|
+
issues_shown += 1
|
|
884
|
+
# Add separator between issues within same severity
|
|
885
|
+
if i < len(critical_findings) - 1:
|
|
886
|
+
policy_lines.append("---")
|
|
887
|
+
policy_lines.append("")
|
|
888
|
+
policy_lines.append("")
|
|
889
|
+
|
|
890
|
+
if truncated:
|
|
891
|
+
break
|
|
892
|
+
|
|
893
|
+
# Add high security findings
|
|
894
|
+
if high_findings:
|
|
895
|
+
policy_lines.append("### 🔶 High")
|
|
896
|
+
policy_lines.append("")
|
|
897
|
+
for i, issue in enumerate(high_findings):
|
|
820
898
|
issue_content = self._format_issue_markdown(issue, result.policy_file)
|
|
821
899
|
test_length = len("\n".join(details_lines + policy_lines)) + len(
|
|
822
900
|
issue_content
|
|
@@ -827,7 +905,7 @@ class ReportGenerator:
|
|
|
827
905
|
policy_lines.append(issue_content)
|
|
828
906
|
issues_shown += 1
|
|
829
907
|
# Add separator between issues within same severity
|
|
830
|
-
if i < len(
|
|
908
|
+
if i < len(high_findings) - 1:
|
|
831
909
|
policy_lines.append("---")
|
|
832
910
|
policy_lines.append("")
|
|
833
911
|
policy_lines.append("")
|
|
@@ -1278,7 +1278,7 @@ class GitHubIntegration:
|
|
|
1278
1278
|
logger.info(f"Submitting {event.value} review (no inline comments)")
|
|
1279
1279
|
success = await self.create_review_with_comments(
|
|
1280
1280
|
comments=[],
|
|
1281
|
-
body=body
|
|
1281
|
+
body=body,
|
|
1282
1282
|
event=event,
|
|
1283
1283
|
)
|
|
1284
1284
|
if not success:
|
iam_validator/sdk/__init__.py
CHANGED
|
@@ -1,66 +1,71 @@
|
|
|
1
|
-
"""
|
|
2
|
-
IAM Policy Validator SDK - Public API for library usage.
|
|
1
|
+
"""IAM Policy Validator SDK - Public API for library usage.
|
|
3
2
|
|
|
4
3
|
This module provides the complete public API for using IAM Policy Validator
|
|
5
4
|
as a Python library. It exposes both high-level convenience functions and
|
|
6
5
|
low-level components for custom integrations.
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
Basic validation
|
|
10
|
-
>>> from iam_validator.sdk import validate_file
|
|
11
|
-
>>> result = await validate_file("policy.json")
|
|
12
|
-
>>> print(f"Valid: {result.is_valid}")
|
|
13
|
-
|
|
14
|
-
With context manager:
|
|
15
|
-
>>> from iam_validator.sdk import validator
|
|
16
|
-
>>> async with validator() as v:
|
|
17
|
-
... result = await v.validate_file("policy.json")
|
|
18
|
-
... v.generate_report([result])
|
|
19
|
-
|
|
20
|
-
Policy manipulation:
|
|
21
|
-
>>> from iam_validator.sdk import parse_policy, get_policy_summary
|
|
22
|
-
>>> policy = parse_policy(policy_json)
|
|
23
|
-
>>> summary = get_policy_summary(policy)
|
|
24
|
-
>>> print(f"Actions: {summary['action_count']}")
|
|
25
|
-
|
|
26
|
-
Query AWS service definitions:
|
|
27
|
-
>>> from iam_validator.sdk import AWSServiceFetcher, query_actions, query_arn_formats
|
|
28
|
-
>>> async with AWSServiceFetcher() as fetcher:
|
|
29
|
-
... # Query all S3 write actions
|
|
30
|
-
... write_actions = await query_actions(fetcher, "s3", access_level="write")
|
|
31
|
-
... # Get ARN formats for S3
|
|
32
|
-
... arns = await query_arn_formats(fetcher, "s3")
|
|
33
|
-
|
|
34
|
-
Custom check development:
|
|
35
|
-
>>> from iam_validator.sdk import PolicyCheck, CheckHelper
|
|
36
|
-
>>> class MyCheck(PolicyCheck):
|
|
37
|
-
... @property
|
|
38
|
-
... def check_id(self) -> str:
|
|
39
|
-
... return "my_check"
|
|
40
|
-
... async def execute(self, statement, idx, fetcher, config):
|
|
41
|
-
... helper = CheckHelper(fetcher)
|
|
42
|
-
... # Use helper.arn_matches(), helper.create_issue(), etc.
|
|
43
|
-
... return []
|
|
44
|
-
"""
|
|
7
|
+
Example:
|
|
8
|
+
Basic validation::
|
|
45
9
|
|
|
46
|
-
|
|
47
|
-
# === AWS utilities ===
|
|
48
|
-
from iam_validator.core.aws_service import AWSServiceFetcher
|
|
10
|
+
from iam_validator.sdk import validate_file
|
|
49
11
|
|
|
50
|
-
|
|
51
|
-
|
|
12
|
+
result = await validate_file("policy.json")
|
|
13
|
+
print(f"Valid: {result.is_valid}")
|
|
14
|
+
|
|
15
|
+
With context manager::
|
|
16
|
+
|
|
17
|
+
from iam_validator.sdk import validator
|
|
18
|
+
|
|
19
|
+
async with validator() as v:
|
|
20
|
+
result = await v.validate_file("policy.json")
|
|
21
|
+
v.generate_report([result])
|
|
22
|
+
|
|
23
|
+
Policy manipulation::
|
|
24
|
+
|
|
25
|
+
from iam_validator.sdk import parse_policy, get_policy_summary
|
|
26
|
+
|
|
27
|
+
policy = parse_policy(policy_json)
|
|
28
|
+
summary = get_policy_summary(policy)
|
|
29
|
+
print(f"Actions: {summary['action_count']}")
|
|
30
|
+
|
|
31
|
+
Query AWS service definitions::
|
|
32
|
+
|
|
33
|
+
from iam_validator.sdk import AWSServiceFetcher, query_actions
|
|
34
|
+
|
|
35
|
+
async with AWSServiceFetcher() as fetcher:
|
|
36
|
+
# Query all S3 write actions
|
|
37
|
+
write_actions = await query_actions(fetcher, "s3", access_level="write")
|
|
38
|
+
|
|
39
|
+
Custom check development::
|
|
40
|
+
|
|
41
|
+
from iam_validator.sdk import PolicyCheck, CheckHelper
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
class MyCheck(PolicyCheck):
|
|
44
|
+
check_id = "my_check"
|
|
45
|
+
description = "My custom check"
|
|
46
|
+
default_severity = "medium"
|
|
55
47
|
|
|
56
|
-
|
|
48
|
+
async def execute(self, statement, idx, fetcher, config):
|
|
49
|
+
helper = CheckHelper(fetcher)
|
|
50
|
+
# Use helper.arn_matches(), helper.create_issue(), etc.
|
|
51
|
+
return []
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
# ruff: noqa: E402
|
|
55
|
+
# Imports are organized by category with comments, which triggers E402.
|
|
56
|
+
# This is intentional for readability in this public API module.
|
|
57
|
+
|
|
58
|
+
from iam_validator.core.aws_service import AWSServiceFetcher
|
|
59
|
+
from iam_validator.core.check_registry import CheckRegistry, PolicyCheck
|
|
60
|
+
from iam_validator.core.config.config_loader import (
|
|
61
|
+
ValidatorConfig,
|
|
62
|
+
load_validator_config,
|
|
63
|
+
)
|
|
57
64
|
from iam_validator.core.formatters.csv import CSVFormatter
|
|
58
65
|
from iam_validator.core.formatters.html import HTMLFormatter
|
|
59
66
|
from iam_validator.core.formatters.json import JSONFormatter
|
|
60
67
|
from iam_validator.core.formatters.markdown import MarkdownFormatter
|
|
61
68
|
from iam_validator.core.formatters.sarif import SARIFFormatter
|
|
62
|
-
|
|
63
|
-
# === Models (for type hints and inspection) ===
|
|
64
69
|
from iam_validator.core.models import (
|
|
65
70
|
IAMPolicy,
|
|
66
71
|
PolicyValidationResult,
|
|
@@ -70,23 +75,17 @@ from iam_validator.core.models import (
|
|
|
70
75
|
from iam_validator.core.policy_checks import validate_policies
|
|
71
76
|
from iam_validator.core.policy_loader import PolicyLoader
|
|
72
77
|
from iam_validator.core.report import ReportGenerator
|
|
73
|
-
|
|
74
|
-
# === ARN matching utilities ===
|
|
75
78
|
from iam_validator.sdk.arn_matching import (
|
|
76
79
|
arn_matches,
|
|
77
80
|
arn_strictly_valid,
|
|
78
81
|
convert_aws_pattern_to_wildcard,
|
|
79
82
|
is_glob_match,
|
|
80
83
|
)
|
|
81
|
-
|
|
82
|
-
# === Context managers ===
|
|
83
84
|
from iam_validator.sdk.context import (
|
|
84
85
|
ValidationContext,
|
|
85
86
|
validator,
|
|
86
87
|
validator_from_config,
|
|
87
88
|
)
|
|
88
|
-
|
|
89
|
-
# === Public exceptions ===
|
|
90
89
|
from iam_validator.sdk.exceptions import (
|
|
91
90
|
AWSServiceError,
|
|
92
91
|
ConfigurationError,
|
|
@@ -96,11 +95,7 @@ from iam_validator.sdk.exceptions import (
|
|
|
96
95
|
PolicyValidationError,
|
|
97
96
|
UnsupportedPolicyTypeError,
|
|
98
97
|
)
|
|
99
|
-
|
|
100
|
-
# === Custom check development ===
|
|
101
98
|
from iam_validator.sdk.helpers import CheckHelper, expand_actions
|
|
102
|
-
|
|
103
|
-
# === Policy manipulation utilities ===
|
|
104
99
|
from iam_validator.sdk.policy_utils import (
|
|
105
100
|
extract_actions,
|
|
106
101
|
extract_condition_keys,
|
|
@@ -116,8 +111,6 @@ from iam_validator.sdk.policy_utils import (
|
|
|
116
111
|
policy_to_dict,
|
|
117
112
|
policy_to_json,
|
|
118
113
|
)
|
|
119
|
-
|
|
120
|
-
# === Query utilities (AWS service definition queries) ===
|
|
121
114
|
from iam_validator.sdk.query_utils import (
|
|
122
115
|
get_actions_by_access_level,
|
|
123
116
|
get_actions_supporting_condition,
|
|
@@ -139,6 +132,9 @@ from iam_validator.sdk.shortcuts import (
|
|
|
139
132
|
validate_json,
|
|
140
133
|
)
|
|
141
134
|
|
|
135
|
+
# Alias for convenience (matches documentation)
|
|
136
|
+
Config = ValidatorConfig
|
|
137
|
+
|
|
142
138
|
__all__ = [
|
|
143
139
|
# === High-level shortcuts ===
|
|
144
140
|
"validate_file",
|
|
@@ -203,6 +199,7 @@ __all__ = [
|
|
|
203
199
|
"Statement",
|
|
204
200
|
# === ValidatorConfiguration ===
|
|
205
201
|
"ValidatorConfig",
|
|
202
|
+
"Config", # Alias for ValidatorConfig
|
|
206
203
|
"load_validator_config",
|
|
207
204
|
# === AWS utilities ===
|
|
208
205
|
"AWSServiceFetcher",
|
|
@@ -214,7 +211,9 @@ __all__ = [
|
|
|
214
211
|
"AWSServiceError",
|
|
215
212
|
"InvalidPolicyFormatError",
|
|
216
213
|
"UnsupportedPolicyTypeError",
|
|
214
|
+
# Version
|
|
215
|
+
"__version__",
|
|
217
216
|
]
|
|
218
217
|
|
|
219
|
-
# SDK version
|
|
220
|
-
__version__
|
|
218
|
+
# SDK version (same as main package)
|
|
219
|
+
from iam_validator.__version__ import __version__
|
iam_validator/sdk/context.py
CHANGED
|
@@ -5,6 +5,7 @@ This module provides context managers that handle resource lifecycle
|
|
|
5
5
|
and make the validation API more convenient to use.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from collections.abc import AsyncIterator
|
|
8
9
|
from contextlib import asynccontextmanager
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
|
|
@@ -169,7 +170,7 @@ class ValidationContext:
|
|
|
169
170
|
@asynccontextmanager
|
|
170
171
|
async def validator(
|
|
171
172
|
config_path: str | None = None,
|
|
172
|
-
):
|
|
173
|
+
) -> AsyncIterator[ValidationContext]:
|
|
173
174
|
"""
|
|
174
175
|
Context manager that handles AWS fetcher lifecycle.
|
|
175
176
|
|
|
@@ -201,7 +202,7 @@ async def validator(
|
|
|
201
202
|
|
|
202
203
|
|
|
203
204
|
@asynccontextmanager
|
|
204
|
-
async def validator_from_config(config_path: str):
|
|
205
|
+
async def validator_from_config(config_path: str) -> AsyncIterator[ValidationContext]:
|
|
205
206
|
"""
|
|
206
207
|
Context manager that loads configuration and creates a validator.
|
|
207
208
|
|
|
File without changes
|
{iam_policy_validator-1.14.5.dist-info → iam_policy_validator-1.14.7.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{iam_policy_validator-1.14.5.dist-info → iam_policy_validator-1.14.7.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|