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.
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/METADATA +34 -23
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/RECORD +42 -29
- iam_policy_validator-1.15.0.dist-info/entry_points.txt +4 -0
- iam_validator/__version__.py +1 -1
- iam_validator/checks/__init__.py +2 -0
- iam_validator/checks/action_validation.py +91 -27
- iam_validator/checks/not_action_not_resource.py +163 -0
- iam_validator/checks/resource_validation.py +132 -81
- iam_validator/checks/wildcard_resource.py +136 -6
- iam_validator/commands/__init__.py +3 -0
- iam_validator/commands/cache.py +66 -24
- iam_validator/commands/completion.py +94 -15
- iam_validator/commands/mcp.py +210 -0
- iam_validator/commands/query.py +489 -65
- iam_validator/core/aws_service/__init__.py +5 -1
- iam_validator/core/aws_service/cache.py +20 -0
- iam_validator/core/aws_service/fetcher.py +180 -11
- iam_validator/core/aws_service/storage.py +14 -6
- iam_validator/core/aws_service/validators.py +32 -41
- iam_validator/core/check_registry.py +100 -35
- iam_validator/core/config/aws_global_conditions.py +13 -0
- iam_validator/core/config/check_documentation.py +104 -51
- iam_validator/core/config/config_loader.py +39 -3
- iam_validator/core/config/defaults.py +6 -0
- iam_validator/core/constants.py +11 -4
- iam_validator/core/models.py +39 -14
- iam_validator/mcp/__init__.py +162 -0
- iam_validator/mcp/models.py +118 -0
- iam_validator/mcp/server.py +2928 -0
- iam_validator/mcp/session_config.py +319 -0
- iam_validator/mcp/templates/__init__.py +79 -0
- iam_validator/mcp/templates/builtin.py +856 -0
- iam_validator/mcp/tools/__init__.py +72 -0
- iam_validator/mcp/tools/generation.py +888 -0
- iam_validator/mcp/tools/org_config_tools.py +263 -0
- iam_validator/mcp/tools/query.py +395 -0
- iam_validator/mcp/tools/validation.py +376 -0
- iam_validator/sdk/__init__.py +64 -63
- iam_validator/sdk/context.py +3 -2
- iam_validator/sdk/policy_utils.py +31 -5
- iam_policy_validator-1.14.6.dist-info/entry_points.txt +0 -2
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""IAM Policy Validator MCP Server.
|
|
2
|
+
|
|
3
|
+
This module provides an MCP (Model Context Protocol) server for AI assistants
|
|
4
|
+
to interact with the IAM Policy Validator. It exposes tools for:
|
|
5
|
+
- Validating IAM policies
|
|
6
|
+
- Generating policies from templates or descriptions
|
|
7
|
+
- Querying AWS service definitions
|
|
8
|
+
- Managing session-wide policy configurations
|
|
9
|
+
|
|
10
|
+
The server uses FastMCP and provides a security-first approach to policy generation.
|
|
11
|
+
|
|
12
|
+
Configuration:
|
|
13
|
+
The MCP server uses the same configuration format as the CLI validator.
|
|
14
|
+
You can load configuration from a YAML file using --config or set it
|
|
15
|
+
programmatically using SessionConfigManager.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from iam_validator.mcp.models import (
|
|
21
|
+
ActionDetails,
|
|
22
|
+
GenerationResult,
|
|
23
|
+
PolicySummary,
|
|
24
|
+
ValidationResult,
|
|
25
|
+
)
|
|
26
|
+
from iam_validator.mcp.session_config import (
|
|
27
|
+
CustomInstructionsManager,
|
|
28
|
+
SessionConfigManager,
|
|
29
|
+
merge_conditions,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from fastmcp import FastMCP
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def create_server() -> "FastMCP":
|
|
37
|
+
"""Create and configure the MCP server.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
FastMCP: Configured MCP server instance
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ImportError: If fastmcp is not installed
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
from iam_validator.mcp.server import create_server as _create_server
|
|
47
|
+
|
|
48
|
+
return _create_server()
|
|
49
|
+
except ImportError as e:
|
|
50
|
+
raise ImportError(
|
|
51
|
+
"fastmcp is required for MCP server. Install with: uv sync --extra mcp"
|
|
52
|
+
) from e
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def run_server() -> None:
|
|
56
|
+
"""Run the MCP server.
|
|
57
|
+
|
|
58
|
+
This is the entry point for the iam-validator-mcp command.
|
|
59
|
+
Supports configuration and custom instructions at startup.
|
|
60
|
+
|
|
61
|
+
Usage:
|
|
62
|
+
iam-validator-mcp
|
|
63
|
+
iam-validator-mcp --config /path/to/config.yaml
|
|
64
|
+
iam-validator-mcp --instructions "Always require MFA for sensitive actions"
|
|
65
|
+
iam-validator-mcp --instructions-file /path/to/instructions.md
|
|
66
|
+
|
|
67
|
+
Custom instructions can also be set via:
|
|
68
|
+
- Environment variable: IAM_VALIDATOR_MCP_INSTRUCTIONS
|
|
69
|
+
- Config file: custom_instructions key in YAML config
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ImportError: If fastmcp is not installed
|
|
73
|
+
"""
|
|
74
|
+
import argparse
|
|
75
|
+
import sys
|
|
76
|
+
from pathlib import Path
|
|
77
|
+
|
|
78
|
+
parser = argparse.ArgumentParser(
|
|
79
|
+
prog="iam-validator-mcp",
|
|
80
|
+
description="IAM Policy Validator MCP Server for AI assistants",
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"--config",
|
|
84
|
+
type=str,
|
|
85
|
+
metavar="FILE",
|
|
86
|
+
help="Path to configuration YAML file to load at startup",
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--instructions",
|
|
90
|
+
type=str,
|
|
91
|
+
metavar="TEXT",
|
|
92
|
+
help="Custom instructions to append to default LLM instructions",
|
|
93
|
+
)
|
|
94
|
+
parser.add_argument(
|
|
95
|
+
"--instructions-file",
|
|
96
|
+
type=str,
|
|
97
|
+
metavar="FILE",
|
|
98
|
+
help="Path to file containing custom instructions (markdown, txt)",
|
|
99
|
+
)
|
|
100
|
+
args = parser.parse_args()
|
|
101
|
+
|
|
102
|
+
# Load config if provided (may include custom_instructions)
|
|
103
|
+
if args.config:
|
|
104
|
+
config_path = Path(args.config)
|
|
105
|
+
if not config_path.exists():
|
|
106
|
+
print(f"Error: Config file not found: {args.config}", file=sys.stderr)
|
|
107
|
+
sys.exit(1)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
config, warnings = SessionConfigManager.load_from_file(str(config_path))
|
|
111
|
+
|
|
112
|
+
for warning in warnings:
|
|
113
|
+
print(f"Warning: {warning}", file=sys.stderr)
|
|
114
|
+
|
|
115
|
+
print(f"Loaded config from: {args.config}", file=sys.stderr)
|
|
116
|
+
|
|
117
|
+
except Exception as e:
|
|
118
|
+
print(f"Error loading config: {e}", file=sys.stderr)
|
|
119
|
+
sys.exit(1)
|
|
120
|
+
|
|
121
|
+
# Load custom instructions from CLI arguments (overrides config/env)
|
|
122
|
+
if args.instructions_file:
|
|
123
|
+
instructions_path = Path(args.instructions_file)
|
|
124
|
+
if not instructions_path.exists():
|
|
125
|
+
print(
|
|
126
|
+
f"Error: Instructions file not found: {args.instructions_file}",
|
|
127
|
+
file=sys.stderr,
|
|
128
|
+
)
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
CustomInstructionsManager.load_from_file(str(instructions_path))
|
|
133
|
+
print(f"Loaded instructions from: {args.instructions_file}", file=sys.stderr)
|
|
134
|
+
except Exception as e:
|
|
135
|
+
print(f"Error loading instructions: {e}", file=sys.stderr)
|
|
136
|
+
sys.exit(1)
|
|
137
|
+
|
|
138
|
+
elif args.instructions:
|
|
139
|
+
CustomInstructionsManager.set_instructions(args.instructions, source="cli")
|
|
140
|
+
print("Custom instructions set from CLI argument", file=sys.stderr)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
from iam_validator.mcp.server import run_server as _run_server
|
|
144
|
+
|
|
145
|
+
_run_server()
|
|
146
|
+
except ImportError as e:
|
|
147
|
+
raise ImportError(
|
|
148
|
+
"fastmcp is required for MCP server. Install with: uv sync --extra mcp"
|
|
149
|
+
) from e
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
__all__ = [
|
|
153
|
+
"create_server",
|
|
154
|
+
"run_server",
|
|
155
|
+
"ValidationResult",
|
|
156
|
+
"GenerationResult",
|
|
157
|
+
"PolicySummary",
|
|
158
|
+
"ActionDetails",
|
|
159
|
+
"SessionConfigManager",
|
|
160
|
+
"CustomInstructionsManager",
|
|
161
|
+
"merge_conditions",
|
|
162
|
+
]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Pydantic models for MCP tool request/response types.
|
|
2
|
+
|
|
3
|
+
This module defines MCP-specific models that extend the core validation models
|
|
4
|
+
for use with the FastMCP server implementation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from iam_validator.core.models import ValidationIssue
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ValidationResult(BaseModel):
|
|
15
|
+
"""Result of policy validation.
|
|
16
|
+
|
|
17
|
+
Used by validation tools to return validation status and issues found.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
is_valid: bool = Field(
|
|
21
|
+
description="Whether the policy passed validation (no errors or warnings)"
|
|
22
|
+
)
|
|
23
|
+
issues: list[ValidationIssue] = Field(
|
|
24
|
+
default_factory=list, description="List of validation issues found"
|
|
25
|
+
)
|
|
26
|
+
policy_file: str | None = Field(
|
|
27
|
+
default=None, description="Path to the policy file that was validated"
|
|
28
|
+
)
|
|
29
|
+
policy_type_detected: str | None = Field(
|
|
30
|
+
default=None,
|
|
31
|
+
description="The policy type used for validation: 'identity', 'resource', or 'trust'. "
|
|
32
|
+
"Shows auto-detected type when policy_type was not explicitly provided.",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GenerationResult(BaseModel):
|
|
37
|
+
"""Result of policy generation.
|
|
38
|
+
|
|
39
|
+
Returned by all policy generation tools (from description, template, or actions).
|
|
40
|
+
Always includes validation results and security notes.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
policy: dict[str, Any] = Field(description="The generated IAM policy document")
|
|
44
|
+
validation: ValidationResult = Field(description="Validation results for the generated policy")
|
|
45
|
+
security_notes: list[str] = Field(
|
|
46
|
+
default_factory=list,
|
|
47
|
+
description="Security warnings and auto-applied conditions (e.g., 'Auto-added MFA condition')",
|
|
48
|
+
)
|
|
49
|
+
template_used: str | None = Field(
|
|
50
|
+
default=None, description="Name of the template used for generation (if applicable)"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class PolicySummary(BaseModel):
|
|
55
|
+
"""Summary of a policy's structure and contents.
|
|
56
|
+
|
|
57
|
+
Provides high-level statistics about a policy for quick analysis.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
total_statements: int = Field(description="Total number of statements in the policy")
|
|
61
|
+
allow_statements: int = Field(description="Number of statements with Effect: Allow")
|
|
62
|
+
deny_statements: int = Field(description="Number of statements with Effect: Deny")
|
|
63
|
+
services_used: list[str] = Field(
|
|
64
|
+
default_factory=list, description="List of AWS services referenced (e.g., ['s3', 'ec2'])"
|
|
65
|
+
)
|
|
66
|
+
actions_count: int = Field(description="Total number of unique actions across all statements")
|
|
67
|
+
has_wildcards: bool = Field(
|
|
68
|
+
description="Whether the policy contains wildcard actions or resources"
|
|
69
|
+
)
|
|
70
|
+
has_conditions: bool = Field(description="Whether the policy contains any conditions")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ActionDetails(BaseModel):
|
|
74
|
+
"""Details about an AWS action.
|
|
75
|
+
|
|
76
|
+
Returned by query tools to provide comprehensive information about an IAM action.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
action: str = Field(description="Full action name (e.g., 's3:GetObject')")
|
|
80
|
+
service: str = Field(description="AWS service prefix (e.g., 's3', 'ec2')")
|
|
81
|
+
access_level: str = Field(
|
|
82
|
+
description="Access level category: Read, Write, List, Tagging, or Permissions management"
|
|
83
|
+
)
|
|
84
|
+
resource_types: list[str] = Field(
|
|
85
|
+
default_factory=list,
|
|
86
|
+
description="Resource types this action can be applied to (e.g., ['bucket', 'object'])",
|
|
87
|
+
)
|
|
88
|
+
condition_keys: list[str] = Field(
|
|
89
|
+
default_factory=list,
|
|
90
|
+
description="Condition keys that can be used with this action",
|
|
91
|
+
)
|
|
92
|
+
description: str | None = Field(
|
|
93
|
+
default=None, description="Human-readable description of what the action does"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class EnforcementResult(BaseModel):
|
|
98
|
+
"""Result of security enforcement on a policy.
|
|
99
|
+
|
|
100
|
+
Returned by the security enforcement layer after applying required conditions
|
|
101
|
+
and validating security constraints.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
policy: dict[str, Any] = Field(
|
|
105
|
+
description="The policy after security enforcement (with auto-added conditions)"
|
|
106
|
+
)
|
|
107
|
+
warnings: list[str] = Field(
|
|
108
|
+
default_factory=list,
|
|
109
|
+
description="Security warnings for issues that were auto-fixed (e.g., 'Added MFA condition')",
|
|
110
|
+
)
|
|
111
|
+
errors: list[str] = Field(
|
|
112
|
+
default_factory=list,
|
|
113
|
+
description="Security errors that could not be auto-fixed (generation should fail)",
|
|
114
|
+
)
|
|
115
|
+
conditions_added: list[str] = Field(
|
|
116
|
+
default_factory=list,
|
|
117
|
+
description="List of conditions that were automatically added (e.g., 'aws:MultiFactorAuthPresent')",
|
|
118
|
+
)
|