iam-policy-validator 1.6.0__py3-none-any.whl → 1.7.1__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.
Files changed (33) hide show
  1. iam_policy_validator-1.7.1.dist-info/METADATA +429 -0
  2. {iam_policy_validator-1.6.0.dist-info → iam_policy_validator-1.7.1.dist-info}/RECORD +32 -31
  3. iam_validator/__version__.py +1 -1
  4. iam_validator/checks/action_condition_enforcement.py +3 -1
  5. iam_validator/checks/action_resource_matching.py +23 -6
  6. iam_validator/checks/full_wildcard.py +5 -1
  7. iam_validator/checks/policy_size.py +3 -7
  8. iam_validator/checks/policy_type_validation.py +9 -3
  9. iam_validator/checks/principal_validation.py +1 -1
  10. iam_validator/checks/resource_validation.py +54 -24
  11. iam_validator/checks/sensitive_action.py +5 -1
  12. iam_validator/checks/service_wildcard.py +3 -1
  13. iam_validator/checks/utils/sensitive_action_matcher.py +1 -2
  14. iam_validator/checks/utils/wildcard_expansion.py +1 -2
  15. iam_validator/checks/wildcard_action.py +7 -2
  16. iam_validator/checks/wildcard_resource.py +5 -1
  17. iam_validator/commands/analyze.py +98 -1
  18. iam_validator/commands/validate.py +4 -2
  19. iam_validator/core/access_analyzer.py +5 -0
  20. iam_validator/core/access_analyzer_report.py +2 -5
  21. iam_validator/core/aws_fetcher.py +14 -4
  22. iam_validator/core/config/config_loader.py +3 -6
  23. iam_validator/core/constants.py +74 -0
  24. iam_validator/core/models.py +29 -13
  25. iam_validator/core/pr_commenter.py +104 -18
  26. iam_validator/core/report.py +49 -36
  27. iam_validator/integrations/github_integration.py +21 -1
  28. iam_validator/sdk/arn_matching.py +108 -0
  29. iam_validator/utils/regex.py +7 -8
  30. iam_policy_validator-1.6.0.dist-info/METADATA +0 -1050
  31. {iam_policy_validator-1.6.0.dist-info → iam_policy_validator-1.7.1.dist-info}/WHEEL +0 -0
  32. {iam_policy_validator-1.6.0.dist-info → iam_policy_validator-1.7.1.dist-info}/entry_points.txt +0 -0
  33. {iam_policy_validator-1.6.0.dist-info → iam_policy_validator-1.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,429 @@
1
+ Metadata-Version: 2.4
2
+ Name: iam-policy-validator
3
+ Version: 1.7.1
4
+ Summary: Validate AWS IAM policies for correctness and security using AWS Service Reference API
5
+ Project-URL: Homepage, https://github.com/boogy/iam-policy-validator
6
+ Project-URL: Documentation, https://github.com/boogy/iam-policy-validator/tree/main/docs
7
+ Project-URL: Repository, https://github.com/boogy/iam-policy-validator
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/docs/CHANGELOG.md
10
+ Author-email: boogy <0xboogy@gmail.com>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: aws,github-action,iam,policy,security,validation
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: System Administrators
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Security
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: boto3>=1.28.0
27
+ Requires-Dist: botocore>=1.40.55
28
+ Requires-Dist: httpx[http2]>=0.27.0
29
+ Requires-Dist: pydantic>=2.0.0
30
+ Requires-Dist: pyyaml>=6.0
31
+ Requires-Dist: rich>=13.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
35
+ Requires-Dist: pytest-benchmark>=4.0.0; extra == 'dev'
36
+ Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
37
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
+ Requires-Dist: types-boto3; extra == 'dev'
40
+ Requires-Dist: types-pyyaml; extra == 'dev'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # IAM Policy Validator
44
+
45
+ > **⚡ Catch IAM policy security issues and errors before they reach production** - A comprehensive validation tool for AWS IAM policies with built-in security checks and optional AWS Access Analyzer integration.
46
+
47
+ [![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-Ready-blue)](https://github.com/marketplace/actions/iam-policy-validator)
48
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
49
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
50
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/boogy/iam-policy-validator/badge)](https://scorecard.dev/viewer/?uri=github.com/boogy/iam-policy-validator)
51
+
52
+ ## 🚀 Why IAM Policy Validator?
53
+
54
+ **IAM policy errors are costly and dangerous.** A single misconfigured policy can:
55
+ - ❌ Grant unintended admin access (privilege escalation)
56
+ - ❌ Expose sensitive data to the public
57
+ - ❌ Break production deployments with invalid syntax
58
+ - ❌ Create security vulnerabilities that persist for months
59
+
60
+ **This tool prevents these issues** by:
61
+ - ✅ **Dual validation** - built-in checks + optional AWS Access Analyzer
62
+ - ✅ **Catches real threats** - Privilege escalation, wildcards, missing conditions
63
+ - ✅ **PR integration** - Automated validation in GitHub Actions
64
+ - ✅ **Saves security team time** - Catches common issues before manual review
65
+ - ✅ **Developer-friendly** - Clear errors with fix suggestions
66
+ - ✅ **Zero setup** - Works as a GitHub Action out of the box
67
+
68
+ ## ✨ What Makes It Special
69
+
70
+ ### 🔍 Two Validation Layers
71
+
72
+ **1. Built-in Checks (No AWS Credentials Required)**
73
+ - **Security & Compliance Checks** - Works offline, no AWS account needed
74
+ - **Privilege Escalation Detection** - Detects dangerous IAM actions and configurable combination patterns
75
+ - **Wildcard Analysis** - Catches overly permissive wildcards (`*`, `s3:*`)
76
+ - **Sensitive Action Enforcement** - 490 actions requiring conditions (MFA, IP, tags)
77
+ - **AWS Requirements Validation** - Actions, conditions, ARN formats, policy size
78
+
79
+ **2. AWS Access Analyzer (Optional)**
80
+ - **Official AWS Validation** - Syntax, semantics, and security checks
81
+ - **Public Access Detection** - Checks 29+ resource types (S3, Lambda, SNS, etc.)
82
+ - **Policy Comparison** - Detect new permissions vs baseline
83
+ - **Cross-account Analysis** - Validates external access
84
+
85
+ ### 🎯 Developer Experience
86
+ - **Auto-detects IAM policies** - Scans mixed JSON/YAML repos automatically
87
+ - **PR comments & reviews** - Line-specific feedback in GitHub
88
+ - **7 output formats** - Console, JSON, Markdown, SARIF, CSV, HTML, Enhanced
89
+ - **Extensible** - Add custom checks via Python plugins
90
+
91
+ **📖 See [full feature documentation](docs/README.md) for details**
92
+
93
+ ## 📈 What It Catches
94
+
95
+ ### Example 1: Privilege Escalation (Built-in Check)
96
+ ```json
97
+ {
98
+ "Statement": [
99
+ {"Effect": "Allow", "Action": "iam:CreateUser", "Resource": "*"},
100
+ {"Effect": "Allow", "Action": "iam:AttachUserPolicy", "Resource": "*"}
101
+ ]
102
+ }
103
+ ```
104
+
105
+ **Detected:**
106
+ ```
107
+ 🚨 CRITICAL: Privilege escalation risk detected!
108
+ Actions ['iam:CreateUser', 'iam:AttachUserPolicy'] enable:
109
+ 1. Create new IAM user
110
+ 2. Attach AdministratorAccess to that user
111
+ 3. Gain full AWS account access
112
+ ```
113
+
114
+ ### Example 2: Overly Permissive Wildcards (Built-in Check)
115
+ ```json
116
+ {
117
+ "Effect": "Allow",
118
+ "Action": "s3:*",
119
+ "Resource": "*"
120
+ }
121
+ ```
122
+
123
+ **Detected:**
124
+ ```
125
+ ❌ HIGH: Service wildcard 's3:*' detected
126
+ ❌ MEDIUM: Wildcard resource '*' - applies to all S3 buckets
127
+ ❌ CRITICAL: Full wildcard (Action + Resource) grants excessive access
128
+ ```
129
+
130
+ ### Example 3: Missing Required Conditions (Built-in Check)
131
+ ```json
132
+ {
133
+ "Effect": "Allow",
134
+ "Action": "iam:PassRole",
135
+ "Resource": "*"
136
+ }
137
+ ```
138
+
139
+ **Detected:**
140
+ ```
141
+ ❌ HIGH: iam:PassRole missing required condition
142
+ 💡 Add condition: iam:PassedToService to restrict role passing
143
+ ```
144
+
145
+ ### Example 4: Public Access (Access Analyzer - Optional)
146
+ ```json
147
+ {
148
+ "Principal": "*",
149
+ "Action": "s3:GetObject",
150
+ "Resource": "arn:aws:s3:::private-bucket/*"
151
+ }
152
+ ```
153
+
154
+ **Detected:**
155
+ ```
156
+ 🛑 CRITICAL: Resource policy allows public internet access
157
+ Principal "*" grants world-readable access to S3 bucket
158
+ 💡 Use specific AWS principals or add aws:SourceIp conditions
159
+ ```
160
+
161
+ ## Quick Start
162
+
163
+ ### GitHub Action (Recommended)
164
+
165
+ Create `.github/workflows/iam-validator.yml`:
166
+
167
+ ```yaml
168
+ name: IAM Policy Validation
169
+
170
+ on:
171
+ pull_request:
172
+ paths: ['policies/**/*.json']
173
+
174
+ jobs:
175
+ validate:
176
+ runs-on: ubuntu-latest
177
+ permissions:
178
+ contents: read
179
+ pull-requests: write
180
+ steps:
181
+ - uses: actions/checkout@v5
182
+ - uses: boogy/iam-policy-validator@v1
183
+ with:
184
+ path: policies/
185
+ fail-on-warnings: true
186
+ ```
187
+
188
+ **With AWS Access Analyzer (optional):**
189
+ ```yaml
190
+ - uses: aws-actions/configure-aws-credentials@v4
191
+ with:
192
+ role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
193
+ aws-region: us-east-1
194
+ - uses: boogy/iam-policy-validator@v1
195
+ with:
196
+ path: policies/
197
+ use-access-analyzer: true
198
+ run-all-checks: true # Run both Access Analyzer + built-in checks
199
+ ```
200
+
201
+ **📖 For all GitHub Action inputs and advanced workflows, see [GitHub Actions Guide](docs/github-actions-workflows.md)**
202
+
203
+ ### CLI Tool
204
+
205
+ ```bash
206
+ # Install
207
+ pip install iam-policy-validator
208
+
209
+ # Validate (built-in checks only - no AWS credentials needed)
210
+ iam-validator validate --path ./policies/
211
+
212
+ # Validate with AWS Access Analyzer (requires AWS credentials)
213
+ iam-validator analyze --path ./policies/
214
+
215
+ # With both Access Analyzer + built-in checks
216
+ iam-validator analyze --path ./policies/ --run-all-checks
217
+
218
+ # Different policy types
219
+ iam-validator validate --path ./policies/ --policy-type RESOURCE_POLICY
220
+
221
+ # Output formats
222
+ iam-validator validate --path ./policies/ --format json --output report.json
223
+ ```
224
+
225
+ **📖 See [CLI documentation](docs/README.md) for all commands and options**
226
+
227
+ ### Python Library
228
+
229
+ ```python
230
+ from iam_validator.core.policy_loader import PolicyLoader
231
+ from iam_validator.core.policy_checks import validate_policies
232
+
233
+ # Load and validate
234
+ loader = PolicyLoader()
235
+ policies = loader.load_from_path("./policies")
236
+ results = await validate_policies(policies)
237
+ ```
238
+
239
+ **📖 See [Python Library Guide](docs/python-library-usage.md) for complete examples**
240
+
241
+ ## Built-in Validation Checks
242
+
243
+ **All checks are fully configurable** - Enable/disable checks, adjust severity levels, add custom requirements, and define ignore patterns through the configuration file.
244
+
245
+ ### AWS Correctness Checks (12)
246
+ Validates policies against AWS IAM requirements:
247
+ - **Action validation** - Verify actions exist in AWS services
248
+ - **Condition key validation** - Check condition keys are valid for actions
249
+ - **Condition type matching** - Ensure condition values match expected types
250
+ - **Resource ARN validation** - Validate ARN formats and patterns
251
+ - **Principal validation** - Check principal formats (resource policies)
252
+ - **Policy size limits** - Enforce AWS size constraints
253
+ - **SID uniqueness** - Ensure statement IDs are unique
254
+ - **Set operator validation** - Validate ForAllValues/ForAnyValue usage
255
+ - **MFA condition patterns** - Detect common MFA anti-patterns
256
+ - **Policy type validation** - Enforce policy type requirements (RCP, SCP, etc.)
257
+ - **Action-resource matching** - Detect impossible action-resource combinations
258
+ - **Action-resource constraints** - Validate service-specific constraints
259
+
260
+ ### Security Best Practices (6)
261
+ Identifies security risks and overly permissive permissions:
262
+ - **Wildcard action** (`Action: "*"`)
263
+ - **Wildcard resource** (`Resource: "*"`)
264
+ - **Full wildcard** (CRITICAL: both `Action: "*"` and `Resource: "*"`)
265
+ - **Service wildcards** (`s3:*`, `iam:*`, etc.)
266
+ - **Sensitive actions** - ~490 actions across 4 risk categories requiring conditions
267
+ - **Action condition enforcement** - Enforce required conditions (MFA, IP, SourceArn, etc.)
268
+
269
+ ### Configuration & Customization
270
+
271
+ All checks can be customized via a yaml configuration file ex: `.iam-validator.yaml`:
272
+
273
+ ```yaml
274
+ settings:
275
+ enable_builtin_checks: true
276
+ fail_on_severity: high
277
+
278
+ # Customize individual checks
279
+ wildcard_action:
280
+ enabled: true
281
+ severity: critical
282
+
283
+ # Detect privilege escalation patterns
284
+ sensitive_action:
285
+ enabled: true
286
+ severity: critical
287
+ sensitive_actions:
288
+ # all_of: Detects when ALL actions exist across the entire policy
289
+ # (checks multiple statements - finds scattered dangerous combinations)
290
+ - all_of:
291
+ - "iam:CreateUser"
292
+ - "iam:AttachUserPolicy"
293
+
294
+ # any_of: Detects when ANY action exists in a single statement
295
+ # (per-statement check - flags individual dangerous actions)
296
+ - any_of:
297
+ - "iam:PutUserPolicy"
298
+ - "iam:PutGroupPolicy"
299
+ - "iam:PutRolePolicy"
300
+
301
+ # Lambda backdoor: Needs both actions somewhere in policy
302
+ - all_of:
303
+ - "lambda:CreateFunction"
304
+ - "iam:PassRole"
305
+
306
+ # Regex patterns work with all_of (policy-wide check)
307
+ - all_of:
308
+ - "iam:Create.*" # Any IAM Create action
309
+ - "iam:Attach.*" # Any IAM Attach action
310
+
311
+ # Enforce required conditions for sensitive actions
312
+ action_condition_enforcement:
313
+ enabled: true
314
+ action_condition_requirements:
315
+ - actions: ["iam:PassRole"]
316
+ severity: critical
317
+ required_conditions:
318
+ - condition_key: "iam:PassedToService"
319
+
320
+ # Ignore specific patterns
321
+ ignore_patterns:
322
+ - filepath: "terraform/modules/admin/*.json"
323
+ - action: "s3:*"
324
+ filepath: "policies/s3-admin-policy.json"
325
+ ```
326
+
327
+ **📖 Complete documentation:**
328
+ - [Check Reference Guide](docs/check-reference.md) - All 18 checks with examples
329
+ - [Configuration Guide](docs/configuration.md) - Full configuration options
330
+ - [Condition Requirements](docs/condition-requirements.md) - Action-specific requirements
331
+ - [Privilege Escalation Detection](docs/privilege-escalation.md) - How privilege escalation works
332
+
333
+ ## Output Formats & GitHub Integration
334
+
335
+ ### Output Formats
336
+ - **Console** - Clean terminal output with colors
337
+ - **Enhanced** - Visual output with progress bars
338
+ - **JSON** - Structured data for automation
339
+ - **Markdown** - GitHub PR comments
340
+ - **SARIF** - GitHub Code Scanning integration
341
+ - **CSV** - Spreadsheet analysis
342
+ - **HTML** - Interactive reports
343
+
344
+ ### GitHub PR Integration
345
+
346
+ **Three comment modes (use any combination):**
347
+ - `--github-comment` - Summary in PR conversation
348
+ - `--github-review` - Line-specific review comments on files
349
+ - `--github-summary` - Overview in GitHub Actions summary tab
350
+
351
+ **Smart comment management:**
352
+ - Automatically cleans up old comments from previous runs
353
+ - Updates summaries instead of duplicating
354
+ - No stale comments left behind
355
+
356
+ **📖 See [GitHub Integration Guide](docs/github-actions-workflows.md) for detailed examples**
357
+
358
+ ## AWS Access Analyzer (Optional)
359
+
360
+ In addition to the 18 built-in checks, optionally enable AWS Access Analyzer for additional validation capabilities that require AWS credentials:
361
+
362
+ ### Access Analyzer Capabilities
363
+
364
+ **Custom Policy Checks:**
365
+ - `check-access-not-granted` - Verify policies DON'T grant specific actions (max 100 actions)
366
+ - `check-no-new-access` - Compare against baseline to detect permission creep
367
+ - `check-no-public-access` - Validate 29+ resource types for public exposure
368
+
369
+ **Example:**
370
+ ```bash
371
+ # Prevent dangerous actions
372
+ iam-validator analyze --path policies/ \
373
+ --check-access-not-granted "s3:DeleteBucket iam:AttachUserPolicy"
374
+
375
+ # Compare against baseline
376
+ iam-validator analyze --path new-policy.json \
377
+ --check-no-new-access baseline-policy.json
378
+
379
+ # Check for public access
380
+ iam-validator analyze --path bucket-policy.json \
381
+ --policy-type RESOURCE_POLICY \
382
+ --check-no-public-access \
383
+ --public-access-resource-type "AWS::S3::Bucket"
384
+ ```
385
+
386
+ **Supported Policy Types:**
387
+ - `IDENTITY_POLICY` (default) - User/role policies
388
+ - `RESOURCE_POLICY` - S3, SNS, KMS resource policies
389
+ - `SERVICE_CONTROL_POLICY` - AWS Organizations SCPs
390
+ - `RESOURCE_CONTROL_POLICY` - AWS Organizations RCPs (2024)
391
+
392
+ **📖 See [Access Analyzer documentation](docs/custom-checks.md) for complete details**
393
+
394
+ ## 📚 Documentation
395
+
396
+ **Guides:**
397
+ - [Check Reference](docs/check-reference.md) - All 18 checks with examples
398
+ - [Configuration Guide](docs/configuration.md) - Customize checks and behavior
399
+ - [GitHub Actions Guide](docs/github-actions-workflows.md) - CI/CD integration
400
+ - [Python Library Guide](docs/python-library-usage.md) - Use as Python package
401
+ - [Contributing Guide](CONTRIBUTING.md) - How to contribute
402
+
403
+ **Examples:**
404
+ - [Configuration Examples](examples/configs/) - 9 config file templates
405
+ - [Workflow Examples](examples/github-actions/) - GitHub Actions workflows
406
+ - [Custom Checks](examples/custom_checks/) - Add your own validation rules
407
+
408
+ ## 🤝 Contributing
409
+
410
+ Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
411
+
412
+ **Quick start:**
413
+ ```bash
414
+ git clone https://github.com/YOUR-USERNAME/iam-policy-validator.git
415
+ cd iam-policy-validator
416
+ uv sync --extra dev
417
+ uv run pytest
418
+ ```
419
+
420
+ ## 📄 License
421
+
422
+ MIT License - see [LICENSE](LICENSE) file for details.
423
+
424
+ **Third-party code:** ARN pattern matching in [iam_validator/sdk/arn_matching.py](iam_validator/sdk/arn_matching.py) is derived from [Parliament](https://github.com/duo-labs/parliament) (BSD 3-Clause License).
425
+
426
+ ## 🆘 Support
427
+
428
+ - **Issues**: [GitHub Issues](https://github.com/boogy/iam-policy-validator/issues)
429
+ - **Discussions**: [GitHub Discussions](https://github.com/boogy/iam-policy-validator/discussions)
@@ -1,53 +1,54 @@
1
1
  iam_validator/__init__.py,sha256=APnMR3Fu4fHhxfsHBvUM2dJIwazgvLKQbfOsSgFPidg,693
2
2
  iam_validator/__main__.py,sha256=to_nz3n_IerJpVVZZ6WSFlFR5s_06J0csfPOTfQZG8g,197
3
- iam_validator/__version__.py,sha256=U-2GASzFF5PD483Cth0LG6biXahUQLBsW4BrfQVnGhw,206
3
+ iam_validator/__version__.py,sha256=hhtguX-fvQWNuUzOdKMFXPyDTbhXhMm7VQgXxQD2xCQ,206
4
4
  iam_validator/checks/__init__.py,sha256=eDiDlVon0CwWGSBnZgM-arn1i5R5ZSG89pgR-ifETxE,1782
5
- iam_validator/checks/action_condition_enforcement.py,sha256=qE2ae6vzOG2LqYGrvxeDdKyXtfdtqgfCBBceTpIGqNY,36573
6
- iam_validator/checks/action_resource_matching.py,sha256=KyF9GgZrfSLy-DR_iaj9J9fOTOaj8G5BvBYqHEiSnkg,16577
5
+ iam_validator/checks/action_condition_enforcement.py,sha256=n-F7NEmQm76Hs-Aj5qxgXney3MpkzbWElZUu1Ig73pw,36723
6
+ iam_validator/checks/action_resource_matching.py,sha256=X9dqWy1s_-h1rA81wZRLOxAVLmUHlGVPjxMo0WKIlwM,17433
7
7
  iam_validator/checks/action_validation.py,sha256=IpxtTsk58f2zEZ-xzAoyHw4QK8BCRV43OffP-8ydf9E,2578
8
8
  iam_validator/checks/condition_key_validation.py,sha256=E-doe2QjvKSkyjXZO9TBp0QS7M0Fv2oYYQQ9738QNxg,3918
9
9
  iam_validator/checks/condition_type_mismatch.py,sha256=qAbP6pP_vM1aBvIBRHji56XLH_5cQI4cDhpMQe19CHM,10588
10
- iam_validator/checks/full_wildcard.py,sha256=8zkmkQo2TkflgNgbclThH73mIBRHbuiob0YO2HwQhuE,2371
10
+ iam_validator/checks/full_wildcard.py,sha256=0_F6h4goWlc3DuZwo1F9YGw5hvpnkfZxYSDxhXXK50I,2449
11
11
  iam_validator/checks/mfa_condition_check.py,sha256=s7K2r9hxlJI1KWk8qXl-JOWE6jLIhpxooK26Pr7acKs,4915
12
- iam_validator/checks/policy_size.py,sha256=gJD8rFHa1CstKaZ2Dj9B5XEI3o0wsGv7ksqjqZXoSXI,5771
13
- iam_validator/checks/policy_type_validation.py,sha256=w85W4zdZ6ZrDy0DmHxxnAXbJGfN8peRDjLfJ4Bp1dWc,15009
14
- iam_validator/checks/principal_validation.py,sha256=DLmqX_QbfuV8O5XtcuocBeR_Vwa50_3RBx35XuLQob8,29837
15
- iam_validator/checks/resource_validation.py,sha256=AEIoiR6AKYLuVaA8ne3QE5qy6NCMDe98_2JAiwE9-JU,4261
16
- iam_validator/checks/sensitive_action.py,sha256=gxPhxMxQzsj7xrvRfMZlfh1o67B2s1ddSLF_KQ0FKOw,9716
17
- iam_validator/checks/service_wildcard.py,sha256=1O3NF8_T1LsCzpm8SFViv1KTh9NYQSqXN8-D3xx6Erw,4156
12
+ iam_validator/checks/policy_size.py,sha256=ibgmrErpkz6OfUAN6bFuHe1KHzpzzra9gHwNtVAkPWc,5729
13
+ iam_validator/checks/policy_type_validation.py,sha256=9qmrA8CXwsVpCU4rT0RrqDXgVOzNamMEpdg3cXWAtBI,15213
14
+ iam_validator/checks/principal_validation.py,sha256=Bm4pH6eiJLDa9ID7UyM63phgffh-P5DpPpSBUbYyVn8,29851
15
+ iam_validator/checks/resource_validation.py,sha256=fGi9QuX-lIHDtLm8xB3VReFFhbZpQ2Yub-FKRafQCkw,5984
16
+ iam_validator/checks/sensitive_action.py,sha256=mdl4g67HBioYTvAvar9CaTjxfaPvpYkNo9phL4E1c1w,9794
17
+ iam_validator/checks/service_wildcard.py,sha256=CiQQoti06nqVgvH-HpBIjoW23tnTJqDU4S-ZnM1DwsA,4218
18
18
  iam_validator/checks/set_operator_validation.py,sha256=1XjOdf-xk-m6m1bODuHsELZccriGqOJTDI-HCcuId80,7464
19
19
  iam_validator/checks/sid_uniqueness.py,sha256=1Ux9W1hPPhzgdCzfxwxvD-nSBRo1SyrxFWlnTXDcOys,6887
20
- iam_validator/checks/wildcard_action.py,sha256=KsAej_GP6qL2XpmvGnS56SIJw3Z-5xyvZ7VDfsERFrU,2045
21
- iam_validator/checks/wildcard_resource.py,sha256=V5aBmb1pr8KhbVv2G4nzjBlZWz0kCOCgW6jKnb2_U60,5504
20
+ iam_validator/checks/wildcard_action.py,sha256=XAVuk5L9dQqiWPgd3HJXGNmYr2bh2szJMVVcHSBXb_8,2140
21
+ iam_validator/checks/wildcard_resource.py,sha256=IEpyoU4mA3t2kRxSwVavtROYIyF0Bq1xZJAL9P7XbVQ,5582
22
22
  iam_validator/checks/utils/__init__.py,sha256=j0X4ibUB6RGx2a-kNoJnlVZwHfoEvzZsIeTmJIAoFzA,45
23
23
  iam_validator/checks/utils/policy_level_checks.py,sha256=2V60C0zhKfsFPjQ-NMlD3EemtwA9S6-4no8nETgXdQE,5274
24
- iam_validator/checks/utils/sensitive_action_matcher.py,sha256=e67RIi-zg7ssFwq6x4kt4wsTF-brNz91KaBxgV-23jg,10687
25
- iam_validator/checks/utils/wildcard_expansion.py,sha256=V3V_KRpapOzPBhpUObJjGHoMhvCH90QvDxppeEHIG_U,3152
24
+ iam_validator/checks/utils/sensitive_action_matcher.py,sha256=tcWK4nImpSVNia0FUsN2uLK9LM5EnzjRFtaPQLHZaLw,10667
25
+ iam_validator/checks/utils/wildcard_expansion.py,sha256=fSSoquVdVZaVWS_qBxAx7LMOzxgHed4ffQ6OAZnuqos,3132
26
26
  iam_validator/commands/__init__.py,sha256=M-5bo8w0TCWydK0cXgJyPD2fmk8bpQs-3b26YbgLzlc,565
27
- iam_validator/commands/analyze.py,sha256=TWlDaZ8gVOdNv6__KQQfzeLVW36qLiL5IzlhGYfvq_g,16501
27
+ iam_validator/commands/analyze.py,sha256=rvLBJ5_A3HB530xtixhaIsC19QON68olEQnn8TievgI,20784
28
28
  iam_validator/commands/base.py,sha256=5baCCMwxz7pdQ6XMpWfXFNz7i1l5dB8Qv9dKKR04Gzs,1074
29
29
  iam_validator/commands/cache.py,sha256=p4ucRVuh42sbK3Lk0b610L3ofAR5TnUreF00fpO6VFg,14219
30
30
  iam_validator/commands/download_services.py,sha256=KKz3ybMLT8DQUf9aFZ0tilJ-o1b6PE8Pf1pC4K6cT8I,9175
31
31
  iam_validator/commands/post_to_pr.py,sha256=CvUXs2xvO-UhluxdfNM6F0TCWD8hDBEOiYw60fm1Dms,2363
32
- iam_validator/commands/validate.py,sha256=vyPsEenHoQPc_ftaVv0Ek5i52OvoqHaRCpVLLjCU5As,23508
32
+ iam_validator/commands/validate.py,sha256=Eik-w613zCnX7hUHziBq4k5la3e3qJ0CO1__7aw-gBk,23554
33
33
  iam_validator/core/__init__.py,sha256=1FvJPMrbzJfS9YbRUJCshJLd5gzWwR9Fd_slS0Aq9c8,416
34
- iam_validator/core/access_analyzer.py,sha256=poeT1i74jXpKr1B3UmvqiTvCTbq82zffWgZHwiFUwoo,24337
35
- iam_validator/core/access_analyzer_report.py,sha256=IrQVszlhFfQ6WykYLpig7TU3hf8dnQTegPDsOvHjR5Q,24873
36
- iam_validator/core/aws_fetcher.py,sha256=NEXS7w6M5_EIXAm6OyyUEenpPU6p2Aj_a_p93aR9vAI,36147
34
+ iam_validator/core/access_analyzer.py,sha256=8GgkR-vCkCtSxtXGywvQNBPYq-rvDLexUuLSyflq0V4,24520
35
+ iam_validator/core/access_analyzer_report.py,sha256=O17gagknvkNMTTlq7BrLM68FjlCEm4LjIKD9oqxEbPg,24860
36
+ iam_validator/core/aws_fetcher.py,sha256=cZFo5JMSoNLx1tpM6NzYr2cnq8Bvc2KQx2nJDmo69lc,36504
37
37
  iam_validator/core/check_registry.py,sha256=cMjtJROkZOLzXxl-mTdLYHdxyajNnOsaHGs-EeaSZ7k,21741
38
38
  iam_validator/core/cli.py,sha256=PkXiZjlgrQ21QustBbspefYsdbxst4gxoClyG2_HQR8,3843
39
39
  iam_validator/core/condition_validators.py,sha256=7zBjlcf2xGFKGbcFrXSLvWT5tFhWxoqwzhsJqS2E8uY,21524
40
- iam_validator/core/models.py,sha256=spL5USsDFNfzQ_7R6yaTo-fcoRANkKS-zCwn88XYjYQ,11544
40
+ iam_validator/core/constants.py,sha256=oblMWsjoroIhwjYgZdcyLxaATsGeR99zQwRg6h59Nlo,3145
41
+ iam_validator/core/models.py,sha256=59yqvHoX3nCSJyQDmWCuEsQzNz9PNiF7um7A1wti-2w,12176
41
42
  iam_validator/core/policy_checks.py,sha256=Uz2yCsqRaoIja31F4ZM-39a1pHv51yZqKyWWkGUZKNY,26489
42
43
  iam_validator/core/policy_loader.py,sha256=TR7SpzlRG3TwH4HBGEFUuhNOmxIR8Cud2SQ-AmHWBpM,14040
43
- iam_validator/core/pr_commenter.py,sha256=EDE8lWsabkHYrOw2ApIUrPbjI5K3-Z_QxJkjakaVsTk,11600
44
- iam_validator/core/report.py,sha256=Yeh_u9jQvTyDV3ignyPcWEQVfFcxNZNrxf4T0fjeWb4,33283
44
+ iam_validator/core/pr_commenter.py,sha256=MU-t7SfdHUpSc6BDbh8_dNAbxDiG-bZBCry-jUXivAc,15066
45
+ iam_validator/core/report.py,sha256=j6uWlFL6Xavl4BnpaQtQoxFOEgKEiuY0IYBq8I9DH5Q,34134
45
46
  iam_validator/core/config/__init__.py,sha256=CWSyIA7kEyzrskEenjYbs9Iih10BXRpiY9H2dHg61rU,2671
46
47
  iam_validator/core/config/aws_api.py,sha256=HLIzOItQ0A37wxHcgWck6ZFO0wmNY8JNTiWMMK6JKYU,1248
47
48
  iam_validator/core/config/aws_global_conditions.py,sha256=gdmMxXGBy95B3uYUG-J7rnM6Ixgc6L7Y9Pcd2XAMb60,7170
48
49
  iam_validator/core/config/category_suggestions.py,sha256=QlrYi4BTkxDSTlL7NZGE9BWN-atWetZ6XjkI9F_7YzI,4370
49
50
  iam_validator/core/config/condition_requirements.py,sha256=1PuADTB9pLqh-kNUGC7kSU6LMLtXMSc003tvI7qKeAY,5170
50
- iam_validator/core/config/config_loader.py,sha256=MjO9SJ3HSXl6gnv_Qy0d906pX9iW8cONM8alOotUaKI,17749
51
+ iam_validator/core/config/config_loader.py,sha256=7YkuPnroR-Up5CUTQOXIyS_b732WrzNn8o1EH9O6lyI,17730
51
52
  iam_validator/core/config/defaults.py,sha256=w5ievxkqki3zYr7NaREoWtVx5rTfxBpZlgoNdovcILs,27112
52
53
  iam_validator/core/config/principal_requirements.py,sha256=VCX7fBDgeDTJQyoz7_x7GI7Kf9O1Eu-sbihoHOrKv6o,15105
53
54
  iam_validator/core/config/sensitive_actions.py,sha256=uATDIp_TD3OQQlsYTZp79qd1mSK2Bf9hJ0JwcqLBr84,25344
@@ -63,10 +64,10 @@ iam_validator/core/formatters/json.py,sha256=A7gZ8P32GEdbDvrSn6v56yQ4fOP_kyMaoFV
63
64
  iam_validator/core/formatters/markdown.py,sha256=aPAY6FpZBHsVBDag3FAsB_X9CZzznFjX9dQr0ysDrTE,2251
64
65
  iam_validator/core/formatters/sarif.py,sha256=O3pn7whqFq5xxk-tuoqSb2k4Fk5ai_A2SKX_ph8GLV4,10469
65
66
  iam_validator/integrations/__init__.py,sha256=7Hlor_X9j0NZaEjFuSvoXAAuSKQ-zgY19Rk-Dz3JpKo,616
66
- iam_validator/integrations/github_integration.py,sha256=bKs94vNT4PmcmUPUeuY2WJFhCYpUY2SWiBP1vj-andA,25673
67
+ iam_validator/integrations/github_integration.py,sha256=QoPkaxdRDQTzmHN4cKEXoGcn8BRv37JW4IvD2W5jEtc,26474
67
68
  iam_validator/integrations/ms_teams.py,sha256=t2PlWuTDb6GGH-eDU1jnOKd8D1w4FCB68bahGA7MJcE,14475
68
69
  iam_validator/sdk/__init__.py,sha256=fRDSXAclGmCU3KDft4StL8JUcpAsdzwIRf8mVj461q0,5306
69
- iam_validator/sdk/arn_matching.py,sha256=we70RM2sriCcsd5GAUj7gL0iGKZt3oa0kle2VLF-X2E,8841
70
+ iam_validator/sdk/arn_matching.py,sha256=HSDpLltOYISq-SoPebAlM89mKOaUaghq_04urchEFDA,12778
70
71
  iam_validator/sdk/context.py,sha256=SBFeedu8rhCzFA-zC2cH4wLZxEJT6XOW30hIZAyXPVU,6826
71
72
  iam_validator/sdk/exceptions.py,sha256=tm91TxIwU157U_UHN7w5qICf_OhU11agj6pV5W_YP-4,1023
72
73
  iam_validator/sdk/helpers.py,sha256=OVBg4xrW95LT74wXCg1LQkba9kw5RfFqeCLuTqhgL-A,5697
@@ -74,9 +75,9 @@ iam_validator/sdk/policy_utils.py,sha256=CZS1OGSdiWsd2lsCwg0BDcUNWa61tUwgvn-P5rK
74
75
  iam_validator/sdk/shortcuts.py,sha256=EVNSYV7rv4TFH03ulsZ3mS1UVmTSp2jKpc2AXs4j1q4,8531
75
76
  iam_validator/utils/__init__.py,sha256=V8u-SSdnL4a7NwF-yg9x0JRl5epKAXEs2f5RiwK2qPo,856
76
77
  iam_validator/utils/cache.py,sha256=wOQKOBeoG6QqC5f0oXcHz63Cjtu_-SsSS-0pTSwyAiM,3254
77
- iam_validator/utils/regex.py,sha256=PMVCYxjlVa2zLNEnIU3upQCSIhPazlXWg_sJClIiqiM,6221
78
- iam_policy_validator-1.6.0.dist-info/METADATA,sha256=rghXQo_4hFarMkPFzCmWFgD_1yMW1dwtwGIId_MsBdc,36586
79
- iam_policy_validator-1.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
- iam_policy_validator-1.6.0.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
81
- iam_policy_validator-1.6.0.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
82
- iam_policy_validator-1.6.0.dist-info/RECORD,,
78
+ iam_validator/utils/regex.py,sha256=xHoMECttb7qaMhts-c9b0GIxdhHNZTt-UBr7wNhWfzg,6219
79
+ iam_policy_validator-1.7.1.dist-info/METADATA,sha256=WCjnDcJ38j-LRUz2EwdT2b2lX2IOTkW3xT1SLtCxiWY,15343
80
+ iam_policy_validator-1.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
81
+ iam_policy_validator-1.7.1.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
82
+ iam_policy_validator-1.7.1.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
83
+ iam_policy_validator-1.7.1.dist-info/RECORD,,
@@ -3,5 +3,5 @@
3
3
  This file is the single source of truth for the package version.
4
4
  """
5
5
 
6
- __version__ = "1.6.0"
6
+ __version__ = "1.7.1"
7
7
  __version_info__ = tuple(int(part) for part in __version__.split("."))
@@ -491,6 +491,7 @@ class ActionConditionEnforcementCheck(PolicyCheck):
491
491
  if re.match(f"^{wildcard_pattern}$", statement_action):
492
492
  return True
493
493
  except re.error:
494
+ # Invalid regex pattern - skip this match attempt
494
495
  pass
495
496
 
496
497
  # AWS wildcard match in statement_action (e.g., "iam:Creat*" in policy)
@@ -507,6 +508,7 @@ class ActionConditionEnforcementCheck(PolicyCheck):
507
508
  if re.match(f"^{stmt_wildcard_pattern}$", required_action):
508
509
  return True
509
510
  except re.error:
511
+ # Invalid regex pattern - skip this match attempt
510
512
  pass
511
513
 
512
514
  # Check if statement wildcard overlaps with any of our action patterns
@@ -794,7 +796,7 @@ class ActionConditionEnforcementCheck(PolicyCheck):
794
796
 
795
797
  # Build example based on condition key type
796
798
  if example:
797
- parts.append(f"Example:\n{example}")
799
+ parts.append(f"Example:\n```json\n{example}\n```")
798
800
  else:
799
801
  # Auto-generate example
800
802
  example_lines = ['Add to "Condition" block:', f' "{operator}": {{']
@@ -27,6 +27,8 @@ from iam_validator.core.models import Statement, ValidationIssue
27
27
  from iam_validator.sdk.arn_matching import (
28
28
  arn_strictly_valid,
29
29
  convert_aws_pattern_to_wildcard,
30
+ has_template_variables,
31
+ normalize_template_variables,
30
32
  )
31
33
 
32
34
 
@@ -71,6 +73,13 @@ class ActionResourceMatchingCheck(PolicyCheck):
71
73
  """
72
74
  issues = []
73
75
 
76
+ # Check if template variable support is enabled (default: true)
77
+ # Try global settings first, then check-specific config
78
+ allow_template_variables = config.root_config.get("settings", {}).get(
79
+ "allow_template_variables",
80
+ config.config.get("allow_template_variables", True),
81
+ )
82
+
74
83
  # Get actions and resources
75
84
  actions = statement.get_actions()
76
85
  resources = statement.get_resources()
@@ -157,7 +166,13 @@ class ActionResourceMatchingCheck(PolicyCheck):
157
166
 
158
167
  # Check if any policy resource matches this ARN pattern
159
168
  for resource in resources:
160
- if arn_strictly_valid(wildcard_pattern, resource, resource_name):
169
+ # Normalize template variables (Terraform/CloudFormation) before matching
170
+ # This allows policies with ${aws_account_id}, ${AWS::AccountId}, etc.
171
+ validation_resource = resource
172
+ if allow_template_variables and has_template_variables(resource):
173
+ validation_resource = normalize_template_variables(resource)
174
+
175
+ if arn_strictly_valid(wildcard_pattern, validation_resource, resource_name):
161
176
  match_found = True
162
177
  break
163
178
 
@@ -185,8 +200,8 @@ class ActionResourceMatchingCheck(PolicyCheck):
185
200
  issues.append(
186
201
  self._create_mismatch_issue(
187
202
  action=action,
188
- required_format=required_formats[0]["format"] if required_formats else "",
189
- required_type=required_formats[0]["type"] if required_formats else "",
203
+ required_format=(required_formats[0]["format"] if required_formats else ""),
204
+ required_type=(required_formats[0]["type"] if required_formats else ""),
190
205
  provided_resources=resources,
191
206
  statement_idx=statement_idx,
192
207
  statement_sid=statement_sid,
@@ -236,9 +251,11 @@ class ActionResourceMatchingCheck(PolicyCheck):
236
251
  issue_type="resource_mismatch",
237
252
  message=message,
238
253
  action=action,
239
- resource=", ".join(provided_resources)
240
- if len(provided_resources) <= 3
241
- else f"{provided_resources[0]}...",
254
+ resource=(
255
+ ", ".join(provided_resources)
256
+ if len(provided_resources) <= 3
257
+ else f"{provided_resources[0]}..."
258
+ ),
242
259
  suggestion=suggestion,
243
260
  line_number=line_number,
244
261
  )
@@ -50,7 +50,11 @@ class FullWildcardCheck(PolicyCheck):
50
50
  example = config.config.get("example", "")
51
51
 
52
52
  # Combine suggestion + example
53
- suggestion = f"{suggestion_text}\nExample:\n{example}" if example else suggestion_text
53
+ suggestion = (
54
+ f"{suggestion_text}\nExample:\n```json\n{example}\n```"
55
+ if example
56
+ else suggestion_text
57
+ )
54
58
 
55
59
  issues.append(
56
60
  ValidationIssue(