runbooks 0.7.9__py3-none-any.whl → 0.9.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 (122) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/cfat/README.md +12 -1
  3. runbooks/cfat/__init__.py +1 -1
  4. runbooks/cfat/assessment/compliance.py +4 -1
  5. runbooks/cfat/assessment/runner.py +42 -34
  6. runbooks/cfat/models.py +1 -1
  7. runbooks/cloudops/__init__.py +123 -0
  8. runbooks/cloudops/base.py +385 -0
  9. runbooks/cloudops/cost_optimizer.py +811 -0
  10. runbooks/cloudops/infrastructure_optimizer.py +29 -0
  11. runbooks/cloudops/interfaces.py +828 -0
  12. runbooks/cloudops/lifecycle_manager.py +29 -0
  13. runbooks/cloudops/mcp_cost_validation.py +678 -0
  14. runbooks/cloudops/models.py +251 -0
  15. runbooks/cloudops/monitoring_automation.py +29 -0
  16. runbooks/cloudops/notebook_framework.py +676 -0
  17. runbooks/cloudops/security_enforcer.py +449 -0
  18. runbooks/common/__init__.py +152 -0
  19. runbooks/common/accuracy_validator.py +1039 -0
  20. runbooks/common/context_logger.py +440 -0
  21. runbooks/common/cross_module_integration.py +594 -0
  22. runbooks/common/enhanced_exception_handler.py +1108 -0
  23. runbooks/common/enterprise_audit_integration.py +634 -0
  24. runbooks/common/mcp_cost_explorer_integration.py +900 -0
  25. runbooks/common/mcp_integration.py +548 -0
  26. runbooks/common/performance_monitor.py +387 -0
  27. runbooks/common/profile_utils.py +216 -0
  28. runbooks/common/rich_utils.py +172 -1
  29. runbooks/feedback/user_feedback_collector.py +440 -0
  30. runbooks/finops/README.md +377 -458
  31. runbooks/finops/__init__.py +4 -21
  32. runbooks/finops/account_resolver.py +279 -0
  33. runbooks/finops/accuracy_cross_validator.py +638 -0
  34. runbooks/finops/aws_client.py +721 -36
  35. runbooks/finops/budget_integration.py +313 -0
  36. runbooks/finops/cli.py +59 -5
  37. runbooks/finops/cost_optimizer.py +1340 -0
  38. runbooks/finops/cost_processor.py +211 -37
  39. runbooks/finops/dashboard_router.py +900 -0
  40. runbooks/finops/dashboard_runner.py +990 -232
  41. runbooks/finops/embedded_mcp_validator.py +288 -0
  42. runbooks/finops/enhanced_dashboard_runner.py +8 -7
  43. runbooks/finops/enhanced_progress.py +327 -0
  44. runbooks/finops/enhanced_trend_visualization.py +423 -0
  45. runbooks/finops/finops_dashboard.py +184 -1829
  46. runbooks/finops/helpers.py +509 -196
  47. runbooks/finops/iam_guidance.py +400 -0
  48. runbooks/finops/markdown_exporter.py +466 -0
  49. runbooks/finops/multi_dashboard.py +1502 -0
  50. runbooks/finops/optimizer.py +15 -15
  51. runbooks/finops/profile_processor.py +2 -2
  52. runbooks/finops/runbooks.inventory.organizations_discovery.log +0 -0
  53. runbooks/finops/runbooks.security.report_generator.log +0 -0
  54. runbooks/finops/runbooks.security.run_script.log +0 -0
  55. runbooks/finops/runbooks.security.security_export.log +0 -0
  56. runbooks/finops/schemas.py +589 -0
  57. runbooks/finops/service_mapping.py +195 -0
  58. runbooks/finops/single_dashboard.py +710 -0
  59. runbooks/finops/tests/test_reference_images_validation.py +1 -1
  60. runbooks/inventory/README.md +12 -1
  61. runbooks/inventory/core/collector.py +157 -29
  62. runbooks/inventory/list_ec2_instances.py +9 -6
  63. runbooks/inventory/list_ssm_parameters.py +10 -10
  64. runbooks/inventory/organizations_discovery.py +210 -164
  65. runbooks/inventory/rich_inventory_display.py +74 -107
  66. runbooks/inventory/run_on_multi_accounts.py +13 -13
  67. runbooks/inventory/runbooks.inventory.organizations_discovery.log +0 -0
  68. runbooks/inventory/runbooks.security.security_export.log +0 -0
  69. runbooks/main.py +1371 -240
  70. runbooks/metrics/dora_metrics_engine.py +711 -17
  71. runbooks/monitoring/performance_monitor.py +433 -0
  72. runbooks/operate/README.md +394 -0
  73. runbooks/operate/base.py +215 -47
  74. runbooks/operate/ec2_operations.py +435 -5
  75. runbooks/operate/iam_operations.py +598 -3
  76. runbooks/operate/privatelink_operations.py +1 -1
  77. runbooks/operate/rds_operations.py +508 -0
  78. runbooks/operate/s3_operations.py +508 -0
  79. runbooks/operate/vpc_endpoints.py +1 -1
  80. runbooks/remediation/README.md +489 -13
  81. runbooks/remediation/base.py +5 -3
  82. runbooks/remediation/commons.py +8 -4
  83. runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
  84. runbooks/security/README.md +12 -1
  85. runbooks/security/__init__.py +265 -33
  86. runbooks/security/cloudops_automation_security_validator.py +1164 -0
  87. runbooks/security/compliance_automation.py +12 -10
  88. runbooks/security/compliance_automation_engine.py +1021 -0
  89. runbooks/security/enterprise_security_framework.py +930 -0
  90. runbooks/security/enterprise_security_policies.json +293 -0
  91. runbooks/security/executive_security_dashboard.py +1247 -0
  92. runbooks/security/integration_test_enterprise_security.py +879 -0
  93. runbooks/security/module_security_integrator.py +641 -0
  94. runbooks/security/multi_account_security_controls.py +2254 -0
  95. runbooks/security/real_time_security_monitor.py +1196 -0
  96. runbooks/security/report_generator.py +1 -1
  97. runbooks/security/run_script.py +4 -8
  98. runbooks/security/security_baseline_tester.py +39 -52
  99. runbooks/security/security_export.py +99 -120
  100. runbooks/sre/README.md +472 -0
  101. runbooks/sre/__init__.py +33 -0
  102. runbooks/sre/mcp_reliability_engine.py +1049 -0
  103. runbooks/sre/performance_optimization_engine.py +1032 -0
  104. runbooks/sre/production_monitoring_framework.py +584 -0
  105. runbooks/sre/reliability_monitoring_framework.py +1011 -0
  106. runbooks/validation/__init__.py +2 -2
  107. runbooks/validation/benchmark.py +154 -149
  108. runbooks/validation/cli.py +159 -147
  109. runbooks/validation/mcp_validator.py +291 -248
  110. runbooks/vpc/README.md +478 -0
  111. runbooks/vpc/__init__.py +2 -2
  112. runbooks/vpc/manager_interface.py +366 -351
  113. runbooks/vpc/networking_wrapper.py +68 -36
  114. runbooks/vpc/rich_formatters.py +22 -8
  115. runbooks-0.9.1.dist-info/METADATA +308 -0
  116. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/RECORD +120 -59
  117. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/entry_points.txt +1 -1
  118. runbooks/finops/cross_validation.py +0 -375
  119. runbooks-0.7.9.dist-info/METADATA +0 -636
  120. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/WHEEL +0 -0
  121. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/licenses/LICENSE +0 -0
  122. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/top_level.txt +0 -0
