iam-policy-validator 1.7.2__py3-none-any.whl → 1.9.0__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 (56) hide show
  1. {iam_policy_validator-1.7.2.dist-info → iam_policy_validator-1.9.0.dist-info}/METADATA +127 -6
  2. iam_policy_validator-1.9.0.dist-info/RECORD +95 -0
  3. iam_validator/__init__.py +1 -1
  4. iam_validator/__version__.py +1 -1
  5. iam_validator/checks/__init__.py +5 -3
  6. iam_validator/checks/action_condition_enforcement.py +559 -207
  7. iam_validator/checks/action_resource_matching.py +12 -15
  8. iam_validator/checks/action_validation.py +7 -13
  9. iam_validator/checks/condition_key_validation.py +7 -13
  10. iam_validator/checks/condition_type_mismatch.py +15 -22
  11. iam_validator/checks/full_wildcard.py +9 -13
  12. iam_validator/checks/mfa_condition_check.py +8 -17
  13. iam_validator/checks/policy_size.py +6 -39
  14. iam_validator/checks/policy_structure.py +547 -0
  15. iam_validator/checks/policy_type_validation.py +61 -46
  16. iam_validator/checks/principal_validation.py +71 -148
  17. iam_validator/checks/resource_validation.py +13 -20
  18. iam_validator/checks/sensitive_action.py +15 -18
  19. iam_validator/checks/service_wildcard.py +8 -14
  20. iam_validator/checks/set_operator_validation.py +21 -28
  21. iam_validator/checks/sid_uniqueness.py +16 -42
  22. iam_validator/checks/trust_policy_validation.py +506 -0
  23. iam_validator/checks/utils/sensitive_action_matcher.py +26 -26
  24. iam_validator/checks/utils/wildcard_expansion.py +2 -2
  25. iam_validator/checks/wildcard_action.py +9 -13
  26. iam_validator/checks/wildcard_resource.py +9 -13
  27. iam_validator/commands/cache.py +4 -3
  28. iam_validator/commands/validate.py +15 -9
  29. iam_validator/core/__init__.py +2 -3
  30. iam_validator/core/access_analyzer.py +1 -1
  31. iam_validator/core/access_analyzer_report.py +2 -2
  32. iam_validator/core/aws_fetcher.py +24 -1028
  33. iam_validator/core/aws_service/__init__.py +21 -0
  34. iam_validator/core/aws_service/cache.py +108 -0
  35. iam_validator/core/aws_service/client.py +205 -0
  36. iam_validator/core/aws_service/fetcher.py +612 -0
  37. iam_validator/core/aws_service/parsers.py +149 -0
  38. iam_validator/core/aws_service/patterns.py +51 -0
  39. iam_validator/core/aws_service/storage.py +291 -0
  40. iam_validator/core/aws_service/validators.py +379 -0
  41. iam_validator/core/check_registry.py +165 -93
  42. iam_validator/core/config/condition_requirements.py +69 -17
  43. iam_validator/core/config/defaults.py +58 -52
  44. iam_validator/core/config/service_principals.py +40 -3
  45. iam_validator/core/constants.py +17 -0
  46. iam_validator/core/ignore_patterns.py +297 -0
  47. iam_validator/core/models.py +15 -5
  48. iam_validator/core/policy_checks.py +38 -475
  49. iam_validator/core/policy_loader.py +27 -4
  50. iam_validator/sdk/__init__.py +1 -1
  51. iam_validator/sdk/context.py +1 -1
  52. iam_validator/sdk/helpers.py +1 -1
  53. iam_policy_validator-1.7.2.dist-info/RECORD +0 -84
  54. {iam_policy_validator-1.7.2.dist-info → iam_policy_validator-1.9.0.dist-info}/WHEEL +0 -0
  55. {iam_policy_validator-1.7.2.dist-info → iam_policy_validator-1.9.0.dist-info}/entry_points.txt +0 -0
  56. {iam_policy_validator-1.7.2.dist-info → iam_policy_validator-1.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,9 @@
1
1
  """Wildcard resource check - detects Resource: '*' in IAM policies."""
2
2
 
3
+ from typing import ClassVar
4
+
3
5
  from iam_validator.checks.utils.wildcard_expansion import expand_wildcard_actions
4
- from iam_validator.core.aws_fetcher import AWSServiceFetcher
6
+ from iam_validator.core.aws_service import AWSServiceFetcher
5
7
  from iam_validator.core.check_registry import CheckConfig, PolicyCheck
6
8
  from iam_validator.core.models import Statement, ValidationIssue
7
9
 
@@ -9,17 +11,9 @@ from iam_validator.core.models import Statement, ValidationIssue
9
11
  class WildcardResourceCheck(PolicyCheck):
10
12
  """Checks for wildcard resources (Resource: '*') which grant access to all resources."""
11
13
 
12
- @property
13
- def check_id(self) -> str:
14
- return "wildcard_resource"
15
-
16
- @property
17
- def description(self) -> str:
18
- return "Checks for wildcard resources (*)"
19
-
20
- @property
21
- def default_severity(self) -> str:
22
- return "medium"
14
+ check_id: ClassVar[str] = "wildcard_resource"
15
+ description: ClassVar[str] = "Checks for wildcard resources (*)"
16
+ default_severity: ClassVar[str] = "medium"
23
17
 
24
18
  async def execute(
25
19
  self,
@@ -62,7 +56,9 @@ class WildcardResourceCheck(PolicyCheck):
62
56
  return issues
63
57
 
64
58
  # Flag the issue if actions are not all allowed or no allowed_wildcards configured
65
- message = config.config.get("message", "Statement applies to all resources (*)")
59
+ message = config.config.get(
60
+ "message", 'Statement applies to all resources `"*"` (wildcard resource).'
61
+ )
66
62
  suggestion = config.config.get(
67
63
  "suggestion", "Replace wildcard with specific resource ARNs"
68
64
  )
@@ -8,7 +8,8 @@ from rich.console import Console
8
8
  from rich.table import Table
9
9
 
10
10
  from iam_validator.commands.base import Command
11
- from iam_validator.core.aws_fetcher import AWSServiceFetcher
11
+ from iam_validator.core.aws_service import AWSServiceFetcher
12
+ from iam_validator.core.aws_service.storage import ServiceFileStorage
12
13
  from iam_validator.core.config.config_loader import ConfigLoader
13
14
 
14
15
  logger = logging.getLogger(__name__)
@@ -130,7 +131,7 @@ Examples:
130
131
  cache_ttl_seconds = cache_ttl_hours * 3600
131
132
 
132
133
  # Get cache directory (even if caching is disabled, for info purposes)
133
- cache_dir = AWSServiceFetcher._get_cache_directory(cache_directory)
134
+ cache_dir = ServiceFileStorage.get_cache_directory(cache_directory)
134
135
 
135
136
  action = args.cache_action
136
137
 
@@ -226,7 +227,7 @@ Examples:
226
227
  services.append({"name": name, "size": size, "file": f.name, "mtime": mtime})
227
228
 
228
229
  # Sort by service name
229
- services.sort(key=lambda x: x["name"])
230
+ services.sort(key=lambda x: str(x["name"]))
230
231
 
231
232
  if output_format == "table":
232
233
  self._print_services_table(services)
@@ -44,6 +44,9 @@ Examples:
44
44
  # Use custom checks from a directory
45
45
  iam-validator validate --path ./policies/ --custom-checks-dir ./my-checks
46
46
 
47
+ # Use offline mode with pre-downloaded AWS service definitions
48
+ iam-validator validate --path ./policies/ --aws-services-dir ./aws_services
49
+
47
50
  # Generate JSON output
48
51
  iam-validator validate --path ./policies/ --format json --output report.json
49
52
 
@@ -114,13 +117,17 @@ Examples:
114
117
  choices=[
115
118
  "IDENTITY_POLICY",
116
119
  "RESOURCE_POLICY",
120
+ "TRUST_POLICY",
117
121
  "SERVICE_CONTROL_POLICY",
118
122
  "RESOURCE_CONTROL_POLICY",
119
123
  ],
120
124
  default="IDENTITY_POLICY",
121
125
  help="Type of IAM policy being validated (default: IDENTITY_POLICY). "
122
- "Enables policy-type-specific validation (e.g., requiring Principal for resource policies, "
123
- "strict RCP requirements for resource control policies)",
126
+ "IDENTITY_POLICY: Attached to users/groups/roles | "
127
+ "RESOURCE_POLICY: S3/SNS/SQS policies | "
128
+ "TRUST_POLICY: Role assumption policies | "
129
+ "SERVICE_CONTROL_POLICY: AWS Orgs SCPs | "
130
+ "RESOURCE_CONTROL_POLICY: AWS Orgs RCPs",
124
131
  )
125
132
 
126
133
  parser.add_argument(
@@ -160,9 +167,10 @@ Examples:
160
167
  )
161
168
 
162
169
  parser.add_argument(
163
- "--no-registry",
164
- action="store_true",
165
- help="Use legacy validation (disable check registry system)",
170
+ "--aws-services-dir",
171
+ help="Path to directory containing pre-downloaded AWS service definitions "
172
+ "(enables offline mode, avoids API rate limiting). "
173
+ "Use 'iam-validator download-services' to create this directory.",
166
174
  )
167
175
 
168
176
  parser.add_argument(
@@ -242,16 +250,16 @@ Examples:
242
250
  logging.info(f"Loaded {len(policies)} policies from {len(args.paths)} path(s)")
243
251
 
244
252
  # Validate policies
245
- use_registry = not getattr(args, "no_registry", False)
246
253
  config_path = getattr(args, "config", None)
247
254
  custom_checks_dir = getattr(args, "custom_checks_dir", None)
255
+ aws_services_dir = getattr(args, "aws_services_dir", None)
248
256
  policy_type = cast(PolicyType, getattr(args, "policy_type", "IDENTITY_POLICY"))
249
257
  results = await validate_policies(
250
258
  policies,
251
259
  config_path=config_path,
252
- use_registry=use_registry,
253
260
  custom_checks_dir=custom_checks_dir,
254
261
  policy_type=policy_type,
262
+ aws_services_dir=aws_services_dir,
255
263
  )
256
264
 
257
265
  # Generate report (include parsing errors if any)
@@ -329,7 +337,6 @@ Examples:
329
337
  """
330
338
  loader = PolicyLoader()
331
339
  generator = ReportGenerator()
332
- use_registry = not getattr(args, "no_registry", False)
333
340
  config_path = getattr(args, "config", None)
334
341
  custom_checks_dir = getattr(args, "custom_checks_dir", None)
335
342
  policy_type = cast(PolicyType, getattr(args, "policy_type", "IDENTITY_POLICY"))
@@ -354,7 +361,6 @@ Examples:
354
361
  results = await validate_policies(
355
362
  [(file_path, policy)],
356
363
  config_path=config_path,
357
- use_registry=use_registry,
358
364
  custom_checks_dir=custom_checks_dir,
359
365
  policy_type=policy_type,
360
366
  )
@@ -1,13 +1,12 @@
1
1
  """Core validation modules."""
2
2
 
3
- from iam_validator.core.aws_fetcher import AWSServiceFetcher
4
- from iam_validator.core.policy_checks import PolicyValidator, validate_policies
3
+ from iam_validator.core.aws_service import AWSServiceFetcher
4
+ from iam_validator.core.policy_checks import validate_policies
5
5
  from iam_validator.core.policy_loader import PolicyLoader
6
6
  from iam_validator.core.report import ReportGenerator
7
7
 
8
8
  __all__ = [
9
9
  "AWSServiceFetcher",
10
- "PolicyValidator",
11
10
  "validate_policies",
12
11
  "PolicyLoader",
13
12
  "ReportGenerator",
@@ -577,7 +577,7 @@ class AccessAnalyzerValidator:
577
577
  )
578
578
  results.append(result)
579
579
 
580
- except Exception as e:
580
+ except Exception as e: # pylint: disable=broad-exception-caught
581
581
  self.logger.error(f"Failed to validate {policy_file}: {e}")
582
582
  result = AccessAnalyzerResult(
583
583
  policy_file=policy_file,
@@ -259,7 +259,7 @@ class AccessAnalyzerReportFormatter:
259
259
  file_path: Path to save JSON report
260
260
  """
261
261
  json_content = self.generate_json_report(report)
262
- with open(file_path, "w") as f:
262
+ with open(file_path, "w", encoding="utf-8") as f:
263
263
  f.write(json_content)
264
264
 
265
265
  def generate_markdown_report(
@@ -636,5 +636,5 @@ class AccessAnalyzerReportFormatter:
636
636
  file_path: Path to save Markdown report
637
637
  """
638
638
  markdown_content = self.generate_markdown_report(report)
639
- with open(file_path, "w") as f:
639
+ with open(file_path, "w", encoding="utf-8") as f:
640
640
  f.write(markdown_content)