iam-policy-validator 1.7.0__py3-none-any.whl → 1.7.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iam_policy_validator-1.7.2.dist-info/METADATA +428 -0
- {iam_policy_validator-1.7.0.dist-info → iam_policy_validator-1.7.2.dist-info}/RECORD +37 -36
- iam_validator/__version__.py +4 -2
- iam_validator/checks/action_condition_enforcement.py +22 -13
- iam_validator/checks/action_resource_matching.py +70 -36
- iam_validator/checks/condition_key_validation.py +7 -7
- iam_validator/checks/condition_type_mismatch.py +8 -6
- iam_validator/checks/full_wildcard.py +2 -8
- iam_validator/checks/mfa_condition_check.py +8 -8
- iam_validator/checks/principal_validation.py +24 -20
- iam_validator/checks/sensitive_action.py +3 -9
- iam_validator/checks/service_wildcard.py +2 -8
- iam_validator/checks/sid_uniqueness.py +1 -1
- iam_validator/checks/utils/sensitive_action_matcher.py +1 -2
- iam_validator/checks/utils/wildcard_expansion.py +1 -2
- iam_validator/checks/wildcard_action.py +2 -8
- iam_validator/checks/wildcard_resource.py +2 -8
- iam_validator/commands/validate.py +2 -2
- iam_validator/core/aws_fetcher.py +115 -22
- iam_validator/core/config/config_loader.py +1 -2
- iam_validator/core/config/defaults.py +16 -7
- iam_validator/core/constants.py +57 -0
- iam_validator/core/formatters/console.py +10 -1
- iam_validator/core/formatters/csv.py +2 -1
- iam_validator/core/formatters/enhanced.py +42 -8
- iam_validator/core/formatters/markdown.py +2 -1
- iam_validator/core/models.py +22 -7
- iam_validator/core/policy_checks.py +5 -4
- iam_validator/core/policy_loader.py +71 -14
- iam_validator/core/report.py +65 -24
- iam_validator/integrations/github_integration.py +4 -5
- iam_validator/utils/__init__.py +4 -0
- iam_validator/utils/regex.py +7 -8
- iam_validator/utils/terminal.py +22 -0
- iam_policy_validator-1.7.0.dist-info/METADATA +0 -1057
- {iam_policy_validator-1.7.0.dist-info → iam_policy_validator-1.7.2.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.7.0.dist-info → iam_policy_validator-1.7.2.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.7.0.dist-info → iam_policy_validator-1.7.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iam-policy-validator
|
|
3
|
+
Version: 1.7.2
|
|
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
|
+
[](https://github.com/marketplace/actions/iam-policy-validator)
|
|
48
|
+
[](https://www.python.org/downloads/)
|
|
49
|
+
[](LICENSE)
|
|
50
|
+
[](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)
|
|
@@ -1,70 +1,70 @@
|
|
|
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=
|
|
3
|
+
iam_validator/__version__.py,sha256=0niAY6KgsXeeyFV5nTmvfvem16X3OTrO_DItEqsW74A,361
|
|
4
4
|
iam_validator/checks/__init__.py,sha256=eDiDlVon0CwWGSBnZgM-arn1i5R5ZSG89pgR-ifETxE,1782
|
|
5
|
-
iam_validator/checks/action_condition_enforcement.py,sha256=
|
|
6
|
-
iam_validator/checks/action_resource_matching.py,sha256=
|
|
5
|
+
iam_validator/checks/action_condition_enforcement.py,sha256=VhFEGbkcgkRwNRRuslvat5uib2tlH2Nr6sltbAQTs6I,36834
|
|
6
|
+
iam_validator/checks/action_resource_matching.py,sha256=sk67jcDF1WzW4tPgcRSdTj4UBe2stALdwHx5ViVA9dU,19207
|
|
7
7
|
iam_validator/checks/action_validation.py,sha256=IpxtTsk58f2zEZ-xzAoyHw4QK8BCRV43OffP-8ydf9E,2578
|
|
8
|
-
iam_validator/checks/condition_key_validation.py,sha256=
|
|
9
|
-
iam_validator/checks/condition_type_mismatch.py,sha256=
|
|
10
|
-
iam_validator/checks/full_wildcard.py,sha256=
|
|
11
|
-
iam_validator/checks/mfa_condition_check.py,sha256=
|
|
8
|
+
iam_validator/checks/condition_key_validation.py,sha256=10XxTwIcr887CbgmN90jfRZabj5RHo08dGa8csM50Fo,3980
|
|
9
|
+
iam_validator/checks/condition_type_mismatch.py,sha256=JyiAOyUZShzXZI8dgycL4oqwRkpJYUPwoGX4zigsi5I,10613
|
|
10
|
+
iam_validator/checks/full_wildcard.py,sha256=ywD762BOV8WxFuTTARkaGMJn27f3ZZVuZUjKo8URnTc,2281
|
|
11
|
+
iam_validator/checks/mfa_condition_check.py,sha256=YCBX3tFTQRmVTAed_W-Tu1b6WqD2LBYyom53P7lBjh4,4935
|
|
12
12
|
iam_validator/checks/policy_size.py,sha256=ibgmrErpkz6OfUAN6bFuHe1KHzpzzra9gHwNtVAkPWc,5729
|
|
13
13
|
iam_validator/checks/policy_type_validation.py,sha256=9qmrA8CXwsVpCU4rT0RrqDXgVOzNamMEpdg3cXWAtBI,15213
|
|
14
|
-
iam_validator/checks/principal_validation.py,sha256=
|
|
14
|
+
iam_validator/checks/principal_validation.py,sha256=gTv_TqJDspGEX3iJkHXrw3DyKMJeyE33uQakZ0PjNoo,29969
|
|
15
15
|
iam_validator/checks/resource_validation.py,sha256=fGi9QuX-lIHDtLm8xB3VReFFhbZpQ2Yub-FKRafQCkw,5984
|
|
16
|
-
iam_validator/checks/sensitive_action.py,sha256=
|
|
17
|
-
iam_validator/checks/service_wildcard.py,sha256=
|
|
16
|
+
iam_validator/checks/sensitive_action.py,sha256=0vuhF1UkAH_vxhfHsC8xk68aJXHvI7c9KTLcJFNlnHM,9652
|
|
17
|
+
iam_validator/checks/service_wildcard.py,sha256=1ynXLG6_82SIH8aHP88qQojJf38ZH0agnSmHp0VkZ98,4010
|
|
18
18
|
iam_validator/checks/set_operator_validation.py,sha256=1XjOdf-xk-m6m1bODuHsELZccriGqOJTDI-HCcuId80,7464
|
|
19
|
-
iam_validator/checks/sid_uniqueness.py,sha256=
|
|
20
|
-
iam_validator/checks/wildcard_action.py,sha256=
|
|
21
|
-
iam_validator/checks/wildcard_resource.py,sha256=
|
|
19
|
+
iam_validator/checks/sid_uniqueness.py,sha256=yWNHyy002aIHxJKtHeYpYds7bKgreL0BvQmRkI2UwvQ,6891
|
|
20
|
+
iam_validator/checks/wildcard_action.py,sha256=f1QZ68eHzQwCTeYY_9UiYaMxUaq7XYia6DaBjIspZ2A,1972
|
|
21
|
+
iam_validator/checks/wildcard_resource.py,sha256=GNpbk7WDExHG6Yqu4_gxeRCK6NUEL8TFjgbvaHgg7V0,5414
|
|
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=
|
|
25
|
-
iam_validator/checks/utils/wildcard_expansion.py,sha256=
|
|
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
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=
|
|
32
|
+
iam_validator/commands/validate.py,sha256=2v91ogbEzKfjk2u6Y4NO0yvsCOwxi9jXoqD7acBbVTE,23624
|
|
33
33
|
iam_validator/core/__init__.py,sha256=1FvJPMrbzJfS9YbRUJCshJLd5gzWwR9Fd_slS0Aq9c8,416
|
|
34
34
|
iam_validator/core/access_analyzer.py,sha256=8GgkR-vCkCtSxtXGywvQNBPYq-rvDLexUuLSyflq0V4,24520
|
|
35
35
|
iam_validator/core/access_analyzer_report.py,sha256=O17gagknvkNMTTlq7BrLM68FjlCEm4LjIKD9oqxEbPg,24860
|
|
36
|
-
iam_validator/core/aws_fetcher.py,sha256=
|
|
36
|
+
iam_validator/core/aws_fetcher.py,sha256=obTzxHD9pMsWo-SojSOeWyw2s2_St-LNgbmh5BGEM9c,41215
|
|
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/constants.py,sha256=
|
|
41
|
-
iam_validator/core/models.py,sha256=
|
|
42
|
-
iam_validator/core/policy_checks.py,sha256=
|
|
43
|
-
iam_validator/core/policy_loader.py,sha256=
|
|
40
|
+
iam_validator/core/constants.py,sha256=H3eH0yddn5Dk-xZxJWtuvluRIpuXKYGiiteBSHPpJoI,5560
|
|
41
|
+
iam_validator/core/models.py,sha256=55BCSqqJiAN96SFwK3tiTy6fhu6YBL6avKo8VpCpy2A,12766
|
|
42
|
+
iam_validator/core/policy_checks.py,sha256=3UMLl8SQ4oJLTU1kwscvh7c7gpT5QtjITk_bJCJ_rzs,26616
|
|
43
|
+
iam_validator/core/policy_loader.py,sha256=HVEnaXhQwrb9WbXpu0tn8SJBvHNW9UgDO6w4zLjLsu0,16776
|
|
44
44
|
iam_validator/core/pr_commenter.py,sha256=MU-t7SfdHUpSc6BDbh8_dNAbxDiG-bZBCry-jUXivAc,15066
|
|
45
|
-
iam_validator/core/report.py,sha256=
|
|
45
|
+
iam_validator/core/report.py,sha256=kzSeWnT1LqWZVA5pqKKz-maVowXVj0djdoShfRhhpz4,35899
|
|
46
46
|
iam_validator/core/config/__init__.py,sha256=CWSyIA7kEyzrskEenjYbs9Iih10BXRpiY9H2dHg61rU,2671
|
|
47
47
|
iam_validator/core/config/aws_api.py,sha256=HLIzOItQ0A37wxHcgWck6ZFO0wmNY8JNTiWMMK6JKYU,1248
|
|
48
48
|
iam_validator/core/config/aws_global_conditions.py,sha256=gdmMxXGBy95B3uYUG-J7rnM6Ixgc6L7Y9Pcd2XAMb60,7170
|
|
49
49
|
iam_validator/core/config/category_suggestions.py,sha256=QlrYi4BTkxDSTlL7NZGE9BWN-atWetZ6XjkI9F_7YzI,4370
|
|
50
50
|
iam_validator/core/config/condition_requirements.py,sha256=1PuADTB9pLqh-kNUGC7kSU6LMLtXMSc003tvI7qKeAY,5170
|
|
51
|
-
iam_validator/core/config/config_loader.py,sha256=
|
|
52
|
-
iam_validator/core/config/defaults.py,sha256=
|
|
51
|
+
iam_validator/core/config/config_loader.py,sha256=qKD8aR8YAswaFf68pnYJLFNwKznvcc6lNxSQWU3i6SY,17713
|
|
52
|
+
iam_validator/core/config/defaults.py,sha256=mCOr_YgiRQp6fThtxrcjMtm-LPdZQbd6AS16gLzV17c,27589
|
|
53
53
|
iam_validator/core/config/principal_requirements.py,sha256=VCX7fBDgeDTJQyoz7_x7GI7Kf9O1Eu-sbihoHOrKv6o,15105
|
|
54
54
|
iam_validator/core/config/sensitive_actions.py,sha256=uATDIp_TD3OQQlsYTZp79qd1mSK2Bf9hJ0JwcqLBr84,25344
|
|
55
55
|
iam_validator/core/config/service_principals.py,sha256=gQSROsxUWBD6P2F9qP320UZV4lHGlsyvHSkMyy0njrU,2685
|
|
56
56
|
iam_validator/core/config/wildcards.py,sha256=H_v6hb-rZ0UUz4cul9lxkVI39e6knaK4Y-MbWz2Ebpw,3228
|
|
57
57
|
iam_validator/core/formatters/__init__.py,sha256=fnCKAEBXItnOf2m4rhVs7zwMaTxbG6ESh3CF8V5j5ec,868
|
|
58
58
|
iam_validator/core/formatters/base.py,sha256=SShDeDiy5mYQnS6BpA8xYg91N-KX1EObkOtlrVHqx1Q,4451
|
|
59
|
-
iam_validator/core/formatters/console.py,sha256=
|
|
60
|
-
iam_validator/core/formatters/csv.py,sha256=
|
|
61
|
-
iam_validator/core/formatters/enhanced.py,sha256=
|
|
59
|
+
iam_validator/core/formatters/console.py,sha256=FdTp7AzeILCWrUynSvSew8QJKGOMJaAA9_YiQJd-uco,2196
|
|
60
|
+
iam_validator/core/formatters/csv.py,sha256=pPqgvGh4KtD5Qm36xnMaDAavXYR6MlQhs4zbcrxT550,5941
|
|
61
|
+
iam_validator/core/formatters/enhanced.py,sha256=TVtkcTIow8NGoLhG45-5ms-_PTxyxMcAHxf_uPMyKAc,18155
|
|
62
62
|
iam_validator/core/formatters/html.py,sha256=j4sQi-wXiD9kCHldW5JCzbJe0frhiP5uQI9KlH3Sj_g,22994
|
|
63
63
|
iam_validator/core/formatters/json.py,sha256=A7gZ8P32GEdbDvrSn6v56yQ4fOP_kyMaoFVXG2bgnew,939
|
|
64
|
-
iam_validator/core/formatters/markdown.py,sha256=
|
|
64
|
+
iam_validator/core/formatters/markdown.py,sha256=dk4STeY-tOEZsVrlmolIEqZvWYP9JhRtygxxNA49DEE,2293
|
|
65
65
|
iam_validator/core/formatters/sarif.py,sha256=O3pn7whqFq5xxk-tuoqSb2k4Fk5ai_A2SKX_ph8GLV4,10469
|
|
66
66
|
iam_validator/integrations/__init__.py,sha256=7Hlor_X9j0NZaEjFuSvoXAAuSKQ-zgY19Rk-Dz3JpKo,616
|
|
67
|
-
iam_validator/integrations/github_integration.py,sha256=
|
|
67
|
+
iam_validator/integrations/github_integration.py,sha256=EnrolMq3uZbKWPxUMhYnqcKAfic6Fb8qJzieDruKqsc,26485
|
|
68
68
|
iam_validator/integrations/ms_teams.py,sha256=t2PlWuTDb6GGH-eDU1jnOKd8D1w4FCB68bahGA7MJcE,14475
|
|
69
69
|
iam_validator/sdk/__init__.py,sha256=fRDSXAclGmCU3KDft4StL8JUcpAsdzwIRf8mVj461q0,5306
|
|
70
70
|
iam_validator/sdk/arn_matching.py,sha256=HSDpLltOYISq-SoPebAlM89mKOaUaghq_04urchEFDA,12778
|
|
@@ -73,11 +73,12 @@ iam_validator/sdk/exceptions.py,sha256=tm91TxIwU157U_UHN7w5qICf_OhU11agj6pV5W_YP
|
|
|
73
73
|
iam_validator/sdk/helpers.py,sha256=OVBg4xrW95LT74wXCg1LQkba9kw5RfFqeCLuTqhgL-A,5697
|
|
74
74
|
iam_validator/sdk/policy_utils.py,sha256=CZS1OGSdiWsd2lsCwg0BDcUNWa61tUwgvn-P5rKqeN8,12987
|
|
75
75
|
iam_validator/sdk/shortcuts.py,sha256=EVNSYV7rv4TFH03ulsZ3mS1UVmTSp2jKpc2AXs4j1q4,8531
|
|
76
|
-
iam_validator/utils/__init__.py,sha256=
|
|
76
|
+
iam_validator/utils/__init__.py,sha256=NveA2F3G1E6-ANZzFr7J6Q6u5mogvMp862iFokmYuCs,1021
|
|
77
77
|
iam_validator/utils/cache.py,sha256=wOQKOBeoG6QqC5f0oXcHz63Cjtu_-SsSS-0pTSwyAiM,3254
|
|
78
|
-
iam_validator/utils/regex.py,sha256=
|
|
79
|
-
|
|
80
|
-
iam_policy_validator-1.7.
|
|
81
|
-
iam_policy_validator-1.7.
|
|
82
|
-
iam_policy_validator-1.7.
|
|
83
|
-
iam_policy_validator-1.7.
|
|
78
|
+
iam_validator/utils/regex.py,sha256=xHoMECttb7qaMhts-c9b0GIxdhHNZTt-UBr7wNhWfzg,6219
|
|
79
|
+
iam_validator/utils/terminal.py,sha256=FsRaRMH_JAyDgXWBCOgOEhbS89cs17HCmKYoughq5io,724
|
|
80
|
+
iam_policy_validator-1.7.2.dist-info/METADATA,sha256=fwySi0xxZPeiRTXyYfmp8YZPNyphy8HylBzhSXkNNG0,15244
|
|
81
|
+
iam_policy_validator-1.7.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
82
|
+
iam_policy_validator-1.7.2.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
|
|
83
|
+
iam_policy_validator-1.7.2.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
|
|
84
|
+
iam_policy_validator-1.7.2.dist-info/RECORD,,
|
iam_validator/__version__.py
CHANGED
|
@@ -3,5 +3,7 @@
|
|
|
3
3
|
This file is the single source of truth for the package version.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
__version__ = "1.7.
|
|
7
|
-
|
|
6
|
+
__version__ = "1.7.2"
|
|
7
|
+
# Parse version, handling pre-release suffixes like -rc, -alpha, -beta
|
|
8
|
+
_version_base = __version__.split("-")[0] # Remove pre-release suffix if present
|
|
9
|
+
__version_info__ = tuple(int(part) for part in _version_base.split("."))
|
|
@@ -349,7 +349,10 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
349
349
|
return issues
|
|
350
350
|
|
|
351
351
|
async def _check_action_match(
|
|
352
|
-
self,
|
|
352
|
+
self,
|
|
353
|
+
statement_actions: list[str],
|
|
354
|
+
requirement: dict[str, Any],
|
|
355
|
+
fetcher: AWSServiceFetcher,
|
|
353
356
|
) -> tuple[bool, list[str]]:
|
|
354
357
|
"""
|
|
355
358
|
Check if statement actions match the requirement.
|
|
@@ -491,6 +494,7 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
491
494
|
if re.match(f"^{wildcard_pattern}$", statement_action):
|
|
492
495
|
return True
|
|
493
496
|
except re.error:
|
|
497
|
+
# Invalid regex pattern - skip this match attempt
|
|
494
498
|
pass
|
|
495
499
|
|
|
496
500
|
# AWS wildcard match in statement_action (e.g., "iam:Creat*" in policy)
|
|
@@ -507,6 +511,7 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
507
511
|
if re.match(f"^{stmt_wildcard_pattern}$", required_action):
|
|
508
512
|
return True
|
|
509
513
|
except re.error:
|
|
514
|
+
# Invalid regex pattern - skip this match attempt
|
|
510
515
|
pass
|
|
511
516
|
|
|
512
517
|
# Check if statement wildcard overlaps with any of our action patterns
|
|
@@ -764,6 +769,10 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
764
769
|
or self.get_severity(config) # Global check severity
|
|
765
770
|
)
|
|
766
771
|
|
|
772
|
+
suggestion_text, example_code = self._build_suggestion(
|
|
773
|
+
condition_key, description, example, expected_value, operator
|
|
774
|
+
)
|
|
775
|
+
|
|
767
776
|
return ValidationIssue(
|
|
768
777
|
severity=severity,
|
|
769
778
|
statement_sid=statement.sid,
|
|
@@ -772,9 +781,8 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
772
781
|
message=f"{message_prefix} Action(s) {matching_actions} require condition '{condition_key}'",
|
|
773
782
|
action=", ".join(matching_actions),
|
|
774
783
|
condition_key=condition_key,
|
|
775
|
-
suggestion=
|
|
776
|
-
|
|
777
|
-
),
|
|
784
|
+
suggestion=suggestion_text,
|
|
785
|
+
example=example_code,
|
|
778
786
|
line_number=statement.line_number,
|
|
779
787
|
)
|
|
780
788
|
|
|
@@ -785,19 +793,20 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
785
793
|
example: str,
|
|
786
794
|
expected_value: Any = None,
|
|
787
795
|
operator: str = "StringEquals",
|
|
788
|
-
) -> str:
|
|
789
|
-
"""Build
|
|
790
|
-
parts = []
|
|
796
|
+
) -> tuple[str, str]:
|
|
797
|
+
"""Build suggestion and example for adding the missing condition.
|
|
791
798
|
|
|
792
|
-
|
|
793
|
-
|
|
799
|
+
Returns:
|
|
800
|
+
Tuple of (suggestion_text, example_code)
|
|
801
|
+
"""
|
|
802
|
+
suggestion = description if description else f"Add condition: {condition_key}"
|
|
794
803
|
|
|
795
804
|
# Build example based on condition key type
|
|
796
805
|
if example:
|
|
797
|
-
|
|
806
|
+
example_code = example
|
|
798
807
|
else:
|
|
799
808
|
# Auto-generate example
|
|
800
|
-
example_lines = [
|
|
809
|
+
example_lines = [f' "{operator}": {{']
|
|
801
810
|
|
|
802
811
|
if isinstance(expected_value, list):
|
|
803
812
|
value_str = (
|
|
@@ -824,9 +833,9 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
824
833
|
example_lines.append(f' "{condition_key}": {value_str}')
|
|
825
834
|
example_lines.append(" }")
|
|
826
835
|
|
|
827
|
-
|
|
836
|
+
example_code = "\n".join(example_lines)
|
|
828
837
|
|
|
829
|
-
return
|
|
838
|
+
return suggestion, example_code
|
|
830
839
|
|
|
831
840
|
def _build_any_of_suggestion(self, any_of_conditions: list[dict[str, Any]]) -> str:
|
|
832
841
|
"""Build suggestion for any_of conditions."""
|