@@ -18,60 +18,58 @@ Usage:
18
18
  import asyncio
19
19
  import sys
20
20
  from pathlib import Path
21
- from typing import Optional, List
21
+ from typing import List, Optional
22
+
22
23
  import click
24
+ from rich import box
23
25
  from rich.console import Console
24
26
  from rich.panel import Panel
25
27
  from rich.table import Table
26
- from rich import box
27
28
 
28
29
  from .mcp_validator import MCPValidator, ValidationStatus
29
30
 
30
31
  console = Console()
31
32
 
33
+
32
34
  @click.group()
33
35
  @click.version_option(version="1.0.0", prog_name="MCP Validator")
34
36
  def cli():
35
37
  """Enterprise MCP Validation Framework - 99.5% Accuracy Target"""
36
38
  pass
37
39
 
40
+
38
41
  @cli.command()
39
- @click.option('--tolerance', default=5.0, help='Tolerance percentage for variance detection')
40
- @click.option('--performance-target', default=30.0, help='Performance target in seconds')
41
- @click.option('--save-report', is_flag=True, help='Save detailed report to artifacts')
42
- @click.option('--profile', help='AWS profile override')
42
+ @click.option("--tolerance", default=5.0, help="Tolerance percentage for variance detection")
43
+ @click.option("--performance-target", default=30.0, help="Performance target in seconds")
44
+ @click.option("--save-report", is_flag=True, help="Save detailed report to artifacts")
45
+ @click.option("--profile", help="AWS profile override")
43
46
  def validate_all(tolerance: float, performance_target: float, save_report: bool, profile: Optional[str]):
