runbooks 1.1.4__py3-none-any.whl → 1.1.5__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 (228) hide show
  1. runbooks/__init__.py +31 -2
  2. runbooks/__init___optimized.py +18 -4
  3. runbooks/_platform/__init__.py +1 -5
  4. runbooks/_platform/core/runbooks_wrapper.py +141 -138
  5. runbooks/aws2/accuracy_validator.py +812 -0
  6. runbooks/base.py +7 -0
  7. runbooks/cfat/assessment/compliance.py +1 -1
  8. runbooks/cfat/assessment/runner.py +1 -0
  9. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  10. runbooks/cli/__init__.py +1 -1
  11. runbooks/cli/commands/cfat.py +64 -23
  12. runbooks/cli/commands/finops.py +1005 -54
  13. runbooks/cli/commands/inventory.py +138 -35
  14. runbooks/cli/commands/operate.py +9 -36
  15. runbooks/cli/commands/security.py +42 -18
  16. runbooks/cli/commands/validation.py +432 -18
  17. runbooks/cli/commands/vpc.py +81 -17
  18. runbooks/cli/registry.py +22 -10
  19. runbooks/cloudops/__init__.py +20 -27
  20. runbooks/cloudops/base.py +96 -107
  21. runbooks/cloudops/cost_optimizer.py +544 -542
  22. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  23. runbooks/cloudops/interfaces.py +224 -225
  24. runbooks/cloudops/lifecycle_manager.py +5 -4
  25. runbooks/cloudops/mcp_cost_validation.py +252 -235
  26. runbooks/cloudops/models.py +78 -53
  27. runbooks/cloudops/monitoring_automation.py +5 -4
  28. runbooks/cloudops/notebook_framework.py +177 -213
  29. runbooks/cloudops/security_enforcer.py +125 -159
  30. runbooks/common/accuracy_validator.py +11 -0
  31. runbooks/common/aws_pricing.py +349 -326
  32. runbooks/common/aws_pricing_api.py +211 -212
  33. runbooks/common/aws_profile_manager.py +40 -36
  34. runbooks/common/aws_utils.py +74 -79
  35. runbooks/common/business_logic.py +126 -104
  36. runbooks/common/cli_decorators.py +36 -60
  37. runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
  38. runbooks/common/cross_account_manager.py +197 -204
  39. runbooks/common/date_utils.py +27 -39
  40. runbooks/common/decorators.py +29 -19
  41. runbooks/common/dry_run_examples.py +173 -208
  42. runbooks/common/dry_run_framework.py +157 -155
  43. runbooks/common/enhanced_exception_handler.py +15 -4
  44. runbooks/common/enhanced_logging_example.py +50 -64
  45. runbooks/common/enhanced_logging_integration_example.py +65 -37
  46. runbooks/common/env_utils.py +16 -16
  47. runbooks/common/error_handling.py +40 -38
  48. runbooks/common/lazy_loader.py +41 -23
  49. runbooks/common/logging_integration_helper.py +79 -86
  50. runbooks/common/mcp_cost_explorer_integration.py +476 -493
  51. runbooks/common/mcp_integration.py +63 -74
  52. runbooks/common/memory_optimization.py +140 -118
  53. runbooks/common/module_cli_base.py +37 -58
  54. runbooks/common/organizations_client.py +175 -193
  55. runbooks/common/patterns.py +23 -25
  56. runbooks/common/performance_monitoring.py +67 -71
  57. runbooks/common/performance_optimization_engine.py +283 -274
  58. runbooks/common/profile_utils.py +111 -37
  59. runbooks/common/rich_utils.py +201 -141
  60. runbooks/common/sre_performance_suite.py +177 -186
  61. runbooks/enterprise/__init__.py +1 -1
  62. runbooks/enterprise/logging.py +144 -106
  63. runbooks/enterprise/security.py +187 -204
  64. runbooks/enterprise/validation.py +43 -56
  65. runbooks/finops/__init__.py +26 -30
  66. runbooks/finops/account_resolver.py +1 -1
  67. runbooks/finops/advanced_optimization_engine.py +980 -0
  68. runbooks/finops/automation_core.py +268 -231
  69. runbooks/finops/business_case_config.py +184 -179
  70. runbooks/finops/cli.py +660 -139
  71. runbooks/finops/commvault_ec2_analysis.py +157 -164
  72. runbooks/finops/compute_cost_optimizer.py +336 -320
  73. runbooks/finops/config.py +20 -20
  74. runbooks/finops/cost_optimizer.py +484 -618
  75. runbooks/finops/cost_processor.py +332 -214
  76. runbooks/finops/dashboard_runner.py +1006 -172
  77. runbooks/finops/ebs_cost_optimizer.py +991 -657
  78. runbooks/finops/elastic_ip_optimizer.py +317 -257
  79. runbooks/finops/enhanced_mcp_integration.py +340 -0
  80. runbooks/finops/enhanced_progress.py +32 -29
  81. runbooks/finops/enhanced_trend_visualization.py +3 -2
  82. runbooks/finops/enterprise_wrappers.py +223 -285
  83. runbooks/finops/executive_export.py +203 -160
  84. runbooks/finops/helpers.py +130 -288
  85. runbooks/finops/iam_guidance.py +1 -1
  86. runbooks/finops/infrastructure/__init__.py +80 -0
  87. runbooks/finops/infrastructure/commands.py +506 -0
  88. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  89. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  90. runbooks/finops/markdown_exporter.py +337 -174
  91. runbooks/finops/mcp_validator.py +1952 -0
  92. runbooks/finops/nat_gateway_optimizer.py +1512 -481
  93. runbooks/finops/network_cost_optimizer.py +657 -587
  94. runbooks/finops/notebook_utils.py +226 -188
  95. runbooks/finops/optimization_engine.py +1136 -0
  96. runbooks/finops/optimizer.py +19 -23
  97. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  98. runbooks/finops/reservation_optimizer.py +427 -363
  99. runbooks/finops/scenario_cli_integration.py +64 -65
  100. runbooks/finops/scenarios.py +1277 -438
  101. runbooks/finops/schemas.py +218 -182
  102. runbooks/finops/snapshot_manager.py +2289 -0
  103. runbooks/finops/types.py +3 -3
  104. runbooks/finops/validation_framework.py +259 -265
  105. runbooks/finops/vpc_cleanup_exporter.py +189 -144
  106. runbooks/finops/vpc_cleanup_optimizer.py +591 -573
  107. runbooks/finops/workspaces_analyzer.py +171 -182
  108. runbooks/integration/__init__.py +89 -0
  109. runbooks/integration/mcp_integration.py +1920 -0
  110. runbooks/inventory/CLAUDE.md +816 -0
  111. runbooks/inventory/__init__.py +2 -2
  112. runbooks/inventory/cloud_foundations_integration.py +144 -149
  113. runbooks/inventory/collectors/aws_comprehensive.py +1 -1
  114. runbooks/inventory/collectors/aws_networking.py +109 -99
  115. runbooks/inventory/collectors/base.py +4 -0
  116. runbooks/inventory/core/collector.py +495 -313
  117. runbooks/inventory/drift_detection_cli.py +69 -96
  118. runbooks/inventory/inventory_mcp_cli.py +48 -46
  119. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  120. runbooks/inventory/mcp_inventory_validator.py +549 -465
  121. runbooks/inventory/mcp_vpc_validator.py +359 -442
  122. runbooks/inventory/organizations_discovery.py +55 -51
  123. runbooks/inventory/rich_inventory_display.py +33 -32
  124. runbooks/inventory/unified_validation_engine.py +278 -251
  125. runbooks/inventory/vpc_analyzer.py +732 -695
  126. runbooks/inventory/vpc_architecture_validator.py +293 -348
  127. runbooks/inventory/vpc_dependency_analyzer.py +382 -378
  128. runbooks/inventory/vpc_flow_analyzer.py +1 -1
  129. runbooks/main.py +49 -34
  130. runbooks/main_final.py +91 -60
  131. runbooks/main_minimal.py +22 -10
  132. runbooks/main_optimized.py +131 -100
  133. runbooks/main_ultra_minimal.py +7 -2
  134. runbooks/mcp/__init__.py +36 -0
  135. runbooks/mcp/integration.py +679 -0
  136. runbooks/monitoring/performance_monitor.py +9 -4
  137. runbooks/operate/dynamodb_operations.py +3 -1
  138. runbooks/operate/ec2_operations.py +145 -137
  139. runbooks/operate/iam_operations.py +146 -152
  140. runbooks/operate/networking_cost_heatmap.py +29 -8
  141. runbooks/operate/rds_operations.py +223 -254
  142. runbooks/operate/s3_operations.py +107 -118
  143. runbooks/operate/vpc_operations.py +646 -616
  144. runbooks/remediation/base.py +1 -1
  145. runbooks/remediation/commons.py +10 -7
  146. runbooks/remediation/commvault_ec2_analysis.py +70 -66
  147. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  148. runbooks/remediation/multi_account.py +24 -21
  149. runbooks/remediation/rds_snapshot_list.py +86 -60
  150. runbooks/remediation/remediation_cli.py +92 -146
  151. runbooks/remediation/universal_account_discovery.py +83 -79
  152. runbooks/remediation/workspaces_list.py +46 -41
  153. runbooks/security/__init__.py +19 -0
  154. runbooks/security/assessment_runner.py +1150 -0
  155. runbooks/security/baseline_checker.py +812 -0
  156. runbooks/security/cloudops_automation_security_validator.py +509 -535
  157. runbooks/security/compliance_automation_engine.py +17 -17
  158. runbooks/security/config/__init__.py +2 -2
  159. runbooks/security/config/compliance_config.py +50 -50
  160. runbooks/security/config_template_generator.py +63 -76
  161. runbooks/security/enterprise_security_framework.py +1 -1
  162. runbooks/security/executive_security_dashboard.py +519 -508
  163. runbooks/security/multi_account_security_controls.py +959 -1210
  164. runbooks/security/real_time_security_monitor.py +422 -444
  165. runbooks/security/security_baseline_tester.py +1 -1
  166. runbooks/security/security_cli.py +143 -112
  167. runbooks/security/test_2way_validation.py +439 -0
  168. runbooks/security/two_way_validation_framework.py +852 -0
  169. runbooks/sre/production_monitoring_framework.py +167 -177
  170. runbooks/tdd/__init__.py +15 -0
  171. runbooks/tdd/cli.py +1071 -0
  172. runbooks/utils/__init__.py +14 -17
  173. runbooks/utils/logger.py +7 -2
  174. runbooks/utils/version_validator.py +50 -47
  175. runbooks/validation/__init__.py +6 -6
  176. runbooks/validation/cli.py +9 -3
  177. runbooks/validation/comprehensive_2way_validator.py +745 -704
  178. runbooks/validation/mcp_validator.py +906 -228
  179. runbooks/validation/terraform_citations_validator.py +104 -115
  180. runbooks/validation/terraform_drift_detector.py +447 -451
  181. runbooks/vpc/README.md +617 -0
  182. runbooks/vpc/__init__.py +8 -1
  183. runbooks/vpc/analyzer.py +577 -0
  184. runbooks/vpc/cleanup_wrapper.py +476 -413
  185. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  186. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  187. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  188. runbooks/vpc/config.py +92 -97
  189. runbooks/vpc/cost_engine.py +411 -148
  190. runbooks/vpc/cost_explorer_integration.py +553 -0
  191. runbooks/vpc/cross_account_session.py +101 -106
  192. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  193. runbooks/vpc/eni_gate_validator.py +961 -0
  194. runbooks/vpc/heatmap_engine.py +185 -160
  195. runbooks/vpc/mcp_no_eni_validator.py +680 -639
  196. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  197. runbooks/vpc/networking_wrapper.py +15 -8
  198. runbooks/vpc/pdca_remediation_planner.py +528 -0
  199. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  200. runbooks/vpc/runbooks_adapter.py +1167 -241
  201. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  202. runbooks/vpc/test_data_loader.py +358 -0
  203. runbooks/vpc/tests/conftest.py +314 -4
  204. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  205. runbooks/vpc/tests/test_cost_engine.py +0 -2
  206. runbooks/vpc/topology_generator.py +326 -0
  207. runbooks/vpc/unified_scenarios.py +1297 -1124
  208. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  209. runbooks-1.1.5.dist-info/METADATA +328 -0
  210. {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/RECORD +214 -193
  211. runbooks/finops/README.md +0 -414
  212. runbooks/finops/accuracy_cross_validator.py +0 -647
  213. runbooks/finops/business_cases.py +0 -950
  214. runbooks/finops/dashboard_router.py +0 -922
  215. runbooks/finops/ebs_optimizer.py +0 -973
  216. runbooks/finops/embedded_mcp_validator.py +0 -1629
  217. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  218. runbooks/finops/finops_dashboard.py +0 -584
  219. runbooks/finops/finops_scenarios.py +0 -1218
  220. runbooks/finops/legacy_migration.py +0 -730
  221. runbooks/finops/multi_dashboard.py +0 -1519
  222. runbooks/finops/single_dashboard.py +0 -1113
  223. runbooks/finops/unlimited_scenarios.py +0 -393
  224. runbooks-1.1.4.dist-info/METADATA +0 -800
  225. {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
  226. {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
  227. {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
  228. {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -11,7 +11,7 @@ Strategic Alignment:
11
11
 
12
12
  Features:
13
13
  - Real-time AWS API cross-validation
14
- - Terraform state drift detection
14
+ - Terraform state drift detection
15
15
  - Rich CLI enterprise UX with visual indicators
16
16
  - Evidence-based drift reporting
17
17
  - Profile override priority system
@@ -34,7 +34,7 @@ from ..common.rich_utils import console, print_error, print_info, print_success
34
34
  from .mcp_inventory_validator import (
35
35
  create_inventory_mcp_validator,
36
36
  generate_drift_report,
37
- validate_inventory_results_with_mcp
37
+ validate_inventory_results_with_mcp,
38
38
  )
39
39
 
40
40
 
@@ -45,46 +45,32 @@ def drift():
45
45
 
46
46
 
47
47
  @drift.command("detect")
48
- @click.option(
49
- "--profile",
50
- help="AWS profile to use (overrides environment variables)"
51
- )
52
- @click.option(
53
- "--profiles",
54
- help="Comma-separated list of AWS profiles for multi-account analysis"
55
- )
48
+ @click.option("--profile", help="AWS profile to use (overrides environment variables)")
49
+ @click.option("--profiles", help="Comma-separated list of AWS profiles for multi-account analysis")
56
50
  @click.option(
57
51
  "--terraform-dir",
58
52
  default="/Volumes/Working/1xOps/CloudOps-Runbooks/terraform-aws",
59
- help="Path to terraform configuration directory"
53
+ help="Path to terraform configuration directory",
60
54
  )
61
55
  @click.option(
62
56
  "--report-format",
63
57
  type=click.Choice(["console", "json", "csv"]),
64
58
  default="console",
65
- help="Output format for drift report"
66
- )
67
- @click.option(
68
- "--output-file",
69
- help="File path to save drift report (optional)"
70
- )
71
- @click.option(
72
- "--threshold",
73
- type=float,
74
- default=99.5,
75
- help="Accuracy threshold for drift detection (default: 99.5%)"
59
+ help="Output format for drift report",
76
60
  )
61
+ @click.option("--output-file", help="File path to save drift report (optional)")
62
+ @click.option("--threshold", type=float, default=99.5, help="Accuracy threshold for drift detection (default: 99.5%)")
77
63
  def detect_drift(
78
64
  profile: Optional[str],
79
- profiles: Optional[str],
65
+ profiles: Optional[str],
80
66
  terraform_dir: str,
81
67
  report_format: str,
82
68
  output_file: Optional[str],
83
- threshold: float
69
+ threshold: float,
84
70
  ):
85
71
  """
86
72
  Detect infrastructure drift using 3-way validation.
87
-
73
+
88
74
  Compares inventory collection results against AWS API and terraform state
89
75
  to identify discrepancies and provide actionable recommendations.
90
76
  """
@@ -98,9 +84,9 @@ def detect_drift(
98
84
  # Use operational profile as default
99
85
  default_profile = get_profile_for_operation("operational", None)
100
86
  profile_list = [default_profile]
101
-
87
+
102
88
  print_info(f"Starting drift detection for {len(profile_list)} profile(s)")
103
-
89
+
104
90
  # Validate all profiles
105
91
  valid_profiles = []
106
92
  for prof in profile_list:
@@ -108,99 +94,83 @@ def detect_drift(
108
94
  valid_profiles.append(prof)
109
95
  else:
110
96
  print_error(f"Profile '{prof}' validation failed - skipping")
111
-
97
+
112
98
  if not valid_profiles:
113
99
  print_error("No valid profiles available for drift detection")
114
100
  return
115
-
101
+
116
102
  # Create validator with terraform integration
117
- validator = create_inventory_mcp_validator(
118
- profiles=valid_profiles,
119
- terraform_directory=terraform_dir
120
- )
121
-
103
+ validator = create_inventory_mcp_validator(profiles=valid_profiles, terraform_directory=terraform_dir)
104
+
122
105
  # Set custom threshold if provided
123
106
  validator.validation_threshold = threshold
124
-
107
+
125
108
  console.print(f"[blue]🔍 Initializing drift detection...[/]")
126
109
  console.print(f"[dim]Terraform directory: {terraform_dir}[/]")
127
110
  console.print(f"[dim]Accuracy threshold: {threshold}%[/]")
128
-
111
+
129
112
  # For demonstration, create mock inventory data
130
113
  # In practice, this would come from actual inventory collection
131
114
  mock_inventory = _create_mock_inventory_data(valid_profiles)
132
-
115
+
133
116
  # Perform enhanced validation with drift detection
134
117
  validation_results = validator.validate_inventory_data(mock_inventory)
135
-
118
+
136
119
  # Generate summary results
137
120
  overall_accuracy = validation_results.get("total_accuracy", 0)
138
121
  terraform_integration = validation_results.get("terraform_integration", {})
139
-
122
+
140
123
  if validation_results.get("passed_validation", False):
141
124
  print_success(f"✅ Drift detection completed: {overall_accuracy:.1f}% accuracy")
142
125
  else:
143
126
  console.print(f"[yellow]🔄 Infrastructure drift detected: {overall_accuracy:.1f}% accuracy[/]")
144
-
127
+
145
128
  # Display terraform integration status
146
129
  if terraform_integration.get("enabled", False):
147
130
  tf_files = terraform_integration.get("state_files_discovered", 0)
148
131
  print_info(f"Terraform integration: {tf_files} configuration files analyzed")
149
-
132
+
150
133
  drift_analysis = terraform_integration.get("drift_analysis", {})
151
134
  if drift_analysis:
152
135
  drift_pct = drift_analysis.get("drift_percentage", 0)
153
136
  tf_coverage = drift_analysis.get("terraform_coverage_percentage", 0)
154
137
  console.print(f"[dim]📊 {drift_pct:.1f}% of accounts have drift detected[/]")
155
138
  console.print(f"[dim]🎯 {tf_coverage:.1f}% of accounts have terraform coverage[/]")
156
-
139
+
157
140
  # Generate and export report if requested
158
141
  if output_file or report_format != "console":
159
142
  drift_report = generate_drift_report(valid_profiles, mock_inventory, terraform_dir)
160
-
143
+
161
144
  if output_file:
162
145
  _export_drift_report(drift_report, output_file, report_format)
163
146
  print_success(f"Drift report exported to: {output_file}")
164
-
147
+
165
148
  print_info("Drift detection analysis complete")
166
-
149
+
167
150
  except Exception as e:
168
151
  print_error(f"Drift detection failed: {str(e)}")
169
152
  raise click.Abort()
170
153
 
171
154
 
172
155
  @drift.command("report")
173
- @click.option(
174
- "--profile",
175
- help="AWS profile to use for single-account analysis"
176
- )
156
+ @click.option("--profile", help="AWS profile to use for single-account analysis")
177
157
  @click.option(
178
158
  "--terraform-dir",
179
159
  default="/Volumes/Working/1xOps/CloudOps-Runbooks/terraform-aws",
180
- help="Path to terraform configuration directory"
160
+ help="Path to terraform configuration directory",
181
161
  )
182
162
  @click.option(
183
163
  "--format",
184
164
  "report_format",
185
165
  type=click.Choice(["json", "csv", "markdown"]),
186
166
  default="json",
187
- help="Report output format"
167
+ help="Report output format",
188
168
  )
189
- @click.option(
190
- "--output",
191
- "output_file",
192
- required=True,
193
- help="Output file path for drift report"
194
- )
195
- def generate_report(
196
- profile: Optional[str],
197
- terraform_dir: str,
198
- report_format: str,
199
- output_file: str
200
- ):
169
+ @click.option("--output", "output_file", required=True, help="Output file path for drift report")
170
+ def generate_report(profile: Optional[str], terraform_dir: str, report_format: str, output_file: str):
201
171
  """
202
172
  Generate comprehensive infrastructure drift report.
203
-
173
+
204
174
  Creates detailed drift analysis report with actionable recommendations
205
175
  for infrastructure as code management and compliance.
206
176
  """
@@ -208,35 +178,35 @@ def generate_report(
208
178
  # Use default profile if none specified
209
179
  if not profile:
210
180
  profile = get_profile_for_operation("operational", None)
211
-
181
+
212
182
  print_info(f"Generating drift report for profile: {profile}")
213
-
183
+
214
184
  # Validate profile
215
185
  if not validate_profile_access(profile, "drift-reporting"):
216
186
  print_error(f"Profile '{profile}' validation failed")
217
187
  return
218
-
188
+
219
189
  # Create mock inventory for demonstration
220
190
  mock_inventory = _create_mock_inventory_data([profile])
221
-
191
+
222
192
  # Generate comprehensive drift report
223
193
  drift_report = generate_drift_report([profile], mock_inventory, terraform_dir)
224
-
194
+
225
195
  # Export report
226
196
  _export_drift_report(drift_report, output_file, report_format)
227
-
197
+
228
198
  print_success(f"Drift report generated: {output_file}")
229
-
199
+
230
200
  # Display summary
231
201
  accounts_analyzed = drift_report.get("accounts_analyzed", 0)
232
202
  overall_accuracy = drift_report.get("overall_accuracy", 0)
233
203
  drift_detected = drift_report.get("drift_detected", False)
234
-
204
+
235
205
  console.print(f"[dim]📊 Analysis Summary:[/]")
236
206
  console.print(f"[dim] Accounts analyzed: {accounts_analyzed}[/]")
237
207
  console.print(f"[dim] Overall accuracy: {overall_accuracy:.1f}%[/]")
238
208
  console.print(f"[dim] Drift detected: {'Yes' if drift_detected else 'No'}[/]")
239
-
209
+
240
210
  except Exception as e:
241
211
  print_error(f"Report generation failed: {str(e)}")
242
212
  raise click.Abort()
@@ -245,7 +215,7 @@ def generate_report(
245
215
  def _create_mock_inventory_data(profiles: List[str]) -> dict:
246
216
  """Create mock inventory data for demonstration purposes."""
247
217
  mock_data = {}
248
-
218
+
249
219
  for profile in profiles:
250
220
  mock_data[profile] = {
251
221
  "resource_counts": {
@@ -258,12 +228,12 @@ def _create_mock_inventory_data(profiles: List[str]) -> dict:
258
228
  "cloudformation": 4,
259
229
  "elbv2": 1,
260
230
  "route53": 2,
261
- "sns": 3
231
+ "sns": 3,
262
232
  },
263
233
  "regions": ["us-east-1", "us-west-2", "ap-southeast-2"],
264
- "collection_timestamp": "2024-09-10T12:00:00Z"
234
+ "collection_timestamp": "2024-09-10T12:00:00Z",
265
235
  }
266
-
236
+
267
237
  return mock_data
268
238
 
269
239
 
@@ -271,50 +241,53 @@ def _export_drift_report(report_data: dict, output_file: str, format_type: str)
271
241
  """Export drift report to specified format."""
272
242
  import json
273
243
  from pathlib import Path
274
-
244
+
275
245
  output_path = Path(output_file)
276
246
  output_path.parent.mkdir(parents=True, exist_ok=True)
277
-
247
+
278
248
  if format_type == "json":
279
- with open(output_path, 'w') as f:
249
+ with open(output_path, "w") as f:
280
250
  json.dump(report_data, f, indent=2, default=str)
281
251
  elif format_type == "csv":
282
252
  # Create CSV summary
283
253
  import csv
284
- with open(output_path, 'w', newline='') as f:
254
+
255
+ with open(output_path, "w", newline="") as f:
285
256
  writer = csv.writer(f)
286
- writer.writerow(['Account ID', 'Profile', 'Accuracy %', 'Drift Detected', 'Terraform Coverage'])
287
-
257
+ writer.writerow(["Account ID", "Profile", "Accuracy %", "Drift Detected", "Terraform Coverage"])
258
+
288
259
  for account in report_data.get("detailed_analysis", []):
289
- writer.writerow([
290
- account.get("account_id", "Unknown"),
291
- account.get("profile", "Unknown"),
292
- f"{account.get('accuracy_percent', 0):.1f}",
293
- "Yes" if account.get("drift_summary", {}).get("drift_detected", 0) > 0 else "No",
294
- "Yes" if account.get("terraform_coverage", False) else "No"
295
- ])
260
+ writer.writerow(
261
+ [
262
+ account.get("account_id", "Unknown"),
263
+ account.get("profile", "Unknown"),
264
+ f"{account.get('accuracy_percent', 0):.1f}",
265
+ "Yes" if account.get("drift_summary", {}).get("drift_detected", 0) > 0 else "No",
266
+ "Yes" if account.get("terraform_coverage", False) else "No",
267
+ ]
268
+ )
296
269
  elif format_type == "markdown":
297
270
  # Create markdown report
298
- with open(output_path, 'w') as f:
271
+ with open(output_path, "w") as f:
299
272
  f.write("# Infrastructure Drift Analysis Report\n\n")
300
273
  f.write(f"**Generated:** {report_data.get('generated_timestamp', 'Unknown')}\n\n")
301
-
274
+
302
275
  terraform_info = report_data.get("terraform_integration", {})
303
276
  f.write(f"**Terraform Integration:** {terraform_info.get('enabled', False)}\n")
304
277
  f.write(f"**State Files Discovered:** {terraform_info.get('state_files_discovered', 0)}\n\n")
305
-
278
+
306
279
  f.write("## Summary\n\n")
307
280
  f.write(f"- **Accounts Analyzed:** {report_data.get('accounts_analyzed', 0)}\n")
308
281
  f.write(f"- **Overall Accuracy:** {report_data.get('overall_accuracy', 0):.1f}%\n")
309
282
  f.write(f"- **Drift Detected:** {'Yes' if report_data.get('drift_detected', False) else 'No'}\n\n")
310
-
283
+
311
284
  f.write("## Detailed Analysis\n\n")
312
285
  for account in report_data.get("detailed_analysis", []):
313
286
  f.write(f"### Account: {account.get('account_id', 'Unknown')}\n\n")
314
287
  f.write(f"- **Profile:** {account.get('profile', 'Unknown')}\n")
315
288
  f.write(f"- **Accuracy:** {account.get('accuracy_percent', 0):.1f}%\n")
316
289
  f.write(f"- **Terraform Coverage:** {'Yes' if account.get('terraform_coverage', False) else 'No'}\n\n")
317
-
290
+
318
291
  recommendations = account.get("recommendations", [])
319
292
  if recommendations:
320
293
  f.write("**Recommendations:**\n")
@@ -324,4 +297,4 @@ def _export_drift_report(report_data: dict, output_file: str, format_type: str)
324
297
 
325
298
 
326
299
  if __name__ == "__main__":
327
- drift()
300
+ drift()
@@ -25,22 +25,28 @@ from .mcp_inventory_validator import create_inventory_mcp_validator
25
25
 
26
26
 
27
27
  @click.command()
28
- @click.option('--profile', help='AWS profile name (takes precedence over environment variables)')
29
- @click.option('--resource-types', multiple=True,
30
- type=click.Choice(['ec2', 's3', 'rds', 'lambda', 'vpc', 'iam', 'cloudformation']),
31
- default=['ec2', 's3', 'vpc'],
32
- help='Resource types to validate')
33
- @click.option('--test-mode', is_flag=True, default=True,
34
- help='Run in test mode with sample data')
35
- @click.option('--real-validation', is_flag=True, default=False,
36
- help='Run validation against real AWS APIs (requires valid profiles)')
28
+ @click.option("--profile", help="AWS profile name (takes precedence over environment variables)")
29
+ @click.option(
30
+ "--resource-types",
31
+ multiple=True,
32
+ type=click.Choice(["ec2", "s3", "rds", "lambda", "vpc", "iam", "cloudformation"]),
33
+ default=["ec2", "s3", "vpc"],
34
+ help="Resource types to validate",
35
+ )
36
+ @click.option("--test-mode", is_flag=True, default=True, help="Run in test mode with sample data")
37
+ @click.option(
38
+ "--real-validation",
39
+ is_flag=True,
40
+ default=False,
41
+ help="Run validation against real AWS APIs (requires valid profiles)",
42
+ )
37
43
  def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], test_mode: bool, real_validation: bool):
38
44
  """
39
45
  Test inventory MCP validation functionality.
40
-
46
+
41
47
  This command demonstrates inventory MCP validation integration
42
48
  following proven enterprise patterns from FinOps module success.
43
-
49
+
44
50
  Examples:
45
51
  runbooks inventory validate-mcp --profile my-profile --resource-types ec2,s3
46
52
  runbooks inventory validate-mcp --test-mode --resource-types ec2,vpc,rds
@@ -48,7 +54,9 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
48
54
  """
49
55
  try:
50
56
  console.print(f"[blue]🔍 Inventory MCP Validation Test[/blue]")
51
- console.print(f"[dim]Profile: {profile or 'environment fallback'} | Resources: {', '.join(resource_types)} | Test mode: {test_mode}[/dim]")
57
+ console.print(
58
+ f"[dim]Profile: {profile or 'environment fallback'} | Resources: {', '.join(resource_types)} | Test mode: {test_mode}[/dim]"
59
+ )
52
60
 
53
61
  # Apply profile priority system following proven patterns
54
62
  operational_profile = get_profile_for_operation("operational", profile)
@@ -61,7 +69,7 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
61
69
  if test_mode and not real_validation:
62
70
  # Test mode: Use sample data to demonstrate validation
63
71
  print_info("Running test mode with sample inventory data")
64
-
72
+
65
73
  # Create sample inventory data for testing
66
74
  sample_inventory = {
67
75
  operational_profile: {
@@ -72,89 +80,83 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
72
80
  "lambda": 12,
73
81
  "vpc": 4,
74
82
  "iam": 25,
75
- "cloudformation": 6
83
+ "cloudformation": 6,
76
84
  },
77
- "regions": ["us-east-1", "us-west-2"]
85
+ "regions": ["us-east-1", "us-west-2"],
78
86
  }
79
87
  }
80
-
88
+
81
89
  # Filter to requested resource types
82
90
  filtered_inventory = {
83
91
  operational_profile: {
84
92
  "resource_counts": {
85
- rt: sample_inventory[operational_profile]["resource_counts"].get(rt, 0)
86
- for rt in resource_types
93
+ rt: sample_inventory[operational_profile]["resource_counts"].get(rt, 0) for rt in resource_types
87
94
  },
88
- "regions": sample_inventory[operational_profile]["regions"]
95
+ "regions": sample_inventory[operational_profile]["regions"],
89
96
  }
90
97
  }
91
-
92
- print_info(f"Testing validation with sample resource counts: {filtered_inventory[operational_profile]['resource_counts']}")
93
-
98
+
99
+ print_info(
100
+ f"Testing validation with sample resource counts: {filtered_inventory[operational_profile]['resource_counts']}"
101
+ )
102
+
94
103
  # Note: In test mode, this will compare sample data against real AWS APIs
95
104
  # This demonstrates the validation mechanism without requiring mock data
96
105
  validation_results = validator.validate_inventory_data(filtered_inventory)
97
-
106
+
98
107
  elif real_validation:
99
108
  # Real validation mode: Requires actual inventory collection
100
109
  print_warning("Real validation mode requires actual inventory collection")
101
110
  print_info("This would typically be called from the main inventory collector")
102
-
111
+
103
112
  # For demonstration, we'll validate empty inventory (should show 0 vs actual counts)
104
113
  empty_inventory = {
105
- operational_profile: {
106
- "resource_counts": {rt: 0 for rt in resource_types},
107
- "regions": ["us-east-1"]
108
- }
114
+ operational_profile: {"resource_counts": {rt: 0 for rt in resource_types}, "regions": ["us-east-1"]}
109
115
  }
110
-
116
+
111
117
  print_info("Validating empty inventory against real AWS APIs (demonstrates detection capability)")
112
118
  validation_results = validator.validate_inventory_data(empty_inventory)
113
-
119
+
114
120
  else:
115
121
  # Resource count validation only
116
122
  print_info("Running resource count validation test")
117
-
118
- sample_counts = {
119
- "ec2": 10,
120
- "s3": 5,
121
- "vpc": 2
122
- }
123
-
123
+
124
+ sample_counts = {"ec2": 10, "s3": 5, "vpc": 2}
125
+
124
126
  # Filter to requested resource types
125
127
  test_counts = {rt: sample_counts.get(rt, 0) for rt in resource_types if rt in sample_counts}
126
-
128
+
127
129
  validation_results = validator.validate_resource_counts(test_counts)
128
130
 
129
131
  # Display results summary
130
132
  console.print(f"\n[bright_cyan]📊 Validation Test Results Summary[/]")
131
-
133
+
132
134
  if isinstance(validation_results, dict):
133
135
  if "total_accuracy" in validation_results:
134
136
  accuracy = validation_results.get("total_accuracy", 0)
135
137
  passed = validation_results.get("passed_validation", False)
136
-
138
+
137
139
  if passed:
138
140
  print_success(f"✅ Test validation completed: {accuracy:.1f}% accuracy")
139
141
  else:
140
142
  print_warning(f"⚠️ Test validation: {accuracy:.1f}% accuracy (target: ≥99.5%)")
141
-
143
+
142
144
  profiles_validated = validation_results.get("profiles_validated", 0)
143
145
  console.print(f"[dim]Profiles validated: {profiles_validated}[/dim]")
144
-
146
+
145
147
  # Show resource summary if available
146
148
  resource_summary = validation_results.get("resource_validation_summary", {})
147
149
  if resource_summary:
148
150
  console.print(f"[dim]Resource types validated: {len(resource_summary)}[/dim]")
149
-
151
+
150
152
  elif "validated_count" in validation_results:
151
153
  validated_count = validation_results.get("validated_count", 0)
152
154
  passed_count = validation_results.get("passed_count", 0)
153
155
  print_info(f"Resource count validation: {passed_count}/{validated_count} passed")
154
-
156
+
155
157
  else:
156
158
  print_info("Validation completed - see detailed output above")
157
-
159
+
158
160
  # Integration guidance
159
161
  console.print(f"\n[bright_cyan]💡 Integration Information[/]")
160
162
  console.print(f"[dim]This MCP validator is automatically integrated into:[/dim]")
@@ -168,4 +170,4 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
168
170
 
169
171
 
170
172
  if __name__ == "__main__":
171
- validate_inventory_mcp()
173
+ validate_inventory_mcp()