iam-policy-validator 1.14.6__py3-none-any.whl → 1.15.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 (43) hide show
  1. {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/METADATA +34 -23
  2. {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/RECORD +42 -29
  3. iam_policy_validator-1.15.0.dist-info/entry_points.txt +4 -0
  4. iam_validator/__version__.py +1 -1
  5. iam_validator/checks/__init__.py +2 -0
  6. iam_validator/checks/action_validation.py +91 -27
  7. iam_validator/checks/not_action_not_resource.py +163 -0
  8. iam_validator/checks/resource_validation.py +132 -81
  9. iam_validator/checks/wildcard_resource.py +136 -6
  10. iam_validator/commands/__init__.py +3 -0
  11. iam_validator/commands/cache.py +66 -24
  12. iam_validator/commands/completion.py +94 -15
  13. iam_validator/commands/mcp.py +210 -0
  14. iam_validator/commands/query.py +489 -65
  15. iam_validator/core/aws_service/__init__.py +5 -1
  16. iam_validator/core/aws_service/cache.py +20 -0
  17. iam_validator/core/aws_service/fetcher.py +180 -11
  18. iam_validator/core/aws_service/storage.py +14 -6
  19. iam_validator/core/aws_service/validators.py +32 -41
  20. iam_validator/core/check_registry.py +100 -35
  21. iam_validator/core/config/aws_global_conditions.py +13 -0
  22. iam_validator/core/config/check_documentation.py +104 -51
  23. iam_validator/core/config/config_loader.py +39 -3
  24. iam_validator/core/config/defaults.py +6 -0
  25. iam_validator/core/constants.py +11 -4
  26. iam_validator/core/models.py +39 -14
  27. iam_validator/mcp/__init__.py +162 -0
  28. iam_validator/mcp/models.py +118 -0
  29. iam_validator/mcp/server.py +2928 -0
  30. iam_validator/mcp/session_config.py +319 -0
  31. iam_validator/mcp/templates/__init__.py +79 -0
  32. iam_validator/mcp/templates/builtin.py +856 -0
  33. iam_validator/mcp/tools/__init__.py +72 -0
  34. iam_validator/mcp/tools/generation.py +888 -0
  35. iam_validator/mcp/tools/org_config_tools.py +263 -0
  36. iam_validator/mcp/tools/query.py +395 -0
  37. iam_validator/mcp/tools/validation.py +376 -0
  38. iam_validator/sdk/__init__.py +64 -63
  39. iam_validator/sdk/context.py +3 -2
  40. iam_validator/sdk/policy_utils.py +31 -5
  41. iam_policy_validator-1.14.6.dist-info/entry_points.txt +0 -2
  42. {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/WHEEL +0 -0
  43. {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,6 +6,8 @@ The generated scripts provide intelligent autocompletion for:
6
6
  - Command options (--service, --access-level, etc.)
7
7
  - Cached AWS service names (for --service flag)
8
8
 
9
+ Both `iam-validator` and `iam-policy-validator` commands are supported.
10
+
9
11
  Usage:
10
12
  # Bash completion
11
13
  iam-validator completion bash > ~/.bash_completion.d/iam-validator
@@ -135,7 +137,7 @@ _iam_validator_completion() {{
135
137
  prev="${{COMP_WORDS[COMP_CWORD-1]}}"
136
138
 
137
139
  # Main commands
138
- local commands="validate post-to-pr analyze cache sync-services query completion"
140
+ local commands="validate post-to-pr analyze cache sync-services query completion mcp"
139
141
 
140
142
  # Get the command (first non-option argument)
141
143
  local cmd=""
@@ -186,7 +188,7 @@ _iam_validator_completion() {{
186
188
  COMPREPLY=( $(compgen -f -- "$cur") )
187
189
  return 0
188
190
  ;;
189
- --resource-type|--condition|--name|--batch-size)
191
+ --resource-type|--condition|--name|--batch-size|--host|--port)
190
192
  # Allow any input
191
193
  return 0
192
194
  ;;
@@ -194,8 +196,23 @@ _iam_validator_completion() {{
194
196
  COMPREPLY=( $(compgen -W "bash zsh" -- "$cur") )
195
197
  return 0
196
198
  ;;
199
+ --transport)
200
+ COMPREPLY=( $(compgen -W "stdio sse" -- "$cur") )
201
+ return 0
202
+ ;;
203
+ --config)
204
+ # File completion for config
205
+ COMPREPLY=( $(compgen -f -- "$cur") )
206
+ return 0
207
+ ;;
197
208
  esac
198
209
 
210
+ # Handle cache list --format specifically
211
+ if [[ "$cmd" == "cache" && "$prev" == "--format" ]]; then
212
+ COMPREPLY=( $(compgen -W "table columns simple" -- "$cur") )
213
+ return 0
214
+ fi
215
+
199
216
  # Command-specific completions
200
217
  case "$cmd" in
201
218
  query)
@@ -215,10 +232,12 @@ _iam_validator_completion() {{
215
232
  fi
216
233
 
217
234
  # Complete options for query subcommands
235
+ # Note: --service is optional if --name includes service prefix (e.g., s3:GetObject)
236
+ # Note: --name accepts multiple values and supports wildcards
218
237
  local opts=""
219
238
  case "$query_subcmd" in
220
239
  action)
221
- opts="--service --name --access-level --resource-type --condition --output"
240
+ opts="--service --name --access-level --resource-type --condition --output --show-condition-keys --show-resource-types --show-access-level"
222
241
  ;;
223
242
  arn)
224
243
  opts="--service --name --list-arn-types --output"
@@ -276,7 +295,16 @@ _iam_validator_completion() {{
276
295
  COMPREPLY=( $(compgen -W "info list clear refresh prefetch location" -- "$cur") )
277
296
  return 0
278
297
  fi
279
- # Cache subcommands have no additional options
298
+
299
+ # Cache subcommand-specific options
300
+ case "$cache_subcmd" in
301
+ list)
302
+ COMPREPLY=( $(compgen -W "--config --format" -- "$cur") )
303
+ ;;
304
+ info|clear|refresh|prefetch|location)
305
+ COMPREPLY=( $(compgen -W "--config" -- "$cur") )
306
+ ;;
307
+ esac
280
308
  return 0
281
309
  ;;
282
310
  sync-services)
@@ -284,12 +312,18 @@ _iam_validator_completion() {{
284
312
  COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
285
313
  return 0
286
314
  ;;
315
+ mcp)
316
+ opts="--transport --host --port --verbose -v --config --instructions --instructions-file"
317
+ COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
318
+ return 0
319
+ ;;
287
320
  esac
288
321
 
289
322
  return 0
290
323
  }}
291
324
 
292
325
  complete -F _iam_validator_completion iam-validator
326
+ complete -F _iam_validator_completion iam-policy-validator
293
327
  '''
294
328
 
295
329
  def _generate_zsh_completion(self) -> str:
@@ -302,8 +336,8 @@ complete -F _iam_validator_completion iam-validator
302
336
  # For zsh, we need to format as: 'service1' 'service2' ...
303
337
  services_list = " ".join(f"'{svc}'" for svc in cached_services) if cached_services else ""
304
338
 
305
- return f"""#compdef iam-validator
306
- # Zsh completion for iam-validator
339
+ return f"""#compdef iam-validator iam-policy-validator
340
+ # Zsh completion for iam-validator and iam-policy-validator
307
341
  # Generated by: iam-validator completion zsh
308
342
 
309
343
  _iam_validator() {{
@@ -332,24 +366,27 @@ _iam_validator() {{
332
366
  case $words[1] in
333
367
  action)
334
368
  _arguments \\
335
- '--service[AWS service name]:service:($aws_services)' \\
336
- '--name[Action name]:action name:' \\
369
+ '--service[AWS service (optional if --name has prefix)]:service:($aws_services)' \\
370
+ '*--name[Action name(s) - supports multiple values and wildcards]:action name:' \\
337
371
  '--access-level[Filter by access level]:access level:(read write list tagging permissions-management)' \\
338
372
  '--resource-type[Filter by resource type]:resource type:' \\
339
373
  '--condition[Filter by condition key]:condition key:' \\
340
- '--output[Output format]:format:(json yaml text)'
374
+ '--output[Output format]:format:(json yaml text)' \\
375
+ '--show-condition-keys[Show only condition keys for each action]' \\
376
+ '--show-resource-types[Show only resource types for each action]' \\
377
+ '--show-access-level[Show only access level for each action]'
341
378
  ;;
342
379
  arn)
343
380
  _arguments \\
344
- '--service[AWS service name]:service:($aws_services)' \\
345
- '--name[ARN resource type]:arn type:' \\
381
+ '--service[AWS service (optional if --name has prefix)]:service:($aws_services)' \\
382
+ '--name[ARN type (e.g., bucket or s3:bucket)]:arn type:' \\
346
383
  '--list-arn-types[List all ARN types]' \\
347
384
  '--output[Output format]:format:(json yaml text)'
348
385
  ;;
349
386
  condition)
350
387
  _arguments \\
351
- '--service[AWS service name]:service:($aws_services)' \\
352
- '--name[Condition key name]:condition key:' \\
388
+ '--service[AWS service (optional if --name has prefix)]:service:($aws_services)' \\
389
+ '--name[Condition key (e.g., prefix or s3:prefix)]:condition key:' \\
353
390
  '--output[Output format]:format:(json yaml text)'
354
391
  ;;
355
392
  esac
@@ -414,8 +451,26 @@ _iam_validator() {{
414
451
  '(--verbose -v)'{{--verbose,-v}}'[Enable verbose logging]'
415
452
  ;;
416
453
  cache)
417
- _arguments \\
418
- '1: :(info list clear refresh prefetch location)'
454
+ local cache_state
455
+ _arguments -C \\
456
+ '1: :_iam_validator_cache_subcommands' \\
457
+ '*::arg:->cache_args' && return 0
458
+
459
+ case $state in
460
+ cache_args)
461
+ case $words[1] in
462
+ info|clear|refresh|prefetch|location)
463
+ _arguments \\
464
+ '--config[Configuration file]:file:_files'
465
+ ;;
466
+ list)
467
+ _arguments \\
468
+ '--config[Configuration file]:file:_files' \\
469
+ '--format[Output format]:format:(table columns simple)'
470
+ ;;
471
+ esac
472
+ ;;
473
+ esac
419
474
  ;;
420
475
  sync-services)
421
476
  _arguments \\
@@ -426,6 +481,16 @@ _iam_validator() {{
426
481
  _arguments \\
427
482
  '1: :(bash zsh)'
428
483
  ;;
484
+ mcp)
485
+ _arguments \\
486
+ '--transport[Transport protocol]:transport:(stdio sse)' \\
487
+ '--host[Host for SSE transport]:host:' \\
488
+ '--port[Port for SSE transport]:port:' \\
489
+ '(--verbose -v)'{{--verbose,-v}}'[Enable verbose logging]' \\
490
+ '--config[Path to configuration YAML file]:file:_files' \\
491
+ '--instructions[Custom instructions for policy generation]:text:' \\
492
+ '--instructions-file[Path to file containing custom instructions]:file:_files'
493
+ ;;
429
494
  esac
430
495
  ;;
431
496
  esac
@@ -441,6 +506,7 @@ _iam_validator_commands() {{
441
506
  'sync-services:Sync/download all AWS service definitions for offline use'
442
507
  'query:Query AWS service definitions (actions, ARNs, condition keys)'
443
508
  'completion:Generate shell completion scripts (bash or zsh)'
509
+ 'mcp:Start MCP server for AI assistant integration'
444
510
  )
445
511
  _describe 'command' commands
446
512
  }}
@@ -455,6 +521,19 @@ _iam_validator_query_subcommands() {{
455
521
  _describe 'query subcommand' subcommands
456
522
  }}
457
523
 
524
+ _iam_validator_cache_subcommands() {{
525
+ local -a subcommands
526
+ subcommands=(
527
+ 'info:Show cache information and statistics'
528
+ 'list:List all cached AWS services'
529
+ 'clear:Clear all cached AWS service definitions'
530
+ 'refresh:Refresh all cached services with fresh data'
531
+ 'prefetch:Pre-fetch common AWS services (without clearing)'
532
+ 'location:Show cache directory location'
533
+ )
534
+ _describe 'cache subcommand' subcommands
535
+ }}
536
+
458
537
  _iam_validator "$@"
459
538
  """
460
539
 
@@ -0,0 +1,210 @@
1
+ """MCP command for IAM Policy Validator."""
2
+
3
+ import argparse
4
+ import logging
5
+
6
+ from iam_validator.commands.base import Command
7
+
8
+
9
+ class MCPCommand(Command):
10
+ """Command to start MCP server for AI assistant integration."""
11
+
12
+ @property
13
+ def name(self) -> str:
14
+ return "mcp"
15
+
16
+ @property
17
+ def help(self) -> str:
18
+ return "Start MCP server for AI assistant integration"
19
+
20
+ @property
21
+ def epilog(self) -> str:
22
+ return """
23
+ Examples:
24
+ # Start MCP server with stdio transport (for Claude Desktop)
25
+ iam-validator mcp
26
+
27
+ # Start with SSE transport on custom host/port
28
+ iam-validator mcp --transport sse --host 127.0.0.1 --port 8000
29
+
30
+ # Start with config preloaded
31
+ iam-validator mcp --config ./config.yaml
32
+
33
+ Claude Desktop Configuration:
34
+ Add to your claude_desktop_config.json:
35
+ {
36
+ "mcpServers": {
37
+ "iam-validator": {
38
+ "command": "iam-validator",
39
+ "args": ["mcp"]
40
+ }
41
+ }
42
+ }
43
+
44
+ With configuration:
45
+ {
46
+ "mcpServers": {
47
+ "iam-validator": {
48
+ "command": "iam-validator",
49
+ "args": ["mcp", "--config", "/path/to/config.yaml"]
50
+ }
51
+ }
52
+ }
53
+
54
+ Config File (YAML) - same format as CLI validator:
55
+ settings:
56
+ fail_on_severity: [error, critical, high]
57
+ wildcard_resource:
58
+ severity: critical
59
+ sensitive_action:
60
+ enabled: true
61
+ severity: high
62
+
63
+ Features:
64
+ - Policy generation from natural language descriptions
65
+ - Template-based policy generation (15 built-in templates)
66
+ - Policy validation with 19 security checks
67
+ - AWS service queries (actions, resources, condition keys)
68
+ - Security enforcement (auto-adds required conditions)
69
+ - Session-wide configuration management
70
+ """
71
+
72
+ def add_arguments(self, parser: argparse.ArgumentParser) -> None:
73
+ """Add MCP command arguments."""
74
+ parser.add_argument(
75
+ "--transport",
76
+ choices=["stdio", "sse"],
77
+ default="stdio",
78
+ help="Transport protocol (default: stdio for Claude Desktop, sse for HTTP/SSE)",
79
+ )
80
+
81
+ parser.add_argument(
82
+ "--host",
83
+ default="127.0.0.1",
84
+ help="Host for SSE transport (default: 127.0.0.1)",
85
+ )
86
+
87
+ parser.add_argument(
88
+ "--port",
89
+ type=int,
90
+ default=8000,
91
+ help="Port for SSE transport (default: 8000)",
92
+ )
93
+
94
+ parser.add_argument(
95
+ "--verbose",
96
+ "-v",
97
+ action="store_true",
98
+ help="Enable verbose logging",
99
+ )
100
+
101
+ parser.add_argument(
102
+ "--config",
103
+ type=str,
104
+ metavar="FILE",
105
+ help="Path to configuration YAML file to load at startup",
106
+ )
107
+
108
+ async def execute(self, args: argparse.Namespace) -> int:
109
+ """Execute the MCP server command.
110
+
111
+ Args:
112
+ args: Parsed command-line arguments
113
+
114
+ Returns:
115
+ Exit code (0 for success, non-zero for failure)
116
+ """
117
+ # Check if fastmcp is installed
118
+ try:
119
+ import fastmcp # noqa: F401
120
+ except ImportError:
121
+ logging.error(
122
+ "FastMCP is not installed. Install with: uv sync --extra mcp or pip install 'iam-validator[mcp]'"
123
+ )
124
+ return 1
125
+
126
+ # Import and create the MCP server
127
+ try:
128
+ from iam_validator.mcp import create_server
129
+ except ImportError as e:
130
+ logging.error(f"Failed to import MCP server: {e}")
131
+ logging.error(
132
+ "Make sure the MCP module is properly installed with: uv sync --extra mcp"
133
+ )
134
+ return 1
135
+
136
+ # Set up logging level
137
+ if args.verbose:
138
+ logging.basicConfig(level=logging.DEBUG)
139
+ else:
140
+ logging.basicConfig(level=logging.INFO)
141
+
142
+ # Load config if provided
143
+ if args.config:
144
+ try:
145
+ from pathlib import Path
146
+
147
+ from iam_validator.mcp.session_config import SessionConfigManager
148
+
149
+ config_path = Path(args.config)
150
+ if not config_path.exists():
151
+ logging.error(f"Config file not found: {args.config}")
152
+ return 1
153
+
154
+ config, warnings = SessionConfigManager.load_from_file(str(config_path))
155
+
156
+ for warning in warnings:
157
+ logging.warning(f"Config warning: {warning}")
158
+
159
+ logging.info(f"Loaded config from: {args.config}")
160
+
161
+ # Log config summary
162
+ if config.settings:
163
+ fail_on = config.settings.get("fail_on_severity", [])
164
+ if fail_on:
165
+ logging.info(f" Fail on severity: {fail_on}")
166
+
167
+ if config.checks_config:
168
+ disabled_checks = [
169
+ k for k, v in config.checks_config.items() if not v.get("enabled", True)
170
+ ]
171
+ if disabled_checks:
172
+ logging.info(f" Disabled checks: {disabled_checks}")
173
+
174
+ except Exception as e:
175
+ logging.error(f"Failed to load config: {e}")
176
+ if args.verbose:
177
+ import traceback
178
+
179
+ traceback.print_exc()
180
+ return 1
181
+
182
+ try:
183
+ # Create and run the server
184
+ server = create_server()
185
+
186
+ if args.transport == "stdio":
187
+ logging.info("Starting MCP server with stdio transport...")
188
+ logging.info("Waiting for client connection...")
189
+ # Run with stdio transport using async method
190
+ await server.run_stdio_async()
191
+ else:
192
+ # SSE transport
193
+ logging.info(
194
+ f"Starting MCP server with SSE transport on {args.host}:{args.port}..."
195
+ )
196
+ # Run with SSE transport using async method
197
+ await server.run_http_async(host=args.host, port=args.port)
198
+
199
+ return 0
200
+
201
+ except KeyboardInterrupt:
202
+ logging.info("\nMCP server stopped by user")
203
+ return 0
204
+ except Exception as e:
205
+ logging.error(f"Failed to start MCP server: {e}")
206
+ if args.verbose:
207
+ import traceback
208
+
209
+ traceback.print_exc()
210
+ return 1