44
47
  """Run comprehensive validation across all critical operations."""
45
-
46
- console.print(Panel(
47
- "[bold blue]Enterprise MCP Validation Framework[/bold blue]\n"
48
- f"Target Accuracy: 99.5% | Tolerance: ±{tolerance}% | Performance: <{performance_target}s",
49
- title="MCP Validator"
50
- ))
51
-
48
+
49
+ console.print(
50
+ Panel(
51
+ "[bold blue]Enterprise MCP Validation Framework[/bold blue]\n"
52
+ f"Target Accuracy: 99.5% | Tolerance: ±{tolerance}% | Performance: <{performance_target}s",
53
+ title="MCP Validator",
54
+ )
55
+ )
56
+
52
57
  # Initialize validator
53
58
  profiles = None
54
59
  if profile:
55
- profiles = {
56
- 'billing': profile,
57
- 'management': profile,
58
- 'centralised_ops': profile,
59
- 'single_aws': profile
60
- }
61
-
60
+ profiles = {"billing": profile, "management": profile, "centralised_ops": profile, "single_aws": profile}
61
+
62
62
  validator = MCPValidator(
63
- profiles=profiles,
64
- tolerance_percentage=tolerance,
65
- performance_target_seconds=performance_target
63
+ profiles=profiles, tolerance_percentage=tolerance, performance_target_seconds=performance_target
66
64
  )
67
-
65
+
68
66
  # Run validation
69
67
  try:
70
68
  report = asyncio.run(validator.validate_all_operations())
71
-
69
+
72
70
  # Display results
73
71
  validator.display_validation_report(report)
74
-
72
+
75
73
  # Exit code based on results
76
74
  if report.overall_accuracy >= 99.5:
77
75
  console.print("[bold green]✅ Validation PASSED - Deploy with confidence[/bold green]")
@@ -82,149 +80,154 @@ def validate_all(tolerance: float, performance_target: float, save_report: bool,
82
80
  else:
83
81
  console.print("[bold red]❌ Validation FAILED - Address issues before deployment[/bold red]")
84
82
  sys.exit(2)
85
-
83
+
86
84
  except Exception as e:
87
85
  console.print(f"[bold red]Error running validation: {e}[/bold red]")
88
86
  sys.exit(3)
89
87
 
88
+
90
89
  @cli.command()
91
- @click.option('--profile', default='ams-admin-Billing-ReadOnlyAccess-909135376185', help='AWS billing profile')
92
- @click.option('--tolerance', default=5.0, help='Cost variance tolerance percentage')
90
+ @click.option("--profile", default="ams-admin-Billing-ReadOnlyAccess-909135376185", help="AWS billing profile")
91
+ @click.option("--tolerance", default=5.0, help="Cost variance tolerance percentage")
93
92
  def validate_costs(profile: str, tolerance: float):
94
93
  """Validate Cost Explorer data accuracy."""
95
-
96
- console.print(Panel(
97
- f"[bold cyan]Cost Explorer Validation[/bold cyan]\n"
98
- f"Profile: {profile}\nTolerance: ±{tolerance}%",
99
- title="Cost Validation"
100
- ))
101
-
102
- validator = MCPValidator(
103
- profiles={'billing': profile},
104
- tolerance_percentage=tolerance
94
+
95
+ console.print(
96
+ Panel(
97
+ f"[bold cyan]Cost Explorer Validation[/bold cyan]\nProfile: {profile}\nTolerance: ±{tolerance}%",
98
+ title="Cost Validation",
99
+ )
105
100
  )
106
-
101
+
102
+ validator = MCPValidator(profiles={"billing": profile}, tolerance_percentage=tolerance)
103
+
107
104
  try:
108
105
  result = asyncio.run(validator.validate_cost_explorer())
109
-
106
+
110
107
  # Display result
111
108
  status_color = "green" if result.status == ValidationStatus.PASSED else "red"
112
-
109
+
113
110
  table = Table(title="Cost Validation Result", box=box.ROUNDED)
114
111
  table.add_column("Metric", style="cyan")
115
112
  table.add_column("Value", style="bold")
116
-
113
+
117
114
  table.add_row("Status", f"[{status_color}]{result.status.value}[/{status_color}]")
118
115
  table.add_row("Accuracy", f"{result.accuracy_percentage:.2f}%")
119
116
  table.add_row("Execution Time", f"{result.execution_time:.2f}s")
120
117
  table.add_row("Timestamp", result.timestamp.strftime("%Y-%m-%d %H:%M:%S"))
121
-
118
+
122
119
  if result.error_message:
123
120
  table.add_row("Error", f"[red]{result.error_message}[/red]")
124
-
121
+
125
122
  console.print(table)
126
-
123
+
127
124
  # Variance details
128
125
  if result.variance_details:
129
- console.print(Panel(
130
- f"Runbooks Total: {result.variance_details.get('details', {}).get('runbooks_total', 'N/A')}\n"
131
- f"MCP Available: {result.variance_details.get('details', {}).get('mcp_available', 'N/A')}",
132
- title="Variance Analysis"
133
- ))
134
-
126
+ console.print(
127
+ Panel(
128
+ f"Runbooks Total: {result.variance_details.get('details', {}).get('runbooks_total', 'N/A')}\n"
129
+ f"MCP Available: {result.variance_details.get('details', {}).get('mcp_available', 'N/A')}",
130
+ title="Variance Analysis",
131
+ )
132
+ )
133
+
135
134
  sys.exit(0 if result.status == ValidationStatus.PASSED else 1)
136
-
135
+
137
136
  except Exception as e:
138
137
  console.print(f"[bold red]Error validating costs: {e}[/bold red]")
139
138
  sys.exit(3)
140
139
 
140
+
141
141
  @cli.command()
142
- @click.option('--profile', default='ams-admin-ReadOnlyAccess-909135376185', help='AWS management profile')
142
+ @click.option("--profile", default="ams-admin-ReadOnlyAccess-909135376185", help="AWS management profile")
143
143
  def validate_organizations(profile: str):
144
144
  """Validate Organizations API data accuracy."""
145
-
146
- console.print(Panel(
147
- f"[bold cyan]Organizations Validation[/bold cyan]\n"
148
- f"Profile: {profile}",
149
- title="Organizations Validation"
150
- ))
151
-
152
- validator = MCPValidator(profiles={'management': profile})
153
-
145
+
146
+ console.print(
147
+ Panel(f"[bold cyan]Organizations Validation[/bold cyan]\nProfile: {profile}", title="Organizations Validation")
148
+ )
149
+
150
+ validator = MCPValidator(profiles={"management": profile})
151
+
154
152
  try:
155
153
  result = asyncio.run(validator.validate_organizations_data())
156
-
154
+
157
155
  # Display result
158
156
  status_color = "green" if result.status == ValidationStatus.PASSED else "red"
159
-
157
+
160
158
  table = Table(title="Organizations Validation Result", box=box.ROUNDED)
161
159
  table.add_column("Metric", style="cyan")
162
160
  table.add_column("Value", style="bold")
163
-
161
+
164
162
  table.add_row("Status", f"[{status_color}]{result.status.value}[/{status_color}]")
165
163
  table.add_row("Accuracy", f"{result.accuracy_percentage:.2f}%")
166
164
  table.add_row("Execution Time", f"{result.execution_time:.2f}s")
167
-
165
+
168
166
  if result.variance_details:
169
- details = result.variance_details.get('details', {})
170
- table.add_row("Runbooks Accounts", str(details.get('runbooks_accounts', 'N/A')))
171
- table.add_row("MCP Accounts", str(details.get('mcp_accounts', 'N/A')))
172
-
167
+ details = result.variance_details.get("details", {})
168
+ table.add_row("Runbooks Accounts", str(details.get("runbooks_accounts", "N/A")))
169
+ table.add_row("MCP Accounts", str(details.get("mcp_accounts", "N/A")))
170
+
173
171
  console.print(table)
174
-
172
+
175
173
  sys.exit(0 if result.status == ValidationStatus.PASSED else 1)
176
-
174
+
177
175
  except Exception as e:
178
176
  console.print(f"[bold red]Error validating organizations: {e}[/bold red]")
179
177
  sys.exit(3)
180
178
 
179
+
181
180
  @cli.command()
182
- @click.option('--target-accuracy', default=99.5, help='Target accuracy percentage')
183
- @click.option('--iterations', default=5, help='Number of benchmark iterations')
184
- @click.option('--performance-target', default=30.0, help='Performance target in seconds')
181
+ @click.option("--target-accuracy", default=99.5, help="Target accuracy percentage")
182
+ @click.option("--iterations", default=5, help="Number of benchmark iterations")
183
+ @click.option("--performance-target", default=30.0, help="Performance target in seconds")
185
184
  def benchmark(target_accuracy: float, iterations: int, performance_target: float):
186
185
  """Run performance benchmark for MCP validation framework."""
187
-
188
- console.print(Panel(
189
- f"[bold magenta]MCP Validation Benchmark[/bold magenta]\n"
190
- f"Target Accuracy: {target_accuracy}%\n"
191
- f"Iterations: {iterations}\n"
192
- f"Performance Target: <{performance_target}s",
193
- title="Benchmark Suite"
194
- ))
195
-
186
+
187
+ console.print(
188
+ Panel(
189
+ f"[bold magenta]MCP Validation Benchmark[/bold magenta]\n"
190
+ f"Target Accuracy: {target_accuracy}%\n"
191
+ f"Iterations: {iterations}\n"
192
+ f"Performance Target: <{performance_target}s",
193
+ title="Benchmark Suite",
194
+ )
195
+ )
196
+
196
197
  validator = MCPValidator(performance_target_seconds=performance_target)
197
-
198
+
198
199
  results = []
199
-
200
+
200
201
  try:
201
202
  for i in range(iterations):
202
- console.print(f"\n[bold cyan]Iteration {i+1}/{iterations}[/bold cyan]")
203
-
203
+ console.print(f"\n[bold cyan]Iteration {i + 1}/{iterations}[/bold cyan]")
204
+
204
205
  report = asyncio.run(validator.validate_all_operations())
205
206
  results.append(report)
206
-
207
- console.print(f"Accuracy: {report.overall_accuracy:.1f}% | "
208
- f"Time: {report.execution_time:.1f}s | "
209
- f"Passed: {report.passed_validations}/{report.total_validations}")
210
-
207
+
208
+ console.print(
209
+ f"Accuracy: {report.overall_accuracy:.1f}% | "
210
+ f"Time: {report.execution_time:.1f}s | "
211
+ f"Passed: {report.passed_validations}/{report.total_validations}"
212
+ )
213
+
211
214
  # Benchmark summary
212
215
  avg_accuracy = sum(r.overall_accuracy for r in results) / len(results)
213
216
  avg_time = sum(r.execution_time for r in results) / len(results)
214
217
  success_rate = len([r for r in results if r.overall_accuracy >= target_accuracy]) / len(results) * 100
215
-
218
+
216
219
  summary_table = Table(title="Benchmark Summary", box=box.ROUNDED)
217
220
  summary_table.add_column("Metric", style="cyan")
218
221
  summary_table.add_column("Value", style="bold")
219
-
222
+
220
223
  summary_table.add_row("Average Accuracy", f"{avg_accuracy:.2f}%")
221
224
  summary_table.add_row("Average Time", f"{avg_time:.2f}s")
222
225
  summary_table.add_row("Success Rate", f"{success_rate:.1f}%")
223
226
  summary_table.add_row("Target Met", "✅ YES" if avg_accuracy >= target_accuracy else "❌ NO")
224
227
  summary_table.add_row("Performance Met", "✅ YES" if avg_time <= performance_target else "❌ NO")
225
-
228
+
226
229
  console.print(summary_table)
227
-
230
+
228
231
  # Performance analysis
229
232
  if avg_accuracy >= target_accuracy and avg_time <= performance_target:
230
233
  console.print("[bold green]🎯 Benchmark PASSED - Production ready[/bold green]")
@@ -232,125 +235,134 @@ def benchmark(target_accuracy: float, iterations: int, performance_target: float
232
235
  else:
233
236
  console.print("[bold red]⚠️ Benchmark FAILED - Optimization needed[/bold red]")
234
237
  sys.exit(1)
235
-
238
+
236
239
  except Exception as e:
237
240
  console.print(f"[bold red]Benchmark error: {e}[/bold red]")
238
241
  sys.exit(3)
239
242
 
243
+
240
244
  @cli.command()
241
- @click.option('--operation',
242
- type=click.Choice(['costs', 'organizations', 'ec2', 'security', 'vpc']),
243
- help='Specific operation to validate')
244
- @click.option('--profile', help='AWS profile to use')
245
- @click.option('--tolerance', default=5.0, help='Tolerance percentage')
245
+ @click.option(
246
+ "--operation",
247
+ type=click.Choice(["costs", "organizations", "ec2", "security", "vpc"]),
248
+ help="Specific operation to validate",
249
+ )
250
+ @click.option("--profile", help="AWS profile to use")
251
+ @click.option("--tolerance", default=5.0, help="Tolerance percentage")
246
252
  def validate_single(operation: str, profile: Optional[str], tolerance: float):
247
253
  """Validate a single operation."""
248
-
249
- console.print(Panel(
250
- f"[bold cyan]Single Operation Validation[/bold cyan]\n"
251
- f"Operation: {operation.title()}\n"
252
- f"Profile: {profile or 'default'}\n"
253
- f"Tolerance: ±{tolerance}%",
254
- title="Single Validation"
255
- ))
256
-
254
+
255
+ console.print(
256
+ Panel(
257
+ f"[bold cyan]Single Operation Validation[/bold cyan]\n"
258
+ f"Operation: {operation.title()}\n"
259
+ f"Profile: {profile or 'default'}\n"
260
+ f"Tolerance: ±{tolerance}%",
261
+ title="Single Validation",
262
+ )
263
+ )
264
+
257
265
  validator = MCPValidator(tolerance_percentage=tolerance)
258
-
266
+
259
267
  try:
260
268
  # Map operations to methods
261
269
  operation_map = {
262
- 'costs': validator.validate_cost_explorer,
263
- 'organizations': validator.validate_organizations_data,
264
- 'ec2': validator.validate_ec2_inventory,
265
- 'security': validator.validate_security_baseline,
266
- 'vpc': validator.validate_vpc_analysis
270
+ "costs": validator.validate_cost_explorer,
271
+ "organizations": validator.validate_organizations_data,
272
+ "ec2": validator.validate_ec2_inventory,
273
+ "security": validator.validate_security_baseline,
274
+ "vpc": validator.validate_vpc_analysis,
267
275
  }
268
-
276
+
269
277
  if operation not in operation_map:
270
278
  console.print(f"[red]Unknown operation: {operation}[/red]")
271
279
  sys.exit(1)
272
-
280
+
273
281
  result = asyncio.run(operation_map[operation]())
274
-
282
+
275
283
  # Display result
276
284
  status_color = {
277
285
  ValidationStatus.PASSED: "green",
278
286
  ValidationStatus.WARNING: "yellow",
279
287
  ValidationStatus.FAILED: "red",
280
288
  ValidationStatus.ERROR: "red",
281
- ValidationStatus.TIMEOUT: "red"
289
+ ValidationStatus.TIMEOUT: "red",
282
290
  }[result.status]
283
-
291
+
284
292
  table = Table(title=f"{operation.title()} Validation Result", box=box.ROUNDED)
285
293
  table.add_column("Metric", style="cyan")
286
294
  table.add_column("Value", style="bold")
287
-
295
+
288
296
  table.add_row("Status", f"[{status_color}]{result.status.value}[/{status_color}]")
289
297
  table.add_row("Accuracy", f"{result.accuracy_percentage:.2f}%")
290
298
  table.add_row("Execution Time", f"{result.execution_time:.2f}s")
291
299
  table.add_row("Timestamp", result.timestamp.strftime("%Y-%m-%d %H:%M:%S"))
292
-
300
+
293
301
  if result.error_message:
294
302
  table.add_row("Error", f"[red]{result.error_message}[/red]")
295
-
303
+
296
304
  console.print(table)
297
-
305
+
298
306
  sys.exit(0 if result.status == ValidationStatus.PASSED else 1)
299
-
307
+
300
308
  except Exception as e:
301
309
  console.print(f"[bold red]Error validating {operation}: {e}[/bold red]")
302
310
  sys.exit(3)
303
311
 
312
+
304
313
  @cli.command()
305
314
  def status():
306
315
  """Show MCP validation framework status."""
307
-
316
+
308
317
  table = Table(title="MCP Validation Framework Status", box=box.ROUNDED)
309
318
  table.add_column("Component", style="cyan")
310
319
  table.add_column("Status", style="bold")
311
320
  table.add_column("Details")
312
-
321
+
313
322
  # Check MCP integration
314
323
  try:
315
324
  from notebooks.mcp_integration import MCPIntegrationManager
325
+
316
326
  table.add_row("MCP Integration", "[green]✅ Available[/green]", "Ready for validation")
317
327
  except ImportError:
318
328
  table.add_row("MCP Integration", "[red]❌ Unavailable[/red]", "Install MCP dependencies")
319
-
329
+
320
330
  # Check AWS profiles
321
331
  profiles = [
322
- 'ams-admin-Billing-ReadOnlyAccess-909135376185',
323
- 'ams-admin-ReadOnlyAccess-909135376185',
324
- 'ams-centralised-ops-ReadOnlyAccess-335083429030',
325
- 'ams-shared-services-non-prod-ReadOnlyAccess-499201730520'
332
+ "ams-admin-Billing-ReadOnlyAccess-909135376185",
333
+ "ams-admin-ReadOnlyAccess-909135376185",
334
+ "ams-centralised-ops-ReadOnlyAccess-335083429030",
335
+ "ams-shared-services-non-prod-ReadOnlyAccess-499201730520",
326
336
  ]
327
-
337
+
328
338
  for profile in profiles:
329
339
  try:
330
340
  import boto3
341
+
331
342
  session = boto3.Session(profile_name=profile)
332
- sts = session.client('sts')
343
+ sts = session.client("sts")
333
344
  identity = sts.get_caller_identity()
334
345
  table.add_row(f"Profile: {profile[:20]}...", "[green]✅ Valid[/green]", f"Account: {identity['Account']}")
335
346
  except Exception as e:
336
347
  table.add_row(f"Profile: {profile[:20]}...", "[red]❌ Invalid[/red]", str(e)[:50])
337
-
348
+
338
349
  # Check validation components
339
350
  components = [
340
- ('Cost Explorer', 'runbooks.finops'),
341
- ('Organizations', 'runbooks.inventory'),
342
- ('Security', 'runbooks.security'),
343
- ('VPC Analysis', 'runbooks.vpc')
351
+ ("Cost Explorer", "runbooks.finops"),
352
+ ("Organizations", "runbooks.inventory"),
353
+ ("Security", "runbooks.security"),
354
+ ("VPC Analysis", "runbooks.vpc"),
344
355
  ]
345
-
356
+
346
357
  for name, module in components:
347
358
  try:
348
359
  __import__(module)
349
360
  table.add_row(f"Component: {name}", "[green]✅ Ready[/green]", "Module loaded")
350
361
  except ImportError:
351
362
  table.add_row(f"Component: {name}", "[red]❌ Missing[/red]", "Module not available")
352
-
363
+
353
364
  console.print(table)
354
365
 
355
- if __name__ == '__main__':
356
- cli()
366
+
367
+ if __name__ == "__main__":
368
+ cli()