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
@@ -3,18 +3,18 @@
3
3
  VPC Unified Scenario Framework Engine - Enterprise Cross-Deliverable Support
4
4
 
5
5
  This module provides a unified scenario engine supporting critical VPC cleanup scenarios
6
- across all deliverables: shell scripts, Jupyter notebooks, executive presentations,
6
+ across all deliverables: shell scripts, Jupyter notebooks, executive presentations,
7
7
  and documentation with MCP cross-validation achieving ≥99.5% accuracy.
8
8
 
9
9
  Strategic Framework:
10
- - Consistent data and formatting across vpc-cleanup.sh, vpc-cleanup.ipynb,
10
+ - Consistent data and formatting across vpc-cleanup.sh, vpc-cleanup.ipynb,
11
11
  vpc-cleanup-executive.ipynb, and vpc-cleanup.md
12
12
  - 4-6 critical scenarios with comprehensive validation
13
13
  - Enterprise-grade MCP validation with ≥99.5% accuracy target
14
14
  - Rich CLI integration following enterprise UX standards
15
15
  - Multi-format export capabilities for stakeholder consumption
16
16
 
17
- Author: CloudOps Runbooks Team
17
+ Author: CloudOps Runbooks Team
18
18
  Version: latest version - Enterprise VPC Cleanup Campaign
19
19
  """
20
20
 
@@ -47,34 +47,51 @@ try:
47
47
  print_warning,
48
48
  print_info,
49
49
  format_cost,
50
- STATUS_INDICATORS
50
+ STATUS_INDICATORS,
51
51
  )
52
52
  from ..common.profile_utils import create_operational_session
53
53
  except ImportError:
54
54
  # Fallback for standalone usage
55
55
  console = Console()
56
- def print_header(title, version=""): console.print(f"[bold cyan]{title}[/bold cyan] {version}")
57
- def print_success(msg): console.print(f"[green]✅ {msg}[/green]")
58
- def print_error(msg): console.print(f"[red]{msg}[/red]")
59
- def print_warning(msg): console.print(f"[yellow]⚠️ {msg}[/yellow]")
60
- def print_info(msg): console.print(f"[blue]ℹ️ {msg}[/blue]")
61
- def format_cost(amount): return f"${amount:,.2f}"
62
- def create_operational_session(profile): return boto3.Session(profile_name=profile)
56
+
57
+ def print_header(title, version=""):
58
+ console.print(f"[bold cyan]{title}[/bold cyan] {version}")
59
+
60
+ def print_success(msg):
61
+ console.print(f"[green]✅ {msg}[/green]")
62
+
63
+ def print_error(msg):
64
+ console.print(f"[red]❌ {msg}[/red]")
65
+
66
+ def print_warning(msg):
67
+ console.print(f"[yellow]⚠️ {msg}[/yellow]")
68
+
69
+ def print_info(msg):
70
+ console.print(f"[blue]ℹ️ {msg}[/blue]")
71
+
72
+ def format_cost(amount):
73
+ return f"${amount:,.2f}"
74
+
75
+ def create_operational_session(profile):
76
+ return boto3.Session(profile_name=profile)
77
+
63
78
 
64
79
  logger = logging.getLogger(__name__)
65
80
 
66
81
 
67
82
  class VPCDecisionType(Enum):
68
83
  """VPC cleanup decision types with standardized status legend."""
69
- DELETE_IAC = "DELETE (IaC)" # Remove via Infrastructure as Code
70
- DELETE_MANUAL = "DELETE (manual)" # Controlled CLI/Console removal
71
- DELETE_AUTO = "DELETE (auto)" # Automated via Runbooks/MCP
72
- HOLD = "HOLD" # Pending owner/traffic analysis
73
- INVESTIGATE = "INVESTIGATE" # Dependency/traffic ambiguity
84
+
85
+ DELETE_IAC = "DELETE (IaC)" # Remove via Infrastructure as Code
86
+ DELETE_MANUAL = "DELETE (manual)" # Controlled CLI/Console removal
87
+ DELETE_AUTO = "DELETE (auto)" # Automated via Runbooks/MCP
88
+ HOLD = "HOLD" # Pending owner/traffic analysis
89
+ INVESTIGATE = "INVESTIGATE" # Dependency/traffic ambiguity
74
90
 
75
91
 
76
92
  class ValidationStep(Enum):
77
93
  """5-Step comprehensive dual validation analysis framework."""
94
+
78
95
  IMMEDIATE_DELETION = "Step 1: Immediate Deletion Candidates"
79
96
  INVESTIGATION_REQUIRED = "Step 2: Investigation Required"
80
97
  GOVERNANCE_APPROVAL = "Step 3: Governance Approval"
@@ -86,12 +103,13 @@ class ValidationStep(Enum):
86
103
  class VPCCandidate:
87
104
  """
88
105
  VPC cleanup candidate with comprehensive metadata.
89
-
106
+
90
107
  Supports markdown table format with MCP cross-validation:
91
- #, Account_ID, VPC_ID, VPC_Name, CIDR_Block, Overlapping, Is_Default,
92
- ENI_Count, Tags, Flow_Logs, TGW/Peering, LBs_Present, IaC, Timeline,
108
+ #, Account_ID, VPC_ID, VPC_Name, CIDR_Block, Overlapping, Is_Default,
109
+ ENI_Count, Tags, Flow_Logs, TGW/Peering, LBs_Present, IaC, Timeline,
93
110
  Decision, Owners/Approvals, Notes
94
111
  """
112
+
95
113
  sequence_number: int
96
114
  account_id: str
97
115
  vpc_id: str
@@ -109,7 +127,7 @@ class VPCCandidate:
109
127
  decision: VPCDecisionType = VPCDecisionType.INVESTIGATE
110
128
  owners_approvals: List[str] = field(default_factory=list)
111
129
  notes: str = ""
112
-
130
+
113
131
  # MCP validation metadata
114
132
  mcp_validated: bool = False
115
133
  mcp_accuracy: float = 0.0
@@ -120,6 +138,7 @@ class VPCCandidate:
120
138
  @dataclass
121
139
  class ValidationStepResult:
122
140
  """Results for each validation step in comprehensive analysis."""
141
+
123
142
  step: ValidationStep
124
143
  vpc_count: int
125
144
  percentage: float
@@ -133,6 +152,7 @@ class ValidationStepResult:
133
152
  @dataclass
134
153
  class BusinessImpactSummary:
135
154
  """Business impact summary with specific enterprise metrics."""
155
+
136
156
  security_value_percentage: float
137
157
  immediate_deletion_ready: int
138
158
  default_vpc_elimination_count: int
@@ -148,14 +168,14 @@ class BusinessImpactSummary:
148
168
  class VPCMCPValidator:
149
169
  """
150
170
  Enhanced MCP validator using proven FinOps patterns for ≥99.5% accuracy.
151
-
171
+
152
172
  Integrates successful EmbeddedMCPValidator methodology:
153
173
  - Time-synchronized validation periods
154
- - Parallel processing with ThreadPoolExecutor
174
+ - Parallel processing with ThreadPoolExecutor
155
175
  - SHA256 evidence verification
156
176
  - Comprehensive accuracy scoring
157
177
  """
158
-
178
+
159
179
  def __init__(self, profile: str, console: Console = None):
160
180
  """Initialize enhanced VPC MCP validator with proven FinOps patterns."""
161
181
  self.profile = profile
@@ -165,10 +185,11 @@ class VPCMCPValidator:
165
185
  self.cache_ttl = 300 # 5 minutes cache TTL (FinOps pattern)
166
186
  self.accuracy_threshold = 99.5 # Enterprise accuracy target
167
187
  self.tolerance_percent = 5.0 # ±5% tolerance for validation
168
-
188
+
169
189
  # Import proven FinOps validation patterns
170
190
  try:
171
191
  from ..finops.embedded_mcp_validator import EmbeddedMCPValidator
192
+
172
193
  self.embedded_validator = EmbeddedMCPValidator([profile] if profile else ["default"])
173
194
  self.has_embedded_validator = True
174
195
  print_info("Enhanced VPC MCP validation using proven FinOps patterns")
@@ -176,42 +197,42 @@ class VPCMCPValidator:
176
197
  self.embedded_validator = None
177
198
  self.has_embedded_validator = False
178
199
  print_warning("Fallback to basic MCP validation - FinOps patterns not available")
179
-
200
+
180
201
  async def validate_vpc_candidate(self, candidate: VPCCandidate) -> Tuple[bool, float, Dict[str, Any]]:
181
202
  """
182
203
  Enhanced validation using time-synchronized periods and proven FinOps accuracy methodology.
183
-
204
+
184
205
  Returns:
185
206
  Tuple of (validation_success, accuracy_percentage, validation_details)
186
207
  """
187
208
  validation_start = datetime.now()
188
-
209
+
189
210
  # Check cache first (FinOps pattern for performance)
190
211
  cache_key = f"{candidate.vpc_id}_{candidate.account_id}_{validation_start.date()}"
191
212
  if cache_key in self.validation_cache:
192
213
  cached_result = self.validation_cache[cache_key]
193
- if (validation_start - datetime.fromisoformat(cached_result['cached_at'])).seconds < self.cache_ttl:
214
+ if (validation_start - datetime.fromisoformat(cached_result["cached_at"])).seconds < self.cache_ttl:
194
215
  print_info(f"Using cached validation for {candidate.vpc_id}")
195
- return cached_result['success'], cached_result['accuracy'], cached_result['details']
196
-
216
+ return cached_result["success"], cached_result["accuracy"], cached_result["details"]
217
+
197
218
  try:
198
- ec2_client = self.session.client('ec2')
199
-
219
+ ec2_client = self.session.client("ec2")
220
+
200
221
  # Time-synchronized validation (critical for accuracy)
201
222
  validation_time_sync = validation_start
202
-
223
+
203
224
  # Enhanced VPC existence and metadata validation
204
225
  vpc_response = ec2_client.describe_vpcs(VpcIds=[candidate.vpc_id])
205
- if not vpc_response['Vpcs']:
226
+ if not vpc_response["Vpcs"]:
206
227
  error_result = {
207
228
  "error": "VPC not found in AWS API",
208
229
  "validation_timestamp": validation_time_sync.isoformat(),
209
230
  "time_sync_enabled": True,
210
- "profile_used": self.profile
231
+ "profile_used": self.profile,
211
232
  }
212
233
  return False, 0.0, error_result
213
-
214
- vpc_data = vpc_response['Vpcs'][0]
234
+
235
+ vpc_data = vpc_response["Vpcs"][0]
215
236
  validation_details = {
216
237
  "validation_method": "enhanced_vpc_mcp_with_time_sync",
217
238
  "validation_timestamp": validation_time_sync.isoformat(),
@@ -222,135 +243,134 @@ class VPCMCPValidator:
222
243
  "vpc_id": candidate.vpc_id,
223
244
  "cidr_block": candidate.cidr_block,
224
245
  "is_default": candidate.is_default,
225
- "eni_count": getattr(candidate, 'eni_count', None)
226
- }
246
+ "eni_count": getattr(candidate, "eni_count", None),
247
+ },
227
248
  }
228
249
  accuracy_points = []
229
-
250
+
230
251
  # Enhanced CIDR block validation
231
- api_cidr = vpc_data.get('CidrBlock', '')
252
+ api_cidr = vpc_data.get("CidrBlock", "")
232
253
  if candidate.cidr_block:
233
254
  cidr_match = api_cidr == candidate.cidr_block
234
255
  accuracy_points.append(cidr_match)
235
- validation_details['cidr_validation'] = {
236
- 'expected': candidate.cidr_block,
237
- 'actual': api_cidr,
238
- 'match': cidr_match,
239
- 'validation_type': 'exact_match'
256
+ validation_details["cidr_validation"] = {
257
+ "expected": candidate.cidr_block,
258
+ "actual": api_cidr,
259
+ "match": cidr_match,
260
+ "validation_type": "exact_match",
240
261
  }
241
-
262
+
242
263
  # Enhanced default VPC status validation
243
- is_default_api = vpc_data.get('IsDefault', False)
264
+ is_default_api = vpc_data.get("IsDefault", False)
244
265
  default_match = is_default_api == candidate.is_default
245
266
  accuracy_points.append(default_match)
246
- validation_details['default_vpc_validation'] = {
247
- 'expected': candidate.is_default,
248
- 'actual': is_default_api,
249
- 'match': default_match,
250
- 'validation_type': 'boolean_match'
267
+ validation_details["default_vpc_validation"] = {
268
+ "expected": candidate.is_default,
269
+ "actual": is_default_api,
270
+ "match": default_match,
271
+ "validation_type": "boolean_match",
251
272
  }
252
-
273
+
253
274
  # Enhanced tag validation
254
- api_tags = {tag['Key']: tag['Value'] for tag in vpc_data.get('Tags', [])}
255
- vpc_name_from_tags = api_tags.get('Name', '')
275
+ api_tags = {tag["Key"]: tag["Value"] for tag in vpc_data.get("Tags", [])}
276
+ vpc_name_from_tags = api_tags.get("Name", "")
256
277
  if candidate.vpc_name:
257
278
  name_match = vpc_name_from_tags == candidate.vpc_name
258
279
  accuracy_points.append(name_match)
259
- validation_details['name_validation'] = {
260
- 'expected': candidate.vpc_name,
261
- 'actual': vpc_name_from_tags,
262
- 'match': name_match,
263
- 'validation_type': 'string_match'
280
+ validation_details["name_validation"] = {
281
+ "expected": candidate.vpc_name,
282
+ "actual": vpc_name_from_tags,
283
+ "match": name_match,
284
+ "validation_type": "string_match",
264
285
  }
265
-
286
+
266
287
  # Enhanced ENI count validation with dependency analysis
267
288
  eni_response = ec2_client.describe_network_interfaces(
268
- Filters=[{'Name': 'vpc-id', 'Values': [candidate.vpc_id]}]
289
+ Filters=[{"Name": "vpc-id", "Values": [candidate.vpc_id]}]
269
290
  )
270
- api_eni_count = len(eni_response['NetworkInterfaces'])
271
-
291
+ api_eni_count = len(eni_response["NetworkInterfaces"])
292
+
272
293
  # Use tolerance for ENI count (infrastructure can change slightly)
273
294
  eni_tolerance = 1 # Allow ±1 ENI variance
274
295
  eni_match = abs(api_eni_count - candidate.eni_count) <= eni_tolerance
275
296
  accuracy_points.append(eni_match)
276
- validation_details['eni_count_validation'] = {
277
- 'expected': candidate.eni_count,
278
- 'actual': api_eni_count,
279
- 'match': eni_match,
280
- 'tolerance': eni_tolerance,
281
- 'validation_type': 'count_match_with_tolerance',
282
- 'eni_details': [eni['NetworkInterfaceId'] for eni in eni_response['NetworkInterfaces']],
283
- 'cleanup_ready': api_eni_count == 0
297
+ validation_details["eni_count_validation"] = {
298
+ "expected": candidate.eni_count,
299
+ "actual": api_eni_count,
300
+ "match": eni_match,
301
+ "tolerance": eni_tolerance,
302
+ "validation_type": "count_match_with_tolerance",
303
+ "eni_details": [eni["NetworkInterfaceId"] for eni in eni_response["NetworkInterfaces"]],
304
+ "cleanup_ready": api_eni_count == 0,
284
305
  }
285
-
306
+
286
307
  # VPC state validation
287
- vpc_state = vpc_data.get('State', 'unknown')
288
- validation_details['vpc_state'] = {
289
- 'state': vpc_state,
290
- 'available': vpc_state == 'available'
291
- }
292
-
308
+ vpc_state = vpc_data.get("State", "unknown")
309
+ validation_details["vpc_state"] = {"state": vpc_state, "available": vpc_state == "available"}
310
+
293
311
  # Calculate enhanced accuracy using FinOps methodology
294
312
  accuracy = (sum(accuracy_points) / len(accuracy_points)) * 100 if accuracy_points else 0
295
313
  validation_success = accuracy >= self.accuracy_threshold
296
-
314
+
297
315
  # Enhanced validation details
298
- validation_details.update({
299
- 'overall_accuracy': accuracy,
300
- 'accuracy_points_evaluated': len(accuracy_points),
301
- 'accuracy_threshold': self.accuracy_threshold,
302
- 'passed_threshold': validation_success,
303
- 'validation_duration_ms': (datetime.now() - validation_start).total_seconds() * 1000,
304
- 'cache_key': cache_key,
305
- 'validation_source': 'enhanced_aws_ec2_api_with_time_sync'
306
- })
307
-
316
+ validation_details.update(
317
+ {
318
+ "overall_accuracy": accuracy,
319
+ "accuracy_points_evaluated": len(accuracy_points),
320
+ "accuracy_threshold": self.accuracy_threshold,
321
+ "passed_threshold": validation_success,
322
+ "validation_duration_ms": (datetime.now() - validation_start).total_seconds() * 1000,
323
+ "cache_key": cache_key,
324
+ "validation_source": "enhanced_aws_ec2_api_with_time_sync",
325
+ }
326
+ )
327
+
308
328
  # Cache result for performance (FinOps pattern)
309
329
  cache_entry = {
310
- 'success': validation_success,
311
- 'accuracy': accuracy,
312
- 'details': validation_details,
313
- 'cached_at': validation_start.isoformat()
330
+ "success": validation_success,
331
+ "accuracy": accuracy,
332
+ "details": validation_details,
333
+ "cached_at": validation_start.isoformat(),
314
334
  }
315
335
  self.validation_cache[cache_key] = cache_entry
316
-
336
+
317
337
  return validation_success, accuracy, validation_details
318
-
338
+
319
339
  except ClientError as e:
320
340
  error_details = {
321
- 'error': f"AWS API Error: {e}",
322
- 'error_code': e.response.get('Error', {}).get('Code', 'Unknown'),
323
- 'error_type': 'AWS_CLIENT_ERROR',
324
- 'validation_timestamp': validation_start.isoformat(),
325
- 'time_sync_enabled': True,
326
- 'profile_used': self.profile,
327
- 'validation_method': 'enhanced_vpc_mcp_with_time_sync',
328
- 'validation_duration_ms': (datetime.now() - validation_start).total_seconds() * 1000
341
+ "error": f"AWS API Error: {e}",
342
+ "error_code": e.response.get("Error", {}).get("Code", "Unknown"),
343
+ "error_type": "AWS_CLIENT_ERROR",
344
+ "validation_timestamp": validation_start.isoformat(),
345
+ "time_sync_enabled": True,
346
+ "profile_used": self.profile,
347
+ "validation_method": "enhanced_vpc_mcp_with_time_sync",
348
+ "validation_duration_ms": (datetime.now() - validation_start).total_seconds() * 1000,
329
349
  }
330
350
  print_warning(f"AWS API error for {candidate.vpc_id}: {e.response.get('Error', {}).get('Code', 'Unknown')}")
331
351
  return False, 0.0, error_details
332
352
  except Exception as e:
333
353
  error_details = {
334
- 'error': f"Enhanced validation error: {str(e)}",
335
- 'error_type': type(e).__name__,
336
- 'validation_timestamp': validation_start.isoformat(),
337
- 'time_sync_enabled': True,
338
- 'profile_used': self.profile,
339
- 'validation_method': 'enhanced_vpc_mcp_with_time_sync',
340
- 'validation_duration_ms': (datetime.now() - validation_start).total_seconds() * 1000
354
+ "error": f"Enhanced validation error: {str(e)}",
355
+ "error_type": type(e).__name__,
356
+ "validation_timestamp": validation_start.isoformat(),
357
+ "time_sync_enabled": True,
358
+ "profile_used": self.profile,
359
+ "validation_method": "enhanced_vpc_mcp_with_time_sync",
360
+ "validation_duration_ms": (datetime.now() - validation_start).total_seconds() * 1000,
341
361
  }
342
362
  print_warning(f"Enhanced validation failed for {candidate.vpc_id}: {e}")
343
363
  return False, 0.0, error_details
344
-
364
+
345
365
  def generate_sha256_evidence(self, validation_results: List[Dict[str, Any]]) -> str:
346
366
  """
347
367
  Generate SHA256 hash for validation evidence integrity.
348
-
368
+
349
369
  Implements cryptographic verification for audit compliance (FinOps pattern).
350
370
  """
351
371
  import hashlib
352
372
  import json
353
-
373
+
354
374
  # Create deterministic evidence string
355
375
  evidence_data = {
356
376
  "validator_type": "enhanced_vpc_mcp_with_finops_patterns",
@@ -362,83 +382,85 @@ class VPCMCPValidator:
362
382
  "vpc_id": result.get("candidate_data", {}).get("vpc_id"),
363
383
  "accuracy": result.get("overall_accuracy", 0),
364
384
  "passed": result.get("passed_threshold", False),
365
- "timestamp": result.get("validation_timestamp")
385
+ "timestamp": result.get("validation_timestamp"),
366
386
  }
367
- for result in validation_results if isinstance(result, dict)
368
- ]
387
+ for result in validation_results
388
+ if isinstance(result, dict)
389
+ ],
369
390
  }
370
-
391
+
371
392
  evidence_json = json.dumps(evidence_data, sort_keys=True)
372
393
  sha256_hash = hashlib.sha256(evidence_json.encode()).hexdigest()
373
-
394
+
374
395
  print_info(f"SHA256 evidence hash generated: {sha256_hash[:16]}...")
375
396
  return sha256_hash
376
-
397
+
377
398
  async def validate_multiple_candidates_parallel(self, candidates: List[VPCCandidate]) -> Dict[str, Any]:
378
399
  """
379
400
  Enhanced parallel validation using proven FinOps patterns.
380
-
401
+
381
402
  Processes multiple VPC candidates concurrently for <30s performance target.
382
403
  """
383
404
  from concurrent.futures import ThreadPoolExecutor, as_completed
384
-
405
+
385
406
  validation_start = datetime.now()
386
407
  print_info(f"Starting parallel enhanced MCP validation for {len(candidates)} VPC candidates")
387
-
408
+
388
409
  validation_results = []
389
410
  accuracy_scores = []
390
-
411
+
391
412
  # Use ThreadPoolExecutor for parallel processing (FinOps pattern)
392
413
  with Progress(
393
414
  SpinnerColumn(),
394
415
  TextColumn("[progress.description]{task.description}"),
395
416
  BarColumn(),
396
417
  TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
397
- console=self.console
418
+ console=self.console,
398
419
  ) as progress:
399
420
  task = progress.add_task("[cyan]Enhanced Parallel VPC Validation...", total=len(candidates))
400
-
421
+
401
422
  # Process candidates in parallel with max workers based on profile count
402
423
  max_workers = min(5, len(candidates)) # Limit concurrent AWS API calls
403
-
424
+
404
425
  async def validate_candidate_wrapper(candidate):
405
426
  """Wrapper for async validation in thread pool."""
406
427
  return await self.validate_vpc_candidate(candidate)
407
-
428
+
408
429
  # Execute validations in parallel
409
430
  import asyncio
410
- validation_tasks = [
411
- validate_candidate_wrapper(candidate) for candidate in candidates
412
- ]
413
-
431
+
432
+ validation_tasks = [validate_candidate_wrapper(candidate) for candidate in candidates]
433
+
414
434
  completed_validations = await asyncio.gather(*validation_tasks, return_exceptions=True)
415
-
435
+
416
436
  for i, result in enumerate(completed_validations):
417
437
  if isinstance(result, Exception):
418
438
  print_warning(f"Validation exception for {candidates[i].vpc_id}: {result}")
419
- validation_results.append({
420
- "error": str(result),
421
- "vpc_id": candidates[i].vpc_id,
422
- "overall_accuracy": 0.0,
423
- "passed_threshold": False,
424
- "validation_timestamp": datetime.now().isoformat()
425
- })
439
+ validation_results.append(
440
+ {
441
+ "error": str(result),
442
+ "vpc_id": candidates[i].vpc_id,
443
+ "overall_accuracy": 0.0,
444
+ "passed_threshold": False,
445
+ "validation_timestamp": datetime.now().isoformat(),
446
+ }
447
+ )
426
448
  accuracy_scores.append(0.0)
427
449
  else:
428
450
  success, accuracy, details = result
429
451
  validation_results.append(details)
430
452
  accuracy_scores.append(accuracy)
431
-
453
+
432
454
  progress.advance(task)
433
-
455
+
434
456
  # Calculate final metrics
435
457
  average_accuracy = sum(accuracy_scores) / len(accuracy_scores) if accuracy_scores else 0.0
436
458
  validated_count = sum(1 for score in accuracy_scores if score >= self.accuracy_threshold)
437
459
  validation_duration = (datetime.now() - validation_start).total_seconds()
438
-
460
+
439
461
  # Generate SHA256 evidence
440
462
  sha256_evidence = self.generate_sha256_evidence(validation_results)
441
-
463
+
442
464
  # Enhanced results with FinOps pattern compliance
443
465
  results = {
444
466
  "validation_timestamp": validation_start.isoformat(),
@@ -451,45 +473,49 @@ class VPCMCPValidator:
451
473
  "validation_method": "enhanced_parallel_vpc_mcp_with_finops_patterns",
452
474
  "evidence_sha256": sha256_evidence,
453
475
  "validation_results": validation_results,
454
- "cache_utilization": len([r for r in validation_results if 'cache_key' in r]) / len(validation_results) if validation_results else 0
476
+ "cache_utilization": len([r for r in validation_results if "cache_key" in r]) / len(validation_results)
477
+ if validation_results
478
+ else 0,
455
479
  }
456
-
480
+
457
481
  # Display results using Rich CLI standards
458
482
  if average_accuracy >= self.accuracy_threshold:
459
483
  print_success(f"Enhanced MCP Validation: {average_accuracy:.1f}% accuracy (≥99.5% target achieved)")
460
484
  else:
461
485
  print_warning(f"Enhanced MCP Validation: {average_accuracy:.1f}% accuracy (below 99.5% target)")
462
-
486
+
463
487
  if validation_duration <= 30.0:
464
488
  print_success(f"Performance target achieved: {validation_duration:.1f}s (≤30s enterprise target)")
465
489
  else:
466
490
  print_warning(f"Performance target missed: {validation_duration:.1f}s (>30s enterprise target)")
467
-
491
+
468
492
  print_info(f"SHA256 evidence: {sha256_evidence[:32]}... ({validated_count}/{len(candidates)} VPCs validated)")
469
-
493
+
470
494
  return results
471
495
 
472
- async def validate_cross_deliverable_consistency(self, vpc_candidates: List['VPCCleanupCandidate']) -> Dict[str, Any]:
496
+ async def validate_cross_deliverable_consistency(
497
+ self, vpc_candidates: List["VPCCleanupCandidate"]
498
+ ) -> Dict[str, Any]:
473
499
  """
474
500
  Validate MCP consistency across all VPC cleanup deliverables.
475
-
501
+
476
502
  Ensures consistent validation results across:
477
503
  - Shell scripts (vpc-cleanup.sh)
478
504
  - Jupyter notebooks (vpc-cleanup.ipynb, vpc-cleanup-executive.ipynb)
479
505
  - Documentation (vpc-cleanup.md)
480
506
  - API modules (unified_scenarios.py)
481
-
507
+
482
508
  Returns validation report with consistency metrics.
483
509
  """
484
510
  consistency_start = datetime.now()
485
511
  print_header("Cross-Deliverable Consistency Validation")
486
-
512
+
487
513
  # Track validation results per deliverable format
488
514
  deliverable_results = {}
489
-
515
+
490
516
  with create_progress_bar() as progress:
491
517
  task = progress.add_task("[cyan]Cross-deliverable validation...", total=4)
492
-
518
+
493
519
  # 1. API module validation (current implementation)
494
520
  try:
495
521
  api_results = await self.validate_multiple_candidates_parallel(vpc_candidates)
@@ -497,7 +523,7 @@ class VPCMCPValidator:
497
523
  "accuracy": api_results["average_accuracy"],
498
524
  "passed_threshold": api_results["passed_threshold"],
499
525
  "evidence_sha256": api_results["evidence_sha256"],
500
- "validation_count": api_results["validated_count"]
526
+ "validation_count": api_results["validated_count"],
501
527
  }
502
528
  progress.advance(task)
503
529
  print_success(f"API Module: {api_results['average_accuracy']:.1f}% accuracy")
@@ -505,7 +531,7 @@ class VPCMCPValidator:
505
531
  deliverable_results["api_module"] = {"error": str(e), "accuracy": 0.0}
506
532
  print_error(f"API Module validation failed: {e}")
507
533
  progress.advance(task)
508
-
534
+
509
535
  # 2. Shell script validation compatibility
510
536
  try:
511
537
  shell_results = await self._validate_shell_script_compatibility(vpc_candidates)
@@ -516,7 +542,7 @@ class VPCMCPValidator:
516
542
  deliverable_results["shell_script"] = {"error": str(e), "accuracy": 0.0}
517
543
  print_error(f"Shell script validation failed: {e}")
518
544
  progress.advance(task)
519
-
545
+
520
546
  # 3. Jupyter notebook validation compatibility
521
547
  try:
522
548
  notebook_results = await self._validate_notebook_compatibility(vpc_candidates)
@@ -527,7 +553,7 @@ class VPCMCPValidator:
527
553
  deliverable_results["jupyter_notebooks"] = {"error": str(e), "accuracy": 0.0}
528
554
  print_error(f"Notebook validation failed: {e}")
529
555
  progress.advance(task)
530
-
556
+
531
557
  # 4. Documentation consistency validation
532
558
  try:
533
559
  docs_results = await self._validate_documentation_consistency(vpc_candidates)
@@ -538,16 +564,17 @@ class VPCMCPValidator:
538
564
  deliverable_results["documentation"] = {"error": str(e), "accuracy": 0.0}
539
565
  print_error(f"Documentation validation failed: {e}")
540
566
  progress.advance(task)
541
-
567
+
542
568
  # Calculate cross-deliverable consistency metrics
543
569
  accuracies = [
544
- result["accuracy"] for result in deliverable_results.values()
570
+ result["accuracy"]
571
+ for result in deliverable_results.values()
545
572
  if "accuracy" in result and result["accuracy"] > 0
546
573
  ]
547
-
574
+
548
575
  overall_accuracy = sum(accuracies) / len(accuracies) if accuracies else 0.0
549
576
  consistency_duration = (datetime.now() - consistency_start).total_seconds()
550
-
577
+
551
578
  # Generate consistency report
552
579
  consistency_report = {
553
580
  "validation_timestamp": consistency_start.isoformat(),
@@ -557,133 +584,140 @@ class VPCMCPValidator:
557
584
  "consistency_duration_seconds": consistency_duration,
558
585
  "deliverable_results": deliverable_results,
559
586
  "consistency_threshold_met": overall_accuracy >= 99.5,
560
- "evidence_sha256": self.generate_sha256_evidence([
561
- {"deliverable": k, "result": v} for k, v in deliverable_results.items()
562
- ])
587
+ "evidence_sha256": self.generate_sha256_evidence(
588
+ [{"deliverable": k, "result": v} for k, v in deliverable_results.items()]
589
+ ),
563
590
  }
564
-
591
+
565
592
  # Display consistency results
566
593
  if overall_accuracy >= 99.5:
567
594
  print_success(f"Cross-deliverable consistency: {overall_accuracy:.1f}% (≥99.5% enterprise target achieved)")
568
595
  else:
569
596
  print_warning(f"Cross-deliverable consistency: {overall_accuracy:.1f}% (below 99.5% enterprise target)")
570
-
597
+
571
598
  print_info(f"Validated {len(deliverable_results)} deliverable formats in {consistency_duration:.1f}s")
572
-
599
+
573
600
  return consistency_report
574
601
 
575
- async def _validate_shell_script_compatibility(self, vpc_candidates: List['VPCCleanupCandidate']) -> Dict[str, Any]:
602
+ async def _validate_shell_script_compatibility(self, vpc_candidates: List["VPCCleanupCandidate"]) -> Dict[str, Any]:
576
603
  """Validate shell script format compatibility with MCP results."""
577
604
  # Check if shell script outputs would match MCP validation results
578
605
  shell_compatible_count = 0
579
606
  total_candidates = len(vpc_candidates)
580
-
607
+
581
608
  for candidate in vpc_candidates:
582
609
  # Simulate shell script validation logic
583
610
  try:
584
611
  # Shell scripts typically validate ENI count and dependency status
585
- eni_count = len(candidate.dependencies.get('network_interfaces', []))
586
- no_dependencies = all(len(deps) == 0 for deps in candidate.dependencies.values() if isinstance(deps, list))
587
-
612
+ eni_count = len(candidate.dependencies.get("network_interfaces", []))
613
+ no_dependencies = all(
614
+ len(deps) == 0 for deps in candidate.dependencies.values() if isinstance(deps, list)
615
+ )
616
+
588
617
  # Shell script would pass this candidate if no ENIs and no dependencies
589
618
  shell_would_pass = eni_count == 0 and no_dependencies
590
-
619
+
591
620
  # Check if our MCP validation would agree
592
621
  mcp_result = await self.validate_vpc_candidate(candidate)
593
622
  mcp_would_pass = mcp_result[0] and mcp_result[1] >= 99.5
594
-
623
+
595
624
  # Count as compatible if both agree
596
625
  if shell_would_pass == mcp_would_pass:
597
626
  shell_compatible_count += 1
598
-
627
+
599
628
  except Exception:
600
629
  # If validation fails, count as incompatible
601
630
  pass
602
-
631
+
603
632
  accuracy = (shell_compatible_count / total_candidates * 100) if total_candidates > 0 else 100.0
604
-
633
+
605
634
  return {
606
635
  "accuracy": accuracy,
607
636
  "compatible_count": shell_compatible_count,
608
637
  "total_candidates": total_candidates,
609
- "validation_method": "shell_script_logic_simulation"
638
+ "validation_method": "shell_script_logic_simulation",
610
639
  }
611
640
 
612
- async def _validate_notebook_compatibility(self, vpc_candidates: List['VPCCleanupCandidate']) -> Dict[str, Any]:
641
+ async def _validate_notebook_compatibility(self, vpc_candidates: List["VPCCleanupCandidate"]) -> Dict[str, Any]:
613
642
  """Validate Jupyter notebook format compatibility with MCP results."""
614
643
  # Notebooks should display same results as MCP validation but in Rich format
615
644
  notebook_compatible_count = 0
616
645
  total_candidates = len(vpc_candidates)
617
-
646
+
618
647
  for candidate in vpc_candidates:
619
648
  try:
620
649
  # Get MCP validation result
621
650
  mcp_result = await self.validate_vpc_candidate(candidate)
622
651
  success, accuracy, details = mcp_result
623
-
652
+
624
653
  # Notebook format should be able to display these results
625
654
  # Check if Rich formatting would work (basic compatibility test)
626
655
  notebook_displayable = (
627
- isinstance(accuracy, (int, float)) and
628
- isinstance(details, dict) and
629
- 'validation_timestamp' in details
656
+ isinstance(accuracy, (int, float))
657
+ and isinstance(details, dict)
658
+ and "validation_timestamp" in details
630
659
  )
631
-
660
+
632
661
  if notebook_displayable:
633
662
  notebook_compatible_count += 1
634
-
663
+
635
664
  except Exception:
636
665
  # If validation fails, count as incompatible
637
666
  pass
638
-
667
+
639
668
  accuracy = (notebook_compatible_count / total_candidates * 100) if total_candidates > 0 else 100.0
640
-
669
+
641
670
  return {
642
671
  "accuracy": accuracy,
643
672
  "compatible_count": notebook_compatible_count,
644
673
  "total_candidates": total_candidates,
645
- "validation_method": "notebook_display_compatibility"
674
+ "validation_method": "notebook_display_compatibility",
646
675
  }
647
676
 
648
- async def _validate_documentation_consistency(self, vpc_candidates: List['VPCCleanupCandidate']) -> Dict[str, Any]:
677
+ async def _validate_documentation_consistency(self, vpc_candidates: List["VPCCleanupCandidate"]) -> Dict[str, Any]:
649
678
  """Validate documentation consistency with MCP validation results."""
650
679
  # Documentation should accurately reflect validation criteria and thresholds
651
680
  doc_consistent_count = 0
652
681
  total_candidates = len(vpc_candidates)
653
-
682
+
654
683
  # Documentation consistency checks
655
684
  consistency_checks = [
656
685
  {"name": "accuracy_threshold", "expected": 99.5, "actual": self.accuracy_threshold},
657
686
  {"name": "performance_target", "expected": 30.0, "actual": 30.0}, # Enterprise <30s target
658
687
  {"name": "validation_method", "expected": "mcp_with_finops_patterns", "actual": "mcp_with_finops_patterns"},
659
688
  ]
660
-
661
- consistent_checks = sum(1 for check in consistency_checks
662
- if (abs(check["expected"] - check["actual"]) < 0.1
663
- if isinstance(check["expected"], (int, float))
664
- else check["expected"] == check["actual"]))
665
-
689
+
690
+ consistent_checks = sum(
691
+ 1
692
+ for check in consistency_checks
693
+ if (
694
+ abs(check["expected"] - check["actual"]) < 0.1
695
+ if isinstance(check["expected"], (int, float))
696
+ else check["expected"] == check["actual"]
697
+ )
698
+ )
699
+
666
700
  # Calculate documentation consistency
667
701
  doc_accuracy = (consistent_checks / len(consistency_checks) * 100) if consistency_checks else 100.0
668
-
702
+
669
703
  return {
670
704
  "accuracy": doc_accuracy,
671
705
  "consistent_checks": consistent_checks,
672
706
  "total_checks": len(consistency_checks),
673
- "validation_method": "documentation_criteria_consistency"
707
+ "validation_method": "documentation_criteria_consistency",
674
708
  }
675
709
 
676
710
 
677
711
  class VPCScenarioEngine:
678
712
  """
679
713
  Unified scenario framework engine for VPC cleanup operations.
680
-
714
+
681
715
  Provides consistent data and formatting across all VPC cleanup deliverables:
682
716
  - vpc-cleanup.sh (shell script text output)
683
717
  - vpc-cleanup.ipynb (Jupyter notebook interactive)
684
718
  - vpc-cleanup-executive.ipynb (executive presentation)
685
719
  - vpc-cleanup.md (documentation)
686
-
720
+
687
721
  Features:
688
722
  - 4-6 critical scenarios with comprehensive validation
689
723
  - MCP cross-validation achieving ≥99.5% accuracy
@@ -691,151 +725,163 @@ class VPCScenarioEngine:
691
725
  - Rich CLI formatting for interactive displays
692
726
  - Enterprise-grade audit trails and evidence generation
693
727
  """
694
-
728
+
695
729
  def __init__(self, profile: str, console: Console = None):
696
730
  """Initialize VPC scenario engine with AWS profile."""
697
731
  self.profile = profile
698
732
  self.console = console or console
699
733
  self.session = create_operational_session(profile)
700
734
  self.mcp_validator = VPCMCPValidator(profile, self.console)
701
-
735
+
702
736
  # Scenario data storage
703
737
  self.vpc_candidates: List[VPCCandidate] = []
704
738
  self.validation_results: Dict[ValidationStep, ValidationStepResult] = {}
705
739
  self.business_impact: Optional[BusinessImpactSummary] = None
706
-
740
+
707
741
  # Performance and audit tracking
708
742
  self.execution_start_time = datetime.now()
709
743
  self.mcp_validation_count = 0
710
744
  self.total_accuracy_score = 0.0
711
-
745
+
712
746
  def discover_vpc_candidates(self, account_ids: Optional[List[str]] = None) -> List[VPCCandidate]:
713
747
  """
714
748
  Discover VPC cleanup candidates across specified accounts.
715
-
749
+
716
750
  Enhanced discovery with comprehensive metadata extraction:
717
751
  - TGW/Peering attachments analysis
718
752
  - Load Balancer presence detection
719
753
  - IaC management identification
720
754
  - CIDR overlapping analysis
721
755
  - Enhanced owner/approval extraction from tags
722
-
756
+
723
757
  Returns complete VPC candidate list for 16-column decision table.
724
758
  """
725
759
  print_header("Enhanced VPC Cleanup Candidate Discovery", "latest version")
726
-
760
+
727
761
  candidates = []
728
762
  sequence_number = 1
729
763
  all_vpc_cidrs = [] # For overlapping analysis
730
-
764
+
731
765
  try:
732
- ec2_client = self.session.client('ec2')
733
- elbv2_client = self.session.client('elbv2') # For ALB/NLB detection
734
- elb_client = self.session.client('elb') # For Classic Load Balancers
735
-
766
+ ec2_client = self.session.client("ec2")
767
+ elbv2_client = self.session.client("elbv2") # For ALB/NLB detection
768
+ elb_client = self.session.client("elb") # For Classic Load Balancers
769
+
736
770
  # If no account IDs specified, use current account
737
771
  if not account_ids:
738
- sts_client = self.session.client('sts')
739
- current_account = sts_client.get_caller_identity()['Account']
772
+ sts_client = self.session.client("sts")
773
+ current_account = sts_client.get_caller_identity()["Account"]
740
774
  account_ids = [current_account]
741
-
775
+
742
776
  print_info(f"Analyzing {len(account_ids)} account(s) for comprehensive VPC metadata")
743
-
777
+
744
778
  # First pass: collect all VPC CIDRs for overlapping analysis
745
779
  for account_id in account_ids:
746
780
  vpcs_response = ec2_client.describe_vpcs()
747
- for vpc_data in vpcs_response['Vpcs']:
748
- cidr_block = vpc_data.get('CidrBlock', '')
781
+ for vpc_data in vpcs_response["Vpcs"]:
782
+ cidr_block = vpc_data.get("CidrBlock", "")
749
783
  if cidr_block:
750
- all_vpc_cidrs.append((vpc_data['VpcId'], cidr_block))
751
-
784
+ all_vpc_cidrs.append((vpc_data["VpcId"], cidr_block))
785
+
752
786
  # Second pass: detailed analysis with all metadata
753
787
  for account_id in account_ids:
754
788
  print_info(f"Comprehensive analysis for account: {account_id}")
755
-
789
+
756
790
  # Discover VPCs in account
757
791
  vpcs_response = ec2_client.describe_vpcs()
758
-
759
- for vpc_data in vpcs_response['Vpcs']:
760
- vpc_id = vpc_data['VpcId']
761
- cidr_block = vpc_data.get('CidrBlock', '')
762
-
792
+
793
+ for vpc_data in vpcs_response["Vpcs"]:
794
+ vpc_id = vpc_data["VpcId"]
795
+ cidr_block = vpc_data.get("CidrBlock", "")
796
+
763
797
  # Extract comprehensive VPC metadata
764
- tags = {tag['Key']: tag['Value'] for tag in vpc_data.get('Tags', [])}
765
- vpc_name = tags.get('Name', f"vpc-{vpc_id[-8:]}")
766
-
798
+ tags = {tag["Key"]: tag["Value"] for tag in vpc_data.get("Tags", [])}
799
+ vpc_name = tags.get("Name", f"vpc-{vpc_id[-8:]}")
800
+
767
801
  # 1. ENI count analysis
768
802
  eni_response = ec2_client.describe_network_interfaces(
769
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
803
+ Filters=[{"Name": "vpc-id", "Values": [vpc_id]}]
770
804
  )
771
- eni_count = len(eni_response['NetworkInterfaces'])
772
-
805
+ eni_count = len(eni_response["NetworkInterfaces"])
806
+
773
807
  # 2. Flow logs detection
774
808
  flow_logs_response = ec2_client.describe_flow_logs(
775
809
  Filters=[
776
- {'Name': 'resource-id', 'Values': [vpc_id]},
777
- {'Name': 'resource-type', 'Values': ['VPC']}
810
+ {"Name": "resource-id", "Values": [vpc_id]},
811
+ {"Name": "resource-type", "Values": ["VPC"]},
778
812
  ]
779
813
  )
780
- flow_logs_enabled = len(flow_logs_response['FlowLogs']) > 0
781
-
814
+ flow_logs_enabled = len(flow_logs_response["FlowLogs"]) > 0
815
+
782
816
  # 3. TGW/Peering attachments analysis
783
817
  tgw_peering_attached = False
784
818
  try:
785
819
  # Check for Transit Gateway attachments
786
820
  tgw_attachments = ec2_client.describe_transit_gateway_vpc_attachments(
787
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
821
+ Filters=[{"Name": "vpc-id", "Values": [vpc_id]}]
788
822
  )
789
- has_tgw = len(tgw_attachments['TransitGatewayVpcAttachments']) > 0
790
-
823
+ has_tgw = len(tgw_attachments["TransitGatewayVpcAttachments"]) > 0
824
+
791
825
  # Check for VPC peering connections
792
826
  peering_connections = ec2_client.describe_vpc_peering_connections(
793
827
  Filters=[
794
- {'Name': 'accepter-vpc-info.vpc-id', 'Values': [vpc_id]},
795
- {'Name': 'requester-vpc-info.vpc-id', 'Values': [vpc_id]}
828
+ {"Name": "accepter-vpc-info.vpc-id", "Values": [vpc_id]},
829
+ {"Name": "requester-vpc-info.vpc-id", "Values": [vpc_id]},
796
830
  ]
797
831
  )
798
- has_peering = len(peering_connections['VpcPeeringConnections']) > 0
799
-
832
+ has_peering = len(peering_connections["VpcPeeringConnections"]) > 0
833
+
800
834
  tgw_peering_attached = has_tgw or has_peering
801
-
835
+
802
836
  except Exception as e:
803
837
  print_warning(f"TGW/Peering check failed for {vpc_id}: {e}")
804
838
  tgw_peering_attached = False
805
-
839
+
806
840
  # 4. Load Balancer presence detection
807
841
  load_balancers_present = False
808
842
  try:
809
843
  # Check ALB/NLB/GLB
810
844
  alb_response = elbv2_client.describe_load_balancers()
811
- alb_in_vpc = [lb for lb in alb_response['LoadBalancers'] if lb.get('VpcId') == vpc_id]
812
-
845
+ alb_in_vpc = [lb for lb in alb_response["LoadBalancers"] if lb.get("VpcId") == vpc_id]
846
+
813
847
  # Check Classic Load Balancers
814
848
  clb_response = elb_client.describe_load_balancers()
815
- clb_in_vpc = [lb for lb in clb_response['LoadBalancerDescriptions'] if lb.get('VPCId') == vpc_id]
816
-
849
+ clb_in_vpc = [
850
+ lb for lb in clb_response["LoadBalancerDescriptions"] if lb.get("VPCId") == vpc_id
851
+ ]
852
+
817
853
  load_balancers_present = len(alb_in_vpc) > 0 or len(clb_in_vpc) > 0
818
-
854
+
819
855
  except Exception as e:
820
856
  print_warning(f"Load Balancer check failed for {vpc_id}: {e}")
821
857
  load_balancers_present = False
822
-
858
+
823
859
  # 5. IaC management detection from tags
824
860
  iac_managed = False
825
861
  iac_indicators = [
826
- 'terraform', 'cloudformation', 'cdk', 'pulumi', 'ansible',
827
- 'managed-by', 'created-by', 'stack-name', 'cdktf'
862
+ "terraform",
863
+ "cloudformation",
864
+ "cdk",
865
+ "pulumi",
866
+ "ansible",
867
+ "managed-by",
868
+ "created-by",
869
+ "stack-name",
870
+ "cdktf",
828
871
  ]
829
872
  for tag_key, tag_value in tags.items():
830
- if any(indicator in tag_key.lower() or indicator in tag_value.lower()
831
- for indicator in iac_indicators):
873
+ if any(
874
+ indicator in tag_key.lower() or indicator in tag_value.lower()
875
+ for indicator in iac_indicators
876
+ ):
832
877
  iac_managed = True
833
878
  break
834
-
879
+
835
880
  # 6. CIDR overlapping analysis
836
881
  overlapping = False
837
882
  try:
838
883
  import ipaddress
884
+
839
885
  current_network = ipaddress.IPv4Network(cidr_block, strict=False)
840
886
  for other_vpc_id, other_cidr in all_vpc_cidrs:
841
887
  if other_vpc_id != vpc_id and other_cidr:
@@ -846,33 +892,46 @@ class VPCScenarioEngine:
846
892
  except Exception as e:
847
893
  print_warning(f"CIDR overlap check failed for {vpc_id}: {e}")
848
894
  overlapping = False
849
-
895
+
850
896
  # 7. Enhanced owner/approval extraction from tags
851
897
  owners = []
852
898
  approval_tags = [
853
- 'Owner', 'owner', 'Team', 'team', 'Contact', 'contact',
854
- 'Approver', 'approver', 'Manager', 'manager', 'Email', 'email',
855
- 'BusinessOwner', 'TechnicalOwner', 'Responsible', 'responsible'
899
+ "Owner",
900
+ "owner",
901
+ "Team",
902
+ "team",
903
+ "Contact",
904
+ "contact",
905
+ "Approver",
906
+ "approver",
907
+ "Manager",
908
+ "manager",
909
+ "Email",
910
+ "email",
911
+ "BusinessOwner",
912
+ "TechnicalOwner",
913
+ "Responsible",
914
+ "responsible",
856
915
  ]
857
-
916
+
858
917
  for tag_name in approval_tags:
859
- tag_value = tags.get(tag_name, '').strip()
918
+ tag_value = tags.get(tag_name, "").strip()
860
919
  if tag_value and tag_value not in owners:
861
920
  owners.append(tag_value)
862
-
921
+
863
922
  # If no owners found in tags, try to extract from naming patterns
864
923
  if not owners:
865
- if '-' in vpc_name:
866
- potential_owner = vpc_name.split('-')[0]
924
+ if "-" in vpc_name:
925
+ potential_owner = vpc_name.split("-")[0]
867
926
  if len(potential_owner) > 2: # Reasonable team/owner name
868
927
  owners.append(f"{potential_owner}@company.com (inferred)")
869
-
928
+
870
929
  # 8. Decision and timeline estimation based on analysis
871
930
  decision = VPCDecisionType.INVESTIGATE
872
931
  timeline = "TBD"
873
-
932
+
874
933
  if eni_count == 0 and not tgw_peering_attached and not load_balancers_present:
875
- if vpc_data.get('IsDefault', False):
934
+ if vpc_data.get("IsDefault", False):
876
935
  decision = VPCDecisionType.DELETE_AUTO
877
936
  timeline = "1-2 hours"
878
937
  else:
@@ -885,7 +944,7 @@ class VPCScenarioEngine:
885
944
  else:
886
945
  decision = VPCDecisionType.HOLD
887
946
  timeline = "3-5 days"
888
-
947
+
889
948
  # Create comprehensive VPC candidate
890
949
  candidate = VPCCandidate(
891
950
  sequence_number=sequence_number,
@@ -894,7 +953,7 @@ class VPCScenarioEngine:
894
953
  vpc_name=vpc_name,
895
954
  cidr_block=cidr_block,
896
955
  overlapping=overlapping,
897
- is_default=vpc_data.get('IsDefault', False),
956
+ is_default=vpc_data.get("IsDefault", False),
898
957
  eni_count=eni_count,
899
958
  tags=tags,
900
959
  flow_logs_enabled=flow_logs_enabled,
@@ -904,38 +963,46 @@ class VPCScenarioEngine:
904
963
  cleanup_timeline=timeline,
905
964
  decision=decision,
906
965
  owners_approvals=owners,
907
- notes=f"Enhanced discovery at {datetime.now().isoformat()} - {len(owners)} owners identified"
966
+ notes=f"Enhanced discovery at {datetime.now().isoformat()} - {len(owners)} owners identified",
908
967
  )
909
-
968
+
910
969
  candidates.append(candidate)
911
970
  sequence_number += 1
912
-
971
+
913
972
  # Enhanced progress reporting
914
- status_emoji = "🔴" if decision == VPCDecisionType.HOLD else "🟡" if decision == VPCDecisionType.INVESTIGATE else "🟢"
915
- print_info(f" {status_emoji} VPC: {vpc_id} ({vpc_name}) - {eni_count} ENIs, {len(owners)} owners, {timeline}")
916
-
973
+ status_emoji = (
974
+ "🔴"
975
+ if decision == VPCDecisionType.HOLD
976
+ else "🟡"
977
+ if decision == VPCDecisionType.INVESTIGATE
978
+ else "🟢"
979
+ )
980
+ print_info(
981
+ f" {status_emoji} VPC: {vpc_id} ({vpc_name}) - {eni_count} ENIs, {len(owners)} owners, {timeline}"
982
+ )
983
+
917
984
  except ClientError as e:
918
985
  print_error(f"AWS API error during enhanced discovery: {e}")
919
986
  raise
920
987
  except Exception as e:
921
988
  print_error(f"Enhanced discovery error: {str(e)}")
922
989
  raise
923
-
990
+
924
991
  self.vpc_candidates = candidates
925
992
  print_success(f"Enhanced discovery complete: {len(candidates)} VPC candidates with comprehensive metadata")
926
993
  print_info(f"Analysis breakdown: TGW/Peering, Load Balancers, IaC detection, CIDR overlap, owner extraction")
927
-
994
+
928
995
  return candidates
929
-
996
+
930
997
  def get_enterprise_optimized_vpc_candidates(self) -> List[VPCCandidate]:
931
998
  """
932
999
  Get VPC candidates sorted using enterprise-optimized strategy.
933
-
1000
+
934
1001
  Multi-level sorting for optimal stakeholder workflow:
935
1002
  1. PRIMARY: Decision (business priority workflow)
936
- 2. SECONDARY: ENI_Count (safety/complexity assessment)
1003
+ 2. SECONDARY: ENI_Count (safety/complexity assessment)
937
1004
  3. TERTIARY: Account_ID (multi-account coordination)
938
-
1005
+
939
1006
  Business rationale:
940
1007
  - Quick wins (DELETE_AUTO, DELETE_MANUAL) appear first
941
1008
  - Within each decision group: 0 ENI VPCs prioritized (safety-first)
@@ -943,45 +1010,47 @@ class VPCScenarioEngine:
943
1010
  """
944
1011
  if not self.vpc_candidates:
945
1012
  return []
946
-
1013
+
947
1014
  # Define decision priority order for business workflow efficiency
948
1015
  decision_priority = {
949
- VPCDecisionType.DELETE_AUTO: 1, # Highest priority - immediate wins
950
- VPCDecisionType.DELETE_MANUAL: 2, # Second priority - quick wins
951
- VPCDecisionType.INVESTIGATE: 3, # Medium priority - analysis required
952
- VPCDecisionType.DELETE_IAC: 4, # Lower priority - coordinated deletion
953
- VPCDecisionType.HOLD: 5 # Lowest priority - complex cases
1016
+ VPCDecisionType.DELETE_AUTO: 1, # Highest priority - immediate wins
1017
+ VPCDecisionType.DELETE_MANUAL: 2, # Second priority - quick wins
1018
+ VPCDecisionType.INVESTIGATE: 3, # Medium priority - analysis required
1019
+ VPCDecisionType.DELETE_IAC: 4, # Lower priority - coordinated deletion
1020
+ VPCDecisionType.HOLD: 5, # Lowest priority - complex cases
954
1021
  }
955
-
1022
+
956
1023
  # Sort using multi-level strategy
957
1024
  sorted_candidates = sorted(
958
1025
  self.vpc_candidates,
959
1026
  key=lambda vpc: (
960
1027
  decision_priority.get(vpc.decision, 999), # Primary: Business workflow priority
961
- vpc.eni_count, # Secondary: Safety (0 ENI first)
962
- vpc.account_id or "zzzz" # Tertiary: Account coordination
963
- )
1028
+ vpc.eni_count, # Secondary: Safety (0 ENI first)
1029
+ vpc.account_id or "zzzz", # Tertiary: Account coordination
1030
+ ),
1031
+ )
1032
+
1033
+ print_success(
1034
+ f"✅ Enterprise sorting applied: {len(sorted_candidates)} VPCs ordered by decision priority, safety, and account coordination"
964
1035
  )
965
-
966
- print_success(f"✅ Enterprise sorting applied: {len(sorted_candidates)} VPCs ordered by decision priority, safety, and account coordination")
967
1036
  return sorted_candidates
968
1037
 
969
1038
  def generate_vpc_candidate_table_markdown(self) -> str:
970
1039
  """
971
1040
  Generate comprehensive Markdown table of VPC candidates with all 16 columns.
972
-
1041
+
973
1042
  Uses enterprise-optimized sorting for stakeholder workflow efficiency.
974
-
1043
+
975
1044
  Implements WIP.md requirements for candidate VPC decision table:
976
- #, Account_ID, VPC_ID, VPC_Name, CIDR_Block, Overlapping, Is_Default,
977
- ENI_Count, Tags, Flow_Logs, TGW/Peering, LBs_Present, IaC, Timeline,
1045
+ #, Account_ID, VPC_ID, VPC_Name, CIDR_Block, Overlapping, Is_Default,
1046
+ ENI_Count, Tags, Flow_Logs, TGW/Peering, LBs_Present, IaC, Timeline,
978
1047
  Decision, Owners/Approvals, Notes
979
1048
  """
980
1049
  if not self.vpc_candidates:
981
1050
  return "⚠️ No VPC candidates discovered. Run discover_vpc_candidates() first."
982
-
1051
+
983
1052
  print_header("Generating VPC Candidate Decision Table", "Markdown Export")
984
-
1053
+
985
1054
  # Markdown table header
986
1055
  markdown_lines = [
987
1056
  "# VPC Cleanup Candidate Decision Table",
@@ -992,7 +1061,7 @@ class VPCScenarioEngine:
992
1061
  "",
993
1062
  "## Status Legend",
994
1063
  "- **DELETE (IaC)** = Remove via Infrastructure as Code",
995
- "- **DELETE (manual)** = Controlled CLI/Console removal",
1064
+ "- **DELETE (manual)** = Controlled CLI/Console removal",
996
1065
  "- **DELETE (auto)** = Automated via Runbooks/MCP",
997
1066
  "- **HOLD** = Pending owner/traffic analysis",
998
1067
  "- **INVESTIGATE** = Dependency/traffic ambiguity",
@@ -1000,34 +1069,34 @@ class VPCScenarioEngine:
1000
1069
  "## Comprehensive VPC Analysis Table",
1001
1070
  "",
1002
1071
  "| # | Account_ID | VPC_ID | VPC_Name | CIDR_Block | Overlapping | Is_Default | ENI_Count | Tags | Flow_Logs | TGW/Peering | LBs_Present | IaC | Timeline | Decision | Owners/Approvals | Notes |",
1003
- "|---|------------|--------|----------|------------|-------------|------------|-----------|------|-----------|-------------|-------------|-----|----------|----------|------------------|-------|"
1072
+ "|---|------------|--------|----------|------------|-------------|------------|-----------|------|-----------|-------------|-------------|-----|----------|----------|------------------|-------|",
1004
1073
  ]
1005
-
1074
+
1006
1075
  # Add data rows using enterprise-optimized sorting
1007
1076
  sorted_candidates = self.get_enterprise_optimized_vpc_candidates()
1008
1077
  for candidate in sorted_candidates:
1009
1078
  # Format tags for display (first 3 most relevant tags)
1010
1079
  relevant_tags = []
1011
1080
  if candidate.tags:
1012
- priority_keys = ['Name', 'Environment', 'Project', 'Application', 'Owner', 'Team']
1081
+ priority_keys = ["Name", "Environment", "Project", "Application", "Owner", "Team"]
1013
1082
  for key in priority_keys:
1014
1083
  if key in candidate.tags and len(relevant_tags) < 3:
1015
1084
  relevant_tags.append(f"{key}:{candidate.tags[key]}")
1016
-
1085
+
1017
1086
  # Add other tags if we have space
1018
1087
  for key, value in candidate.tags.items():
1019
1088
  if key not in priority_keys and len(relevant_tags) < 3:
1020
1089
  relevant_tags.append(f"{key}:{value}")
1021
-
1090
+
1022
1091
  tags_display = "; ".join(relevant_tags) if relevant_tags else "None"
1023
1092
  if len(tags_display) > 40: # Truncate if too long
1024
1093
  tags_display = tags_display[:37] + "..."
1025
-
1094
+
1026
1095
  # Format owners/approvals
1027
1096
  owners_display = "; ".join(candidate.owners_approvals) if candidate.owners_approvals else "Unknown"
1028
1097
  if len(owners_display) > 30: # Truncate if too long
1029
1098
  owners_display = owners_display[:27] + "..."
1030
-
1099
+
1031
1100
  # Format boolean values
1032
1101
  overlapping = "Yes" if candidate.overlapping else "No"
1033
1102
  is_default = "Yes" if candidate.is_default else "No"
@@ -1035,67 +1104,73 @@ class VPCScenarioEngine:
1035
1104
  tgw_peering = "Yes" if candidate.tgw_peering_attached else "No"
1036
1105
  load_balancers = "Yes" if candidate.load_balancers_present else "No"
1037
1106
  iac = "Yes" if candidate.iac_managed else "No"
1038
-
1107
+
1039
1108
  # Create table row
1040
1109
  row = f"| {candidate.sequence_number} | {candidate.account_id} | {candidate.vpc_id} | {candidate.vpc_name} | {candidate.cidr_block} | {overlapping} | {is_default} | {candidate.eni_count} | {tags_display} | {flow_logs} | {tgw_peering} | {load_balancers} | {iac} | {candidate.cleanup_timeline} | {candidate.decision.value} | {owners_display} | {candidate.notes} |"
1041
-
1110
+
1042
1111
  markdown_lines.append(row)
1043
-
1112
+
1044
1113
  # Add summary statistics
1045
1114
  total_vpcs = len(self.vpc_candidates)
1046
1115
  default_vpcs = sum(1 for c in self.vpc_candidates if c.is_default)
1047
- immediate_deletion = sum(1 for c in self.vpc_candidates if c.decision == VPCDecisionType.DELETE_AUTO or c.decision == VPCDecisionType.DELETE_MANUAL)
1116
+ immediate_deletion = sum(
1117
+ 1
1118
+ for c in self.vpc_candidates
1119
+ if c.decision == VPCDecisionType.DELETE_AUTO or c.decision == VPCDecisionType.DELETE_MANUAL
1120
+ )
1048
1121
  investigation_required = sum(1 for c in self.vpc_candidates if c.decision == VPCDecisionType.INVESTIGATE)
1049
1122
  hold_required = sum(1 for c in self.vpc_candidates if c.decision == VPCDecisionType.HOLD)
1050
1123
  iac_managed_count = sum(1 for c in self.vpc_candidates if c.iac_managed)
1051
-
1052
- markdown_lines.extend([
1053
- "",
1054
- "## Analysis Summary",
1055
- "",
1056
- f"- **Total VPCs Analyzed**: {total_vpcs}",
1057
- f"- **Default VPCs**: {default_vpcs} ({default_vpcs/total_vpcs*100:.1f}%)",
1058
- f"- **Immediate Deletion Candidates**: {immediate_deletion} ({immediate_deletion/total_vpcs*100:.1f}%)",
1059
- f"- **Investigation Required**: {investigation_required} ({investigation_required/total_vpcs*100:.1f}%)",
1060
- f"- **Hold for Owner Review**: {hold_required} ({hold_required/total_vpcs*100:.1f}%)",
1061
- f"- **IaC Managed**: {iac_managed_count} ({iac_managed_count/total_vpcs*100:.1f}%)",
1062
- "",
1063
- "## Next Steps",
1064
- "",
1065
- "1. **Immediate Actions**: Process DELETE candidates with zero dependencies",
1066
- "2. **Investigation Phase**: Analyze INVESTIGATE candidates for hidden dependencies",
1067
- "3. **Owner Approval**: Contact owners for HOLD candidates before proceeding",
1068
- "4. **IaC Coordination**: Update Infrastructure as Code for DELETE (IaC) candidates",
1069
- "",
1070
- f"**Validation**: MCP cross-validated with AWS APIs at {datetime.now().isoformat()}**"
1071
- ])
1072
-
1124
+
1125
+ markdown_lines.extend(
1126
+ [
1127
+ "",
1128
+ "## Analysis Summary",
1129
+ "",
1130
+ f"- **Total VPCs Analyzed**: {total_vpcs}",
1131
+ f"- **Default VPCs**: {default_vpcs} ({default_vpcs / total_vpcs * 100:.1f}%)",
1132
+ f"- **Immediate Deletion Candidates**: {immediate_deletion} ({immediate_deletion / total_vpcs * 100:.1f}%)",
1133
+ f"- **Investigation Required**: {investigation_required} ({investigation_required / total_vpcs * 100:.1f}%)",
1134
+ f"- **Hold for Owner Review**: {hold_required} ({hold_required / total_vpcs * 100:.1f}%)",
1135
+ f"- **IaC Managed**: {iac_managed_count} ({iac_managed_count / total_vpcs * 100:.1f}%)",
1136
+ "",
1137
+ "## Next Steps",
1138
+ "",
1139
+ "1. **Immediate Actions**: Process DELETE candidates with zero dependencies",
1140
+ "2. **Investigation Phase**: Analyze INVESTIGATE candidates for hidden dependencies",
1141
+ "3. **Owner Approval**: Contact owners for HOLD candidates before proceeding",
1142
+ "4. **IaC Coordination**: Update Infrastructure as Code for DELETE (IaC) candidates",
1143
+ "",
1144
+ f"**Validation**: MCP cross-validated with AWS APIs at {datetime.now().isoformat()}**",
1145
+ ]
1146
+ )
1147
+
1073
1148
  markdown_content = "\n".join(markdown_lines)
1074
-
1149
+
1075
1150
  print_success(f"Generated comprehensive decision table with {len(self.vpc_candidates)} VPC candidates")
1076
1151
  print_info(f"Table includes all 16 required columns with enhanced owner extraction")
1077
-
1152
+
1078
1153
  return markdown_content
1079
-
1154
+
1080
1155
  async def scenario_5_governance_orchestration(self) -> Dict[str, Any]:
1081
1156
  """
1082
1157
  Essential Scenario #5: Governance & Compliance Orchestration (5W1H Framework)
1083
-
1158
+
1084
1159
  WHAT: Multi-stakeholder approval workflow for VPC cleanup decisions
1085
- WHY: CIS Benchmark compliance + regulatory audit requirements
1160
+ WHY: CIS Benchmark compliance + regulatory audit requirements
1086
1161
  WHO: Security teams, compliance officers, infrastructure owners
1087
1162
  WHEN: Before any VPC deletion operations (approval gates)
1088
1163
  WHERE: Enterprise governance workflows with audit trails
1089
1164
  HOW: Automated owner identification + approval request generation
1090
-
1165
+
1091
1166
  Returns governance orchestration results with approval matrix.
1092
1167
  """
1093
1168
  print_header("Scenario #5: Governance & Compliance Orchestration", "Enterprise Workflow")
1094
-
1169
+
1095
1170
  if not self.vpc_candidates:
1096
1171
  print_error("No VPC candidates available. Run discover_vpc_candidates() first.")
1097
1172
  return {"error": "No candidates for governance analysis"}
1098
-
1173
+
1099
1174
  governance_start = datetime.now()
1100
1175
  governance_results = {
1101
1176
  "scenario_name": "Governance & Compliance Orchestration",
@@ -1105,73 +1180,77 @@ class VPCScenarioEngine:
1105
1180
  "cis_benchmark_analysis": {},
1106
1181
  "regulatory_compliance": {},
1107
1182
  "stakeholder_notifications": [],
1108
- "audit_trail_entries": []
1183
+ "audit_trail_entries": [],
1109
1184
  }
1110
-
1185
+
1111
1186
  # Multi-stakeholder approval matrix
1112
1187
  approval_matrix = {
1113
1188
  "security_team_approvals": [],
1114
1189
  "compliance_officer_approvals": [],
1115
1190
  "infrastructure_owner_approvals": [],
1116
1191
  "business_stakeholder_approvals": [],
1117
- "emergency_approvals": []
1192
+ "emergency_approvals": [],
1118
1193
  }
1119
-
1194
+
1120
1195
  # CIS Benchmark compliance analysis
1121
1196
  cis_violations = {
1122
1197
  "default_vpcs": [],
1123
1198
  "unencrypted_vpcs": [],
1124
1199
  "no_flow_logs": [],
1125
1200
  "open_security_groups": [],
1126
- "compliance_score": 0.0
1201
+ "compliance_score": 0.0,
1127
1202
  }
1128
-
1203
+
1129
1204
  print_info(f"Analyzing {len(self.vpc_candidates)} VPC candidates for governance requirements...")
1130
-
1205
+
1131
1206
  with create_progress_bar() as progress:
1132
1207
  task = progress.add_task("[cyan]Governance orchestration analysis...", total=len(self.vpc_candidates))
1133
-
1208
+
1134
1209
  for candidate in self.vpc_candidates:
1135
1210
  # 1. Determine required approval stakeholders based on VPC characteristics
1136
1211
  required_approvals = []
1137
-
1212
+
1138
1213
  # Security team approval required for all VPCs
1139
1214
  required_approvals.append("security-team@company.com")
1140
-
1215
+
1141
1216
  # Default VPC requires compliance officer approval (CIS Benchmark)
1142
1217
  if candidate.is_default:
1143
1218
  required_approvals.append("compliance-officer@company.com")
1144
- cis_violations["default_vpcs"].append({
1145
- "vpc_id": candidate.vpc_id,
1146
- "account_id": candidate.account_id,
1147
- "violation": "CIS 4.3 - Default VPC should not be used",
1148
- "risk_level": "HIGH"
1149
- })
1150
-
1219
+ cis_violations["default_vpcs"].append(
1220
+ {
1221
+ "vpc_id": candidate.vpc_id,
1222
+ "account_id": candidate.account_id,
1223
+ "violation": "CIS 4.3 - Default VPC should not be used",
1224
+ "risk_level": "HIGH",
1225
+ }
1226
+ )
1227
+
1151
1228
  # VPCs with no flow logs require compliance review
1152
1229
  if not candidate.flow_logs_enabled:
1153
1230
  required_approvals.append("compliance-officer@company.com")
1154
- cis_violations["no_flow_logs"].append({
1155
- "vpc_id": candidate.vpc_id,
1156
- "account_id": candidate.account_id,
1157
- "violation": "CIS 3.9 - VPC Flow Logs should be enabled",
1158
- "risk_level": "MEDIUM"
1159
- })
1160
-
1231
+ cis_violations["no_flow_logs"].append(
1232
+ {
1233
+ "vpc_id": candidate.vpc_id,
1234
+ "account_id": candidate.account_id,
1235
+ "violation": "CIS 3.9 - VPC Flow Logs should be enabled",
1236
+ "risk_level": "MEDIUM",
1237
+ }
1238
+ )
1239
+
1161
1240
  # VPCs with load balancers or TGW require infrastructure owner approval
1162
1241
  if candidate.load_balancers_present or candidate.tgw_peering_attached:
1163
1242
  required_approvals.append("infrastructure-owner@company.com")
1164
1243
  if candidate.owners_approvals:
1165
1244
  required_approvals.extend(candidate.owners_approvals)
1166
-
1245
+
1167
1246
  # IaC managed VPCs require DevOps approval
1168
1247
  if candidate.iac_managed:
1169
1248
  required_approvals.append("devops-team@company.com")
1170
-
1249
+
1171
1250
  # High ENI count requires business stakeholder approval
1172
1251
  if candidate.eni_count > 5:
1173
1252
  required_approvals.append("business-stakeholder@company.com")
1174
-
1253
+
1175
1254
  # 2. Generate approval request details
1176
1255
  approval_request = {
1177
1256
  "vpc_id": candidate.vpc_id,
@@ -1183,9 +1262,9 @@ class VPCScenarioEngine:
1183
1262
  "risk_assessment": self._assess_governance_risk(candidate),
1184
1263
  "compliance_impact": self._assess_compliance_impact(candidate),
1185
1264
  "approval_deadline": (datetime.now() + timedelta(days=7)).isoformat(),
1186
- "escalation_path": self._determine_escalation_path(candidate)
1265
+ "escalation_path": self._determine_escalation_path(candidate),
1187
1266
  }
1188
-
1267
+
1189
1268
  # 3. Categorize by stakeholder type
1190
1269
  if "security-team@company.com" in required_approvals:
1191
1270
  approval_matrix["security_team_approvals"].append(approval_request)
@@ -1195,134 +1274,154 @@ class VPCScenarioEngine:
1195
1274
  approval_matrix["infrastructure_owner_approvals"].append(approval_request)
1196
1275
  if "business-stakeholder@company.com" in required_approvals:
1197
1276
  approval_matrix["business_stakeholder_approvals"].append(approval_request)
1198
-
1277
+
1199
1278
  # 4. Emergency approval classification
1200
- if (candidate.decision == VPCDecisionType.DELETE_AUTO and
1201
- candidate.is_default and candidate.eni_count == 0):
1202
- approval_matrix["emergency_approvals"].append({
1203
- **approval_request,
1204
- "emergency_reason": "CIS Benchmark compliance violation - immediate action required",
1205
- "fast_track": True
1206
- })
1207
-
1279
+ if (
1280
+ candidate.decision == VPCDecisionType.DELETE_AUTO
1281
+ and candidate.is_default
1282
+ and candidate.eni_count == 0
1283
+ ):
1284
+ approval_matrix["emergency_approvals"].append(
1285
+ {
1286
+ **approval_request,
1287
+ "emergency_reason": "CIS Benchmark compliance violation - immediate action required",
1288
+ "fast_track": True,
1289
+ }
1290
+ )
1291
+
1208
1292
  # 5. Generate audit trail entry
1209
1293
  audit_entry = {
1210
1294
  "timestamp": datetime.now().isoformat(),
1211
1295
  "vpc_id": candidate.vpc_id,
1212
1296
  "action": "governance_analysis_completed",
1213
1297
  "approvals_required": len(required_approvals),
1214
- "compliance_violations": len([v for v in [
1215
- candidate.is_default, not candidate.flow_logs_enabled
1216
- ] if v]),
1298
+ "compliance_violations": len(
1299
+ [v for v in [candidate.is_default, not candidate.flow_logs_enabled] if v]
1300
+ ),
1217
1301
  "risk_score": self._calculate_risk_score(candidate),
1218
1302
  "analyst": "vpc-scenario-engine",
1219
- "evidence_hash": self.mcp_validator.generate_sha256_evidence([approval_request])
1303
+ "evidence_hash": self.mcp_validator.generate_sha256_evidence([approval_request]),
1220
1304
  }
1221
1305
  governance_results["audit_trail_entries"].append(audit_entry)
1222
-
1306
+
1223
1307
  progress.advance(task)
1224
-
1308
+
1225
1309
  # Calculate CIS Benchmark compliance score
1226
1310
  total_violations = len(cis_violations["default_vpcs"]) + len(cis_violations["no_flow_logs"])
1227
1311
  cis_violations["compliance_score"] = max(0, 100 - (total_violations / len(self.vpc_candidates) * 100))
1228
-
1312
+
1229
1313
  # Generate stakeholder notification summaries
1230
1314
  stakeholder_notifications = []
1231
-
1315
+
1232
1316
  if approval_matrix["security_team_approvals"]:
1233
- stakeholder_notifications.append({
1234
- "recipient": "security-team@company.com",
1235
- "subject": f"VPC Cleanup Security Review Required - {len(approval_matrix['security_team_approvals'])} VPCs",
1236
- "priority": "HIGH",
1237
- "vpcs_requiring_approval": len(approval_matrix["security_team_approvals"]),
1238
- "cis_violations": len(cis_violations["default_vpcs"]) + len(cis_violations["no_flow_logs"]),
1239
- "deadline": (datetime.now() + timedelta(days=3)).isoformat()
1240
- })
1241
-
1317
+ stakeholder_notifications.append(
1318
+ {
1319
+ "recipient": "security-team@company.com",
1320
+ "subject": f"VPC Cleanup Security Review Required - {len(approval_matrix['security_team_approvals'])} VPCs",
1321
+ "priority": "HIGH",
1322
+ "vpcs_requiring_approval": len(approval_matrix["security_team_approvals"]),
1323
+ "cis_violations": len(cis_violations["default_vpcs"]) + len(cis_violations["no_flow_logs"]),
1324
+ "deadline": (datetime.now() + timedelta(days=3)).isoformat(),
1325
+ }
1326
+ )
1327
+
1242
1328
  if approval_matrix["compliance_officer_approvals"]:
1243
- stakeholder_notifications.append({
1244
- "recipient": "compliance-officer@company.com",
1245
- "subject": f"VPC Compliance Review Required - CIS Benchmark Violations",
1246
- "priority": "URGENT" if cis_violations["default_vpcs"] else "HIGH",
1247
- "vpcs_requiring_approval": len(approval_matrix["compliance_officer_approvals"]),
1248
- "default_vpc_violations": len(cis_violations["default_vpcs"]),
1249
- "deadline": (datetime.now() + timedelta(days=2)).isoformat()
1250
- })
1251
-
1329
+ stakeholder_notifications.append(
1330
+ {
1331
+ "recipient": "compliance-officer@company.com",
1332
+ "subject": f"VPC Compliance Review Required - CIS Benchmark Violations",
1333
+ "priority": "URGENT" if cis_violations["default_vpcs"] else "HIGH",
1334
+ "vpcs_requiring_approval": len(approval_matrix["compliance_officer_approvals"]),
1335
+ "default_vpc_violations": len(cis_violations["default_vpcs"]),
1336
+ "deadline": (datetime.now() + timedelta(days=2)).isoformat(),
1337
+ }
1338
+ )
1339
+
1252
1340
  if approval_matrix["emergency_approvals"]:
1253
- stakeholder_notifications.append({
1254
- "recipient": "incident-commander@company.com",
1255
- "subject": f"URGENT: Emergency VPC Cleanup Approval Required",
1256
- "priority": "CRITICAL",
1257
- "vpcs_requiring_approval": len(approval_matrix["emergency_approvals"]),
1258
- "reason": "CIS Benchmark compliance violations requiring immediate action",
1259
- "deadline": (datetime.now() + timedelta(hours=24)).isoformat()
1260
- })
1261
-
1341
+ stakeholder_notifications.append(
1342
+ {
1343
+ "recipient": "incident-commander@company.com",
1344
+ "subject": f"URGENT: Emergency VPC Cleanup Approval Required",
1345
+ "priority": "CRITICAL",
1346
+ "vpcs_requiring_approval": len(approval_matrix["emergency_approvals"]),
1347
+ "reason": "CIS Benchmark compliance violations requiring immediate action",
1348
+ "deadline": (datetime.now() + timedelta(hours=24)).isoformat(),
1349
+ }
1350
+ )
1351
+
1262
1352
  # Finalize governance results
1263
1353
  governance_duration = (datetime.now() - governance_start).total_seconds()
1264
-
1265
- governance_results.update({
1266
- "approval_matrix": approval_matrix,
1267
- "cis_benchmark_analysis": cis_violations,
1268
- "stakeholder_notifications": stakeholder_notifications,
1269
- "governance_duration_seconds": governance_duration,
1270
- "total_approvals_required": sum(len(approvals) for approvals in approval_matrix.values()),
1271
- "critical_violations": len(cis_violations["default_vpcs"]),
1272
- "compliance_score": cis_violations["compliance_score"],
1273
- "recommended_action": self._determine_recommended_governance_action(approval_matrix, cis_violations)
1274
- })
1275
-
1354
+
1355
+ governance_results.update(
1356
+ {
1357
+ "approval_matrix": approval_matrix,
1358
+ "cis_benchmark_analysis": cis_violations,
1359
+ "stakeholder_notifications": stakeholder_notifications,
1360
+ "governance_duration_seconds": governance_duration,
1361
+ "total_approvals_required": sum(len(approvals) for approvals in approval_matrix.values()),
1362
+ "critical_violations": len(cis_violations["default_vpcs"]),
1363
+ "compliance_score": cis_violations["compliance_score"],
1364
+ "recommended_action": self._determine_recommended_governance_action(approval_matrix, cis_violations),
1365
+ }
1366
+ )
1367
+
1276
1368
  # Display governance orchestration results
1277
1369
  print_success(f"Governance orchestration complete in {governance_duration:.1f}s")
1278
1370
  print_info(f"Multi-stakeholder approvals required: {governance_results['total_approvals_required']}")
1279
1371
  print_info(f"CIS Benchmark compliance score: {cis_violations['compliance_score']:.1f}%")
1280
-
1372
+
1281
1373
  if cis_violations["default_vpcs"]:
1282
- print_warning(f"CRITICAL: {len(cis_violations['default_vpcs'])} default VPC violations require immediate action")
1374
+ print_warning(
1375
+ f"CRITICAL: {len(cis_violations['default_vpcs'])} default VPC violations require immediate action"
1376
+ )
1283
1377
  if cis_violations["no_flow_logs"]:
1284
1378
  print_warning(f"MEDIUM: {len(cis_violations['no_flow_logs'])} VPCs without flow logs")
1285
-
1379
+
1286
1380
  return governance_results
1287
-
1381
+
1288
1382
  def _generate_approval_rationale(self, candidate: VPCCandidate) -> str:
1289
1383
  """Generate business rationale for approval request."""
1290
1384
  rationale_parts = []
1291
-
1385
+
1292
1386
  if candidate.is_default:
1293
1387
  rationale_parts.append("CIS Benchmark 4.3 compliance - Default VPC elimination")
1294
1388
  if candidate.eni_count == 0:
1295
- rationale_parts.append("Zero network interfaces - no active workloads")
1389
+ rationale_parts.append("Zero network interfaces - no active workloads")
1296
1390
  if not candidate.flow_logs_enabled:
1297
1391
  rationale_parts.append("CIS Benchmark 3.9 compliance - Missing flow logs")
1298
1392
  if candidate.load_balancers_present:
1299
1393
  rationale_parts.append("Active load balancers require graceful migration")
1300
1394
  if candidate.tgw_peering_attached:
1301
1395
  rationale_parts.append("Transit Gateway/Peering dependencies require coordination")
1302
-
1396
+
1303
1397
  return "; ".join(rationale_parts) if rationale_parts else "Standard VPC cleanup evaluation"
1304
-
1398
+
1305
1399
  def _assess_governance_risk(self, candidate: VPCCandidate) -> str:
1306
1400
  """Assess governance risk level for approval workflow."""
1307
1401
  risk_factors = 0
1308
-
1309
- if candidate.eni_count > 0: risk_factors += 2
1310
- if candidate.load_balancers_present: risk_factors += 3
1311
- if candidate.tgw_peering_attached: risk_factors += 3
1312
- if candidate.iac_managed: risk_factors += 1
1313
- if not candidate.owners_approvals: risk_factors += 1
1314
-
1402
+
1403
+ if candidate.eni_count > 0:
1404
+ risk_factors += 2
1405
+ if candidate.load_balancers_present:
1406
+ risk_factors += 3
1407
+ if candidate.tgw_peering_attached:
1408
+ risk_factors += 3
1409
+ if candidate.iac_managed:
1410
+ risk_factors += 1
1411
+ if not candidate.owners_approvals:
1412
+ risk_factors += 1
1413
+
1315
1414
  if risk_factors >= 6:
1316
1415
  return "HIGH"
1317
1416
  elif risk_factors >= 3:
1318
1417
  return "MEDIUM"
1319
1418
  else:
1320
1419
  return "LOW"
1321
-
1420
+
1322
1421
  def _assess_compliance_impact(self, candidate: VPCCandidate) -> str:
1323
1422
  """Assess regulatory compliance impact."""
1324
1423
  impact_factors = []
1325
-
1424
+
1326
1425
  if candidate.is_default:
1327
1426
  impact_factors.append("CIS_4.3_VIOLATION")
1328
1427
  if not candidate.flow_logs_enabled:
@@ -1331,46 +1430,51 @@ class VPCScenarioEngine:
1331
1430
  impact_factors.append("DATA_RESIDENCY_REVIEW")
1332
1431
  if candidate.load_balancers_present:
1333
1432
  impact_factors.append("SERVICE_AVAILABILITY_IMPACT")
1334
-
1433
+
1335
1434
  return "; ".join(impact_factors) if impact_factors else "MINIMAL_COMPLIANCE_IMPACT"
1336
-
1435
+
1337
1436
  def _determine_escalation_path(self, candidate: VPCCandidate) -> List[str]:
1338
1437
  """Determine escalation path for approval delays."""
1339
1438
  escalation_path = ["team-lead@company.com"]
1340
-
1439
+
1341
1440
  if candidate.is_default:
1342
1441
  escalation_path.append("security-manager@company.com")
1343
1442
  if candidate.load_balancers_present or candidate.tgw_peering_attached:
1344
1443
  escalation_path.append("infrastructure-director@company.com")
1345
1444
  if candidate.iac_managed:
1346
1445
  escalation_path.append("devops-manager@company.com")
1347
-
1446
+
1348
1447
  escalation_path.append("cto@company.com") # Final escalation
1349
1448
  return escalation_path
1350
-
1449
+
1351
1450
  def _calculate_risk_score(self, candidate: VPCCandidate) -> float:
1352
1451
  """Calculate numerical risk score (0-100) for governance decisions."""
1353
1452
  base_score = 0.0
1354
-
1453
+
1355
1454
  # ENI count impact (0-30 points)
1356
1455
  base_score += min(30, candidate.eni_count * 3)
1357
-
1456
+
1358
1457
  # Dependency impact (0-40 points)
1359
- if candidate.load_balancers_present: base_score += 20
1360
- if candidate.tgw_peering_attached: base_score += 20
1361
-
1458
+ if candidate.load_balancers_present:
1459
+ base_score += 20
1460
+ if candidate.tgw_peering_attached:
1461
+ base_score += 20
1462
+
1362
1463
  # Compliance impact (0-30 points)
1363
- if candidate.is_default: base_score += 15
1364
- if not candidate.flow_logs_enabled: base_score += 10
1365
- if not candidate.owners_approvals: base_score += 5
1366
-
1464
+ if candidate.is_default:
1465
+ base_score += 15
1466
+ if not candidate.flow_logs_enabled:
1467
+ base_score += 10
1468
+ if not candidate.owners_approvals:
1469
+ base_score += 5
1470
+
1367
1471
  return min(100.0, base_score)
1368
-
1472
+
1369
1473
  def _determine_recommended_governance_action(self, approval_matrix: Dict, cis_violations: Dict) -> str:
1370
1474
  """Determine recommended governance action based on analysis."""
1371
1475
  total_approvals = sum(len(approvals) for approvals in approval_matrix.values())
1372
1476
  critical_violations = len(cis_violations["default_vpcs"])
1373
-
1477
+
1374
1478
  if critical_violations > 0:
1375
1479
  return f"URGENT: Process {critical_violations} critical CIS violations immediately"
1376
1480
  elif total_approvals > 10:
@@ -1379,26 +1483,26 @@ class VPCScenarioEngine:
1379
1483
  return f"STANDARD: Process {total_approvals} approval requests via normal workflow"
1380
1484
  else:
1381
1485
  return "CLEAR: No governance approvals required - proceed with technical validation"
1382
-
1486
+
1383
1487
  async def scenario_6_operational_continuity(self) -> Dict[str, Any]:
1384
1488
  """
1385
1489
  Essential Scenario #6: Operational Continuity & Risk Management (5W1H Framework)
1386
-
1490
+
1387
1491
  WHAT: Business continuity assessment and rollback planning
1388
1492
  WHY: Zero-downtime requirements + disaster recovery validation
1389
1493
  WHO: SRE teams, business stakeholders, incident response
1390
1494
  WHEN: Continuous monitoring during cleanup phases
1391
1495
  WHERE: Production environments with business impact assessment
1392
1496
  HOW: Real-time dependency monitoring + automated rollback triggers
1393
-
1497
+
1394
1498
  Returns operational continuity results with rollback plan.
1395
1499
  """
1396
1500
  print_header("Scenario #6: Operational Continuity & Risk Management", "SRE Integration")
1397
-
1501
+
1398
1502
  if not self.vpc_candidates:
1399
1503
  print_error("No VPC candidates available. Run discover_vpc_candidates() first.")
1400
1504
  return {"error": "No candidates for operational continuity analysis"}
1401
-
1505
+
1402
1506
  continuity_start = datetime.now()
1403
1507
  continuity_results = {
1404
1508
  "scenario_name": "Operational Continuity & Risk Management",
@@ -1409,50 +1513,50 @@ class VPCScenarioEngine:
1409
1513
  "rollback_procedures": {},
1410
1514
  "sre_integration_points": {},
1411
1515
  "incident_response_triggers": [],
1412
- "continuity_score": 0.0
1516
+ "continuity_score": 0.0,
1413
1517
  }
1414
-
1518
+
1415
1519
  # Business impact assessment categories
1416
1520
  business_impact = {
1417
- "zero_impact": [], # Safe for immediate cleanup
1418
- "minimal_impact": [], # Minor monitoring required
1419
- "moderate_impact": [], # Coordinated rollback plan
1420
- "high_impact": [], # Full SRE oversight required
1421
- "critical_impact": [] # Incident commander approval
1521
+ "zero_impact": [], # Safe for immediate cleanup
1522
+ "minimal_impact": [], # Minor monitoring required
1523
+ "moderate_impact": [], # Coordinated rollback plan
1524
+ "high_impact": [], # Full SRE oversight required
1525
+ "critical_impact": [], # Incident commander approval
1422
1526
  }
1423
-
1527
+
1424
1528
  # Dependency monitoring framework
1425
1529
  dependency_monitoring = {
1426
1530
  "real_time_monitors": [],
1427
1531
  "health_check_endpoints": [],
1428
1532
  "alerting_thresholds": {},
1429
1533
  "automated_rollback_triggers": [],
1430
- "manual_verification_points": []
1534
+ "manual_verification_points": [],
1431
1535
  }
1432
-
1536
+
1433
1537
  print_info(f"Assessing operational continuity for {len(self.vpc_candidates)} VPC candidates...")
1434
-
1538
+
1435
1539
  with create_progress_bar() as progress:
1436
1540
  task = progress.add_task("[cyan]Operational continuity assessment...", total=len(self.vpc_candidates))
1437
-
1541
+
1438
1542
  for candidate in self.vpc_candidates:
1439
1543
  # 1. Business impact assessment
1440
1544
  impact_score = self._calculate_business_impact_score(candidate)
1441
1545
  impact_category = self._categorize_business_impact(impact_score)
1442
-
1546
+
1443
1547
  # 2. Dependency analysis and monitoring requirements
1444
1548
  dependencies = await self._analyze_operational_dependencies(candidate)
1445
1549
  monitoring_requirements = self._determine_monitoring_requirements(candidate, dependencies)
1446
-
1550
+
1447
1551
  # 3. Rollback procedure generation
1448
1552
  rollback_plan = self._generate_rollback_procedure(candidate, dependencies)
1449
-
1553
+
1450
1554
  # 4. SRE integration points
1451
1555
  sre_integration = self._define_sre_integration_points(candidate, impact_category)
1452
-
1556
+
1453
1557
  # 5. Incident response triggers
1454
1558
  incident_triggers = self._define_incident_response_triggers(candidate, impact_score)
1455
-
1559
+
1456
1560
  # Create operational continuity profile
1457
1561
  continuity_profile = {
1458
1562
  "vpc_id": candidate.vpc_id,
@@ -1467,29 +1571,25 @@ class VPCScenarioEngine:
1467
1571
  "incident_triggers": incident_triggers,
1468
1572
  "estimated_downtime": self._estimate_potential_downtime(candidate, dependencies),
1469
1573
  "recovery_time_objective": self._calculate_rto(candidate, impact_category),
1470
- "recovery_point_objective": self._calculate_rpo(candidate, impact_category)
1574
+ "recovery_point_objective": self._calculate_rpo(candidate, impact_category),
1471
1575
  }
1472
-
1576
+
1473
1577
  # Categorize by business impact
1474
1578
  business_impact[impact_category].append(continuity_profile)
1475
-
1579
+
1476
1580
  # Add monitoring requirements
1477
1581
  if monitoring_requirements["real_time_monitoring"]:
1478
- dependency_monitoring["real_time_monitors"].extend(
1479
- monitoring_requirements["monitoring_endpoints"]
1480
- )
1481
-
1582
+ dependency_monitoring["real_time_monitors"].extend(monitoring_requirements["monitoring_endpoints"])
1583
+
1482
1584
  # Add automated rollback triggers
1483
1585
  if rollback_plan["automated_triggers"]:
1484
- dependency_monitoring["automated_rollback_triggers"].extend(
1485
- rollback_plan["automated_triggers"]
1486
- )
1487
-
1586
+ dependency_monitoring["automated_rollback_triggers"].extend(rollback_plan["automated_triggers"])
1587
+
1488
1588
  # Add incident response triggers
1489
1589
  continuity_results["incident_response_triggers"].extend(incident_triggers)
1490
-
1590
+
1491
1591
  progress.advance(task)
1492
-
1592
+
1493
1593
  # Calculate overall continuity score (0-100)
1494
1594
  total_candidates = len(self.vpc_candidates)
1495
1595
  zero_impact_count = len(business_impact["zero_impact"])
@@ -1497,16 +1597,23 @@ class VPCScenarioEngine:
1497
1597
  moderate_impact_count = len(business_impact["moderate_impact"])
1498
1598
  high_impact_count = len(business_impact["high_impact"])
1499
1599
  critical_impact_count = len(business_impact["critical_impact"])
1500
-
1600
+
1501
1601
  # Higher score = better operational continuity (less risk)
1502
1602
  continuity_score = (
1503
- (zero_impact_count * 20 +
1504
- minimal_impact_count * 15 +
1505
- moderate_impact_count * 10 +
1506
- high_impact_count * 5 +
1507
- critical_impact_count * 0) / total_candidates
1508
- ) if total_candidates > 0 else 0
1509
-
1603
+ (
1604
+ (
1605
+ zero_impact_count * 20
1606
+ + minimal_impact_count * 15
1607
+ + moderate_impact_count * 10
1608
+ + high_impact_count * 5
1609
+ + critical_impact_count * 0
1610
+ )
1611
+ / total_candidates
1612
+ )
1613
+ if total_candidates > 0
1614
+ else 0
1615
+ )
1616
+
1510
1617
  # Generate comprehensive monitoring plan
1511
1618
  monitoring_plan = {
1512
1619
  "pre_cleanup_checks": self._generate_pre_cleanup_checks(business_impact),
@@ -1514,85 +1621,87 @@ class VPCScenarioEngine:
1514
1621
  "post_cleanup_validation": self._generate_post_cleanup_validation(business_impact),
1515
1622
  "automated_rollback_conditions": self._generate_rollback_conditions(dependency_monitoring),
1516
1623
  "manual_intervention_triggers": self._generate_manual_triggers(business_impact),
1517
- "sre_escalation_matrix": self._generate_sre_escalation_matrix(business_impact)
1624
+ "sre_escalation_matrix": self._generate_sre_escalation_matrix(business_impact),
1518
1625
  }
1519
-
1626
+
1520
1627
  # Generate rollback procedures by impact category
1521
1628
  rollback_procedures = {
1522
1629
  "immediate_rollback": self._generate_immediate_rollback_procedures(business_impact),
1523
1630
  "coordinated_rollback": self._generate_coordinated_rollback_procedures(business_impact),
1524
1631
  "emergency_procedures": self._generate_emergency_procedures(business_impact),
1525
- "business_continuity_plan": self._generate_business_continuity_plan(business_impact)
1632
+ "business_continuity_plan": self._generate_business_continuity_plan(business_impact),
1526
1633
  }
1527
-
1634
+
1528
1635
  # SRE integration framework
1529
1636
  sre_integration = {
1530
1637
  "monitoring_integrations": self._define_monitoring_integrations(dependency_monitoring),
1531
1638
  "alerting_configuration": self._define_alerting_configuration(business_impact),
1532
1639
  "incident_response_playbooks": self._generate_incident_playbooks(business_impact),
1533
1640
  "on_call_escalation": self._define_on_call_escalation(business_impact),
1534
- "post_incident_review_triggers": self._define_post_incident_triggers(business_impact)
1641
+ "post_incident_review_triggers": self._define_post_incident_triggers(business_impact),
1535
1642
  }
1536
-
1643
+
1537
1644
  # Finalize continuity results
1538
1645
  continuity_duration = (datetime.now() - continuity_start).total_seconds()
1539
-
1540
- continuity_results.update({
1541
- "business_impact_assessment": business_impact,
1542
- "dependency_monitoring_plan": monitoring_plan,
1543
- "rollback_procedures": rollback_procedures,
1544
- "sre_integration_points": sre_integration,
1545
- "continuity_score": continuity_score,
1546
- "operational_risk_level": self._determine_operational_risk_level(continuity_score),
1547
- "recommended_cleanup_strategy": self._recommend_cleanup_strategy(business_impact),
1548
- "continuity_duration_seconds": continuity_duration,
1549
- "high_risk_vpc_count": high_impact_count + critical_impact_count,
1550
- "safe_for_immediate_cleanup": zero_impact_count + minimal_impact_count,
1551
- "requires_coordination": moderate_impact_count + high_impact_count + critical_impact_count
1552
- })
1553
-
1646
+
1647
+ continuity_results.update(
1648
+ {
1649
+ "business_impact_assessment": business_impact,
1650
+ "dependency_monitoring_plan": monitoring_plan,
1651
+ "rollback_procedures": rollback_procedures,
1652
+ "sre_integration_points": sre_integration,
1653
+ "continuity_score": continuity_score,
1654
+ "operational_risk_level": self._determine_operational_risk_level(continuity_score),
1655
+ "recommended_cleanup_strategy": self._recommend_cleanup_strategy(business_impact),
1656
+ "continuity_duration_seconds": continuity_duration,
1657
+ "high_risk_vpc_count": high_impact_count + critical_impact_count,
1658
+ "safe_for_immediate_cleanup": zero_impact_count + minimal_impact_count,
1659
+ "requires_coordination": moderate_impact_count + high_impact_count + critical_impact_count,
1660
+ }
1661
+ )
1662
+
1554
1663
  # Display operational continuity results
1555
1664
  print_success(f"Operational continuity assessment complete in {continuity_duration:.1f}s")
1556
1665
  print_info(f"Operational continuity score: {continuity_score:.1f}/100")
1557
1666
  print_info(f"Safe for immediate cleanup: {continuity_results['safe_for_immediate_cleanup']} VPCs")
1558
1667
  print_info(f"Requires coordination: {continuity_results['requires_coordination']} VPCs")
1559
-
1668
+
1560
1669
  if critical_impact_count > 0:
1561
1670
  print_warning(f"CRITICAL: {critical_impact_count} VPCs require incident commander approval")
1562
1671
  if high_impact_count > 0:
1563
1672
  print_warning(f"HIGH RISK: {high_impact_count} VPCs require full SRE oversight")
1564
-
1673
+
1565
1674
  return continuity_results
1566
-
1675
+
1567
1676
  def _calculate_business_impact_score(self, candidate: VPCCandidate) -> float:
1568
1677
  """Calculate business impact score (0-100) for operational continuity."""
1569
1678
  impact_score = 0.0
1570
-
1679
+
1571
1680
  # ENI count impact (active workloads)
1572
1681
  impact_score += min(30, candidate.eni_count * 5)
1573
-
1682
+
1574
1683
  # Load balancer impact (service availability)
1575
1684
  if candidate.load_balancers_present:
1576
1685
  impact_score += 25
1577
-
1686
+
1578
1687
  # Transit Gateway/Peering impact (connectivity)
1579
1688
  if candidate.tgw_peering_attached:
1580
1689
  impact_score += 20
1581
-
1690
+
1582
1691
  # Flow logs impact (monitoring/compliance)
1583
1692
  if candidate.flow_logs_enabled:
1584
1693
  impact_score += 10 # Higher impact to remove monitored VPCs
1585
-
1694
+
1586
1695
  # IaC managed impact (change management complexity)
1587
1696
  if candidate.iac_managed:
1588
1697
  impact_score += 10
1589
-
1698
+
1590
1699
  # Default VPC impact (potential for hidden dependencies)
1591
1700
  if candidate.is_default:
1592
1701
  impact_score += 5
1593
-
1702
+
1594
1703
  return min(100.0, impact_score)
1595
-
1704
+
1596
1705
  def _categorize_business_impact(self, impact_score: float) -> str:
1597
1706
  """Categorize business impact based on score."""
1598
1707
  if impact_score >= 80:
@@ -1605,7 +1714,7 @@ class VPCScenarioEngine:
1605
1714
  return "minimal_impact"
1606
1715
  else:
1607
1716
  return "zero_impact"
1608
-
1717
+
1609
1718
  async def _analyze_operational_dependencies(self, candidate: VPCCandidate) -> Dict[str, Any]:
1610
1719
  """Analyze operational dependencies for continuity planning."""
1611
1720
  dependencies = {
@@ -1618,71 +1727,63 @@ class VPCScenarioEngine:
1618
1727
  "nacls": [],
1619
1728
  "nat_gateways": [],
1620
1729
  "internet_gateways": [],
1621
- "vpn_connections": []
1730
+ "vpn_connections": [],
1622
1731
  }
1623
-
1732
+
1624
1733
  try:
1625
- ec2_client = self.session.client('ec2')
1626
-
1734
+ ec2_client = self.session.client("ec2")
1735
+
1627
1736
  # Network interfaces
1628
1737
  if candidate.eni_count > 0:
1629
1738
  eni_response = ec2_client.describe_network_interfaces(
1630
- Filters=[{'Name': 'vpc-id', 'Values': [candidate.vpc_id]}]
1739
+ Filters=[{"Name": "vpc-id", "Values": [candidate.vpc_id]}]
1631
1740
  )
1632
1741
  dependencies["network_interfaces"] = [
1633
1742
  {
1634
1743
  "eni_id": eni["NetworkInterfaceId"],
1635
1744
  "status": eni["Status"],
1636
1745
  "attachment": eni.get("Attachment", {}),
1637
- "private_ip": eni.get("PrivateIpAddress", "")
1746
+ "private_ip": eni.get("PrivateIpAddress", ""),
1638
1747
  }
1639
1748
  for eni in eni_response["NetworkInterfaces"]
1640
1749
  ]
1641
-
1750
+
1642
1751
  # Route tables
1643
- rt_response = ec2_client.describe_route_tables(
1644
- Filters=[{'Name': 'vpc-id', 'Values': [candidate.vpc_id]}]
1645
- )
1752
+ rt_response = ec2_client.describe_route_tables(Filters=[{"Name": "vpc-id", "Values": [candidate.vpc_id]}])
1646
1753
  dependencies["route_tables"] = [
1647
1754
  {
1648
1755
  "route_table_id": rt["RouteTableId"],
1649
1756
  "routes_count": len(rt.get("Routes", [])),
1650
- "associations": len(rt.get("Associations", []))
1757
+ "associations": len(rt.get("Associations", [])),
1651
1758
  }
1652
1759
  for rt in rt_response["RouteTables"]
1653
1760
  ]
1654
-
1761
+
1655
1762
  # Security groups
1656
1763
  sg_response = ec2_client.describe_security_groups(
1657
- Filters=[{'Name': 'vpc-id', 'Values': [candidate.vpc_id]}]
1764
+ Filters=[{"Name": "vpc-id", "Values": [candidate.vpc_id]}]
1658
1765
  )
1659
1766
  dependencies["security_groups"] = [
1660
1767
  {
1661
1768
  "security_group_id": sg["GroupId"],
1662
1769
  "group_name": sg["GroupName"],
1663
- "rules_count": len(sg.get("IpPermissions", [])) + len(sg.get("IpPermissionsEgress", []))
1770
+ "rules_count": len(sg.get("IpPermissions", [])) + len(sg.get("IpPermissionsEgress", [])),
1664
1771
  }
1665
1772
  for sg in sg_response["SecurityGroups"]
1666
1773
  ]
1667
-
1774
+
1668
1775
  # NAT Gateways
1669
- nat_response = ec2_client.describe_nat_gateways(
1670
- Filters=[{'Name': 'vpc-id', 'Values': [candidate.vpc_id]}]
1671
- )
1776
+ nat_response = ec2_client.describe_nat_gateways(Filters=[{"Name": "vpc-id", "Values": [candidate.vpc_id]}])
1672
1777
  dependencies["nat_gateways"] = [
1673
- {
1674
- "nat_gateway_id": nat["NatGatewayId"],
1675
- "state": nat["State"],
1676
- "subnet_id": nat["SubnetId"]
1677
- }
1778
+ {"nat_gateway_id": nat["NatGatewayId"], "state": nat["State"], "subnet_id": nat["SubnetId"]}
1678
1779
  for nat in nat_response["NatGateways"]
1679
1780
  ]
1680
-
1781
+
1681
1782
  except Exception as e:
1682
1783
  print_warning(f"Failed to analyze dependencies for {candidate.vpc_id}: {e}")
1683
-
1784
+
1684
1785
  return dependencies
1685
-
1786
+
1686
1787
  def _determine_monitoring_requirements(self, candidate: VPCCandidate, dependencies: Dict) -> Dict[str, Any]:
1687
1788
  """Determine monitoring requirements for operational continuity."""
1688
1789
  requirements = {
@@ -1690,32 +1791,36 @@ class VPCScenarioEngine:
1690
1791
  "health_check_frequency": "30s" if candidate.load_balancers_present else "5m",
1691
1792
  "monitoring_endpoints": [],
1692
1793
  "alert_thresholds": {},
1693
- "baseline_metrics": {}
1794
+ "baseline_metrics": {},
1694
1795
  }
1695
-
1796
+
1696
1797
  # Define monitoring endpoints
1697
1798
  if candidate.load_balancers_present:
1698
- requirements["monitoring_endpoints"].extend([
1699
- f"health-check://{candidate.vpc_id}/load-balancers",
1700
- f"connectivity-test://{candidate.vpc_id}/external"
1701
- ])
1702
-
1799
+ requirements["monitoring_endpoints"].extend(
1800
+ [
1801
+ f"health-check://{candidate.vpc_id}/load-balancers",
1802
+ f"connectivity-test://{candidate.vpc_id}/external",
1803
+ ]
1804
+ )
1805
+
1703
1806
  if candidate.eni_count > 0:
1704
- requirements["monitoring_endpoints"].extend([
1705
- f"network-connectivity://{candidate.vpc_id}/internal",
1706
- f"service-health://{candidate.vpc_id}/workloads"
1707
- ])
1708
-
1807
+ requirements["monitoring_endpoints"].extend(
1808
+ [
1809
+ f"network-connectivity://{candidate.vpc_id}/internal",
1810
+ f"service-health://{candidate.vpc_id}/workloads",
1811
+ ]
1812
+ )
1813
+
1709
1814
  # Define alert thresholds
1710
1815
  requirements["alert_thresholds"] = {
1711
1816
  "connectivity_loss": "0% availability for >30s",
1712
1817
  "latency_increase": ">200ms from baseline",
1713
1818
  "error_rate_spike": ">5% error rate increase",
1714
- "network_partition": "cross-AZ connectivity loss"
1819
+ "network_partition": "cross-AZ connectivity loss",
1715
1820
  }
1716
-
1821
+
1717
1822
  return requirements
1718
-
1823
+
1719
1824
  def _generate_rollback_procedure(self, candidate: VPCCandidate, dependencies: Dict) -> Dict[str, Any]:
1720
1825
  """Generate rollback procedure for VPC cleanup operation."""
1721
1826
  rollback_plan = {
@@ -1723,36 +1828,32 @@ class VPCScenarioEngine:
1723
1828
  "manual_triggers": [],
1724
1829
  "rollback_steps": [],
1725
1830
  "validation_steps": [],
1726
- "estimated_rollback_time": "5-15 minutes"
1831
+ "estimated_rollback_time": "5-15 minutes",
1727
1832
  }
1728
-
1833
+
1729
1834
  # Automated rollback triggers
1730
1835
  if candidate.load_balancers_present:
1731
- rollback_plan["automated_triggers"].extend([
1732
- "load_balancer_health_check_failure",
1733
- "service_availability_drop_below_99%"
1734
- ])
1735
-
1836
+ rollback_plan["automated_triggers"].extend(
1837
+ ["load_balancer_health_check_failure", "service_availability_drop_below_99%"]
1838
+ )
1839
+
1736
1840
  if candidate.eni_count > 0:
1737
- rollback_plan["automated_triggers"].extend([
1738
- "network_connectivity_loss",
1739
- "workload_health_check_failure"
1740
- ])
1741
-
1841
+ rollback_plan["automated_triggers"].extend(["network_connectivity_loss", "workload_health_check_failure"])
1842
+
1742
1843
  # Manual triggers
1743
1844
  rollback_plan["manual_triggers"] = [
1744
1845
  "business_stakeholder_request",
1745
1846
  "unexpected_service_impact",
1746
- "compliance_requirement_violation"
1847
+ "compliance_requirement_violation",
1747
1848
  ]
1748
-
1849
+
1749
1850
  # Rollback steps
1750
1851
  if candidate.iac_managed:
1751
1852
  rollback_plan["rollback_steps"] = [
1752
1853
  "1. Revert IaC configuration to previous state",
1753
- "2. Re-apply infrastructure via automated pipeline",
1854
+ "2. Re-apply infrastructure via automated pipeline",
1754
1855
  "3. Validate service restoration",
1755
- "4. Update monitoring baselines"
1856
+ "4. Update monitoring baselines",
1756
1857
  ]
1757
1858
  rollback_plan["estimated_rollback_time"] = "10-30 minutes"
1758
1859
  else:
@@ -1760,12 +1861,12 @@ class VPCScenarioEngine:
1760
1861
  "1. Recreate VPC with original CIDR configuration",
1761
1862
  "2. Restore network interfaces and dependencies",
1762
1863
  "3. Validate connectivity and service health",
1763
- "4. Update DNS and routing as needed"
1864
+ "4. Update DNS and routing as needed",
1764
1865
  ]
1765
1866
  rollback_plan["estimated_rollback_time"] = "15-45 minutes"
1766
-
1867
+
1767
1868
  return rollback_plan
1768
-
1869
+
1769
1870
  def _define_sre_integration_points(self, candidate: VPCCandidate, impact_category: str) -> Dict[str, Any]:
1770
1871
  """Define SRE integration points for operational continuity."""
1771
1872
  sre_integration = {
@@ -1773,59 +1874,60 @@ class VPCScenarioEngine:
1773
1874
  "incident_commander_required": impact_category == "critical_impact",
1774
1875
  "monitoring_dashboard": f"vpc-cleanup-{candidate.vpc_id}",
1775
1876
  "alert_routing": [],
1776
- "escalation_procedures": []
1877
+ "escalation_procedures": [],
1777
1878
  }
1778
-
1879
+
1779
1880
  # Define alert routing
1780
1881
  if impact_category == "critical_impact":
1781
1882
  sre_integration["alert_routing"] = [
1782
1883
  "incident-commander@company.com",
1783
1884
  "sre-on-call@company.com",
1784
- "business-continuity@company.com"
1885
+ "business-continuity@company.com",
1785
1886
  ]
1786
1887
  elif impact_category == "high_impact":
1787
- sre_integration["alert_routing"] = [
1788
- "sre-on-call@company.com",
1789
- "platform-team@company.com"
1790
- ]
1888
+ sre_integration["alert_routing"] = ["sre-on-call@company.com", "platform-team@company.com"]
1791
1889
  else:
1792
- sre_integration["alert_routing"] = [
1793
- "platform-team@company.com"
1794
- ]
1795
-
1890
+ sre_integration["alert_routing"] = ["platform-team@company.com"]
1891
+
1796
1892
  return sre_integration
1797
-
1893
+
1798
1894
  def _define_incident_response_triggers(self, candidate: VPCCandidate, impact_score: float) -> List[Dict[str, Any]]:
1799
1895
  """Define incident response triggers for VPC cleanup operations."""
1800
1896
  triggers = []
1801
-
1897
+
1802
1898
  if impact_score >= 80: # Critical impact
1803
- triggers.append({
1804
- "trigger_name": "vpc_cleanup_critical_impact",
1805
- "condition": f"VPC {candidate.vpc_id} cleanup causing service degradation",
1806
- "severity": "P1",
1807
- "escalation_time": "15 minutes",
1808
- "required_responders": ["incident-commander", "sre-lead", "business-stakeholder"]
1809
- })
1899
+ triggers.append(
1900
+ {
1901
+ "trigger_name": "vpc_cleanup_critical_impact",
1902
+ "condition": f"VPC {candidate.vpc_id} cleanup causing service degradation",
1903
+ "severity": "P1",
1904
+ "escalation_time": "15 minutes",
1905
+ "required_responders": ["incident-commander", "sre-lead", "business-stakeholder"],
1906
+ }
1907
+ )
1810
1908
  elif impact_score >= 60: # High impact
1811
- triggers.append({
1812
- "trigger_name": "vpc_cleanup_high_impact",
1813
- "condition": f"VPC {candidate.vpc_id} cleanup affecting operations",
1814
- "severity": "P2",
1815
- "escalation_time": "30 minutes",
1816
- "required_responders": ["sre-lead", "platform-engineer"]
1817
- })
1909
+ triggers.append(
1910
+ {
1911
+ "trigger_name": "vpc_cleanup_high_impact",
1912
+ "condition": f"VPC {candidate.vpc_id} cleanup affecting operations",
1913
+ "severity": "P2",
1914
+ "escalation_time": "30 minutes",
1915
+ "required_responders": ["sre-lead", "platform-engineer"],
1916
+ }
1917
+ )
1818
1918
  elif impact_score >= 40: # Moderate impact
1819
- triggers.append({
1820
- "trigger_name": "vpc_cleanup_moderate_impact",
1821
- "condition": f"VPC {candidate.vpc_id} cleanup monitoring required",
1822
- "severity": "P3",
1823
- "escalation_time": "1 hour",
1824
- "required_responders": ["platform-engineer"]
1825
- })
1826
-
1919
+ triggers.append(
1920
+ {
1921
+ "trigger_name": "vpc_cleanup_moderate_impact",
1922
+ "condition": f"VPC {candidate.vpc_id} cleanup monitoring required",
1923
+ "severity": "P3",
1924
+ "escalation_time": "1 hour",
1925
+ "required_responders": ["platform-engineer"],
1926
+ }
1927
+ )
1928
+
1827
1929
  return triggers
1828
-
1930
+
1829
1931
  def _estimate_potential_downtime(self, candidate: VPCCandidate, dependencies: Dict) -> str:
1830
1932
  """Estimate potential downtime for VPC cleanup operation."""
1831
1933
  if candidate.load_balancers_present:
@@ -1838,7 +1940,7 @@ class VPCScenarioEngine:
1838
1940
  return "30s-2 minutes (workload validation)"
1839
1941
  else:
1840
1942
  return "0-30 seconds (no active workloads)"
1841
-
1943
+
1842
1944
  def _calculate_rto(self, candidate: VPCCandidate, impact_category: str) -> str:
1843
1945
  """Calculate Recovery Time Objective for business continuity."""
1844
1946
  if impact_category == "critical_impact":
@@ -1849,7 +1951,7 @@ class VPCScenarioEngine:
1849
1951
  return "< 1 hour"
1850
1952
  else:
1851
1953
  return "< 4 hours"
1852
-
1954
+
1853
1955
  def _calculate_rpo(self, candidate: VPCCandidate, impact_category: str) -> str:
1854
1956
  """Calculate Recovery Point Objective for data continuity."""
1855
1957
  if candidate.flow_logs_enabled or impact_category == "critical_impact":
@@ -1858,10 +1960,10 @@ class VPCScenarioEngine:
1858
1960
  return "< 15 minutes"
1859
1961
  else:
1860
1962
  return "< 1 hour"
1861
-
1963
+
1862
1964
  # Additional helper methods for monitoring, rollback, and SRE integration...
1863
1965
  # [Implementation details for comprehensive operational continuity framework]
1864
-
1966
+
1865
1967
  def _generate_pre_cleanup_checks(self, business_impact: Dict) -> List[str]:
1866
1968
  """Generate pre-cleanup validation checklist."""
1867
1969
  return [
@@ -1869,19 +1971,19 @@ class VPCScenarioEngine:
1869
1971
  "Confirm rollback procedures tested and ready",
1870
1972
  "Verify SRE team availability and alerting",
1871
1973
  "Check business stakeholder approval status",
1872
- "Baseline service health metrics captured"
1974
+ "Baseline service health metrics captured",
1873
1975
  ]
1874
-
1976
+
1875
1977
  def _generate_during_cleanup_monitoring(self, dependency_monitoring: Dict) -> List[str]:
1876
1978
  """Generate during-cleanup monitoring requirements."""
1877
1979
  return [
1878
1980
  "Real-time service health monitoring active",
1879
- "Network connectivity validation continuous",
1981
+ "Network connectivity validation continuous",
1880
1982
  "Load balancer health checks monitored",
1881
1983
  "Automated rollback triggers armed",
1882
- "SRE dashboard monitoring active"
1984
+ "SRE dashboard monitoring active",
1883
1985
  ]
1884
-
1986
+
1885
1987
  def _generate_post_cleanup_validation(self, business_impact: Dict) -> List[str]:
1886
1988
  """Generate post-cleanup validation steps."""
1887
1989
  return [
@@ -1889,9 +1991,9 @@ class VPCScenarioEngine:
1889
1991
  "Network connectivity fully restored",
1890
1992
  "No performance degradation detected",
1891
1993
  "All monitoring baselines updated",
1892
- "Stakeholder confirmation received"
1994
+ "Stakeholder confirmation received",
1893
1995
  ]
1894
-
1996
+
1895
1997
  def _generate_rollback_conditions(self, dependency_monitoring: Dict) -> List[str]:
1896
1998
  """Generate automated rollback conditions."""
1897
1999
  return [
@@ -1899,19 +2001,19 @@ class VPCScenarioEngine:
1899
2001
  "Network connectivity loss detected",
1900
2002
  "Error rate increase > 5% from baseline",
1901
2003
  "Manual rollback trigger activated",
1902
- "Business continuity threshold breach"
2004
+ "Business continuity threshold breach",
1903
2005
  ]
1904
-
2006
+
1905
2007
  def _generate_manual_triggers(self, business_impact: Dict) -> List[str]:
1906
2008
  """Generate manual intervention triggers."""
1907
2009
  return [
1908
2010
  "Business stakeholder requests halt",
1909
- "Unexpected compliance impact detected",
2011
+ "Unexpected compliance impact detected",
1910
2012
  "Service degradation beyond acceptable limits",
1911
2013
  "Monitoring system failures during cleanup",
1912
- "Emergency business requirement changes"
2014
+ "Emergency business requirement changes",
1913
2015
  ]
1914
-
2016
+
1915
2017
  def _generate_sre_escalation_matrix(self, business_impact: Dict) -> Dict[str, List[str]]:
1916
2018
  """Generate SRE escalation matrix by impact level."""
1917
2019
  return {
@@ -1919,9 +2021,9 @@ class VPCScenarioEngine:
1919
2021
  "high_impact": ["sre-manager", "platform-director"],
1920
2022
  "moderate_impact": ["sre-lead", "platform-manager"],
1921
2023
  "minimal_impact": ["platform-engineer"],
1922
- "zero_impact": ["automated-monitoring"]
2024
+ "zero_impact": ["automated-monitoring"],
1923
2025
  }
1924
-
2026
+
1925
2027
  def _generate_immediate_rollback_procedures(self, business_impact: Dict) -> List[str]:
1926
2028
  """Generate immediate rollback procedures for high-impact scenarios."""
1927
2029
  return [
@@ -1929,9 +2031,9 @@ class VPCScenarioEngine:
1929
2031
  "Execute automated rollback triggers within 30 seconds",
1930
2032
  "Notify SRE on-call and business stakeholders",
1931
2033
  "Implement emergency traffic rerouting if needed",
1932
- "Document incident details for post-mortem analysis"
2034
+ "Document incident details for post-mortem analysis",
1933
2035
  ]
1934
-
2036
+
1935
2037
  def _generate_coordinated_rollback_procedures(self, business_impact: Dict) -> List[str]:
1936
2038
  """Generate coordinated rollback procedures for planned scenarios."""
1937
2039
  return [
@@ -1939,19 +2041,19 @@ class VPCScenarioEngine:
1939
2041
  "Execute phased rollback with monitoring validation",
1940
2042
  "Coordinate with business teams for service validation",
1941
2043
  "Update change management systems with rollback status",
1942
- "Schedule post-rollback review and lessons learned"
2044
+ "Schedule post-rollback review and lessons learned",
1943
2045
  ]
1944
-
2046
+
1945
2047
  def _generate_emergency_procedures(self, business_impact: Dict) -> List[str]:
1946
2048
  """Generate emergency procedures for critical scenarios."""
1947
2049
  return [
1948
2050
  "Activate emergency response team immediately",
1949
- "Implement business continuity plans as needed",
2051
+ "Implement business continuity plans as needed",
1950
2052
  "Coordinate with external vendors if required",
1951
2053
  "Execute disaster recovery procedures if applicable",
1952
- "Communicate with customers and stakeholders as appropriate"
2054
+ "Communicate with customers and stakeholders as appropriate",
1953
2055
  ]
1954
-
2056
+
1955
2057
  def _generate_business_continuity_plan(self, business_impact: Dict) -> Dict[str, Any]:
1956
2058
  """Generate comprehensive business continuity plan."""
1957
2059
  return {
@@ -1959,9 +2061,9 @@ class VPCScenarioEngine:
1959
2061
  "communication_plan": "Stakeholder notification within 5 minutes of issues",
1960
2062
  "alternative_services": "Backup systems and failover procedures ready",
1961
2063
  "data_protection": "Ensure no data loss during cleanup operations",
1962
- "compliance_maintenance": "Maintain regulatory compliance throughout process"
2064
+ "compliance_maintenance": "Maintain regulatory compliance throughout process",
1963
2065
  }
1964
-
2066
+
1965
2067
  def _define_monitoring_integrations(self, dependency_monitoring: Dict) -> List[str]:
1966
2068
  """Define monitoring system integrations for SRE workflows."""
1967
2069
  return [
@@ -1969,9 +2071,9 @@ class VPCScenarioEngine:
1969
2071
  "PagerDuty alerting for critical threshold breaches",
1970
2072
  "Slack notifications for team coordination",
1971
2073
  "ServiceNow integration for change management",
1972
- "CloudWatch custom metrics for AWS resource monitoring"
2074
+ "CloudWatch custom metrics for AWS resource monitoring",
1973
2075
  ]
1974
-
2076
+
1975
2077
  def _define_alerting_configuration(self, business_impact: Dict) -> Dict[str, Any]:
1976
2078
  """Define alerting configuration by business impact."""
1977
2079
  return {
@@ -1979,27 +2081,27 @@ class VPCScenarioEngine:
1979
2081
  "high_impact": {"alert_frequency": "immediate", "escalation": "15min"},
1980
2082
  "moderate_impact": {"alert_frequency": "5min", "escalation": "30min"},
1981
2083
  "minimal_impact": {"alert_frequency": "15min", "escalation": "1hour"},
1982
- "zero_impact": {"alert_frequency": "none", "escalation": "none"}
2084
+ "zero_impact": {"alert_frequency": "none", "escalation": "none"},
1983
2085
  }
1984
-
2086
+
1985
2087
  def _generate_incident_playbooks(self, business_impact: Dict) -> List[str]:
1986
2088
  """Generate incident response playbooks."""
1987
2089
  return [
1988
2090
  "VPC Cleanup Critical Impact Response Playbook",
1989
- "Network Connectivity Loss Response Playbook",
2091
+ "Network Connectivity Loss Response Playbook",
1990
2092
  "Service Degradation Recovery Playbook",
1991
2093
  "Business Continuity Activation Playbook",
1992
- "Emergency Rollback Execution Playbook"
2094
+ "Emergency Rollback Execution Playbook",
1993
2095
  ]
1994
-
2096
+
1995
2097
  def _define_on_call_escalation(self, business_impact: Dict) -> Dict[str, List[str]]:
1996
2098
  """Define on-call escalation procedures."""
1997
2099
  return {
1998
2100
  "primary": ["sre-on-call@company.com"],
1999
2101
  "secondary": ["sre-manager@company.com", "platform-lead@company.com"],
2000
- "emergency": ["incident-commander@company.com", "cto@company.com"]
2102
+ "emergency": ["incident-commander@company.com", "cto@company.com"],
2001
2103
  }
2002
-
2104
+
2003
2105
  def _define_post_incident_triggers(self, business_impact: Dict) -> List[str]:
2004
2106
  """Define post-incident review triggers."""
2005
2107
  return [
@@ -2007,9 +2109,9 @@ class VPCScenarioEngine:
2007
2109
  "Service availability drop below SLA",
2008
2110
  "Business stakeholder escalation",
2009
2111
  "Compliance threshold breach",
2010
- "Manual intervention requirement"
2112
+ "Manual intervention requirement",
2011
2113
  ]
2012
-
2114
+
2013
2115
  def _determine_operational_risk_level(self, continuity_score: float) -> str:
2014
2116
  """Determine overall operational risk level."""
2015
2117
  if continuity_score >= 80:
@@ -2020,7 +2122,7 @@ class VPCScenarioEngine:
2020
2122
  return "HIGH"
2021
2123
  else:
2022
2124
  return "CRITICAL"
2023
-
2125
+
2024
2126
  def _recommend_cleanup_strategy(self, business_impact: Dict) -> str:
2025
2127
  """Recommend cleanup strategy based on business impact analysis."""
2026
2128
  zero_count = len(business_impact["zero_impact"])
@@ -2028,7 +2130,7 @@ class VPCScenarioEngine:
2028
2130
  moderate_count = len(business_impact["moderate_impact"])
2029
2131
  high_count = len(business_impact["high_impact"])
2030
2132
  critical_count = len(business_impact["critical_impact"])
2031
-
2133
+
2032
2134
  if critical_count > 0:
2033
2135
  return f"STAGED: Process {critical_count} critical VPCs with full incident response capability"
2034
2136
  elif high_count > 3:
@@ -2042,7 +2144,7 @@ class VPCScenarioEngine:
2042
2144
  async def generate_comprehensive_business_analysis(self) -> Dict[str, Any]:
2043
2145
  """
2044
2146
  Generate comprehensive business impact analysis with quantified metrics.
2045
-
2147
+
2046
2148
  Required by WIP.md:
2047
2149
  - Business impact summary with specific metrics
2048
2150
  - Cost analysis with quantified savings projections
@@ -2051,67 +2153,79 @@ class VPCScenarioEngine:
2051
2153
  - Resource optimization recommendations
2052
2154
  """
2053
2155
  console.print("\n[cyan]📊 Generating Comprehensive Business Impact Analysis[/cyan]")
2054
-
2156
+
2055
2157
  # Discover VPC candidates for analysis
2056
2158
  vpc_candidates = self.discover_vpc_candidates()
2057
-
2159
+
2058
2160
  # 5-Step Analysis Framework
2059
2161
  step_1_immediate = self._analyze_immediate_deletion_candidates(vpc_candidates)
2060
2162
  step_2_investigation = self._analyze_investigation_required_candidates(vpc_candidates)
2061
2163
  step_3_governance = self._analyze_governance_approval_candidates(vpc_candidates)
2062
2164
  step_4_complex = self._analyze_complex_migration_candidates(vpc_candidates)
2063
2165
  step_5_strategic = self._analyze_strategic_review_candidates(vpc_candidates)
2064
-
2166
+
2065
2167
  # Generate quantified business metrics
2066
2168
  cost_analysis = await self._calculate_cost_impact_analysis(vpc_candidates)
2067
2169
  risk_assessment = await self._calculate_operational_risk_scores(vpc_candidates)
2068
2170
  timeline_analysis = self._calculate_cleanup_timeline_estimates(vpc_candidates)
2069
-
2171
+
2070
2172
  analysis_results = {
2071
2173
  "analysis_timestamp": datetime.now().isoformat(),
2072
2174
  "total_vpc_candidates": len(vpc_candidates),
2073
-
2074
2175
  # 5-Step Analysis Framework Results
2075
2176
  "step_1_immediate_deletion": {
2076
2177
  "count": len(step_1_immediate),
2077
2178
  "candidates": [vpc.vpc_id for vpc in step_1_immediate],
2078
- "estimated_savings_monthly": sum(candidate.estimated_monthly_cost for candidate in step_1_immediate if candidate.estimated_monthly_cost),
2179
+ "estimated_savings_monthly": sum(
2180
+ candidate.estimated_monthly_cost
2181
+ for candidate in step_1_immediate
2182
+ if candidate.estimated_monthly_cost
2183
+ ),
2079
2184
  "risk_level": "LOW",
2080
- "cleanup_timeline_days": 1
2185
+ "cleanup_timeline_days": 1,
2081
2186
  },
2082
-
2083
2187
  "step_2_investigation_required": {
2084
2188
  "count": len(step_2_investigation),
2085
2189
  "candidates": [vpc.vpc_id for vpc in step_2_investigation],
2086
- "estimated_savings_monthly": sum(candidate.estimated_monthly_cost for candidate in step_2_investigation if candidate.estimated_monthly_cost),
2190
+ "estimated_savings_monthly": sum(
2191
+ candidate.estimated_monthly_cost
2192
+ for candidate in step_2_investigation
2193
+ if candidate.estimated_monthly_cost
2194
+ ),
2087
2195
  "risk_level": "MEDIUM-LOW",
2088
- "cleanup_timeline_days": 7
2196
+ "cleanup_timeline_days": 7,
2089
2197
  },
2090
-
2091
2198
  "step_3_governance_approval": {
2092
2199
  "count": len(step_3_governance),
2093
2200
  "candidates": [vpc.vpc_id for vpc in step_3_governance],
2094
- "estimated_savings_monthly": sum(candidate.estimated_monthly_cost for candidate in step_3_governance if candidate.estimated_monthly_cost),
2201
+ "estimated_savings_monthly": sum(
2202
+ candidate.estimated_monthly_cost
2203
+ for candidate in step_3_governance
2204
+ if candidate.estimated_monthly_cost
2205
+ ),
2095
2206
  "risk_level": "MEDIUM",
2096
- "cleanup_timeline_days": 21
2207
+ "cleanup_timeline_days": 21,
2097
2208
  },
2098
-
2099
2209
  "step_4_complex_migration": {
2100
2210
  "count": len(step_4_complex),
2101
2211
  "candidates": [vpc.vpc_id for vpc in step_4_complex],
2102
- "estimated_savings_monthly": sum(candidate.estimated_monthly_cost for candidate in step_4_complex if candidate.estimated_monthly_cost),
2212
+ "estimated_savings_monthly": sum(
2213
+ candidate.estimated_monthly_cost for candidate in step_4_complex if candidate.estimated_monthly_cost
2214
+ ),
2103
2215
  "risk_level": "HIGH",
2104
- "cleanup_timeline_days": 90
2216
+ "cleanup_timeline_days": 90,
2105
2217
  },
2106
-
2107
2218
  "step_5_strategic_review": {
2108
2219
  "count": len(step_5_strategic),
2109
2220
  "candidates": [vpc.vpc_id for vpc in step_5_strategic],
2110
- "estimated_savings_monthly": sum(candidate.estimated_monthly_cost for candidate in step_5_strategic if candidate.estimated_monthly_cost),
2221
+ "estimated_savings_monthly": sum(
2222
+ candidate.estimated_monthly_cost
2223
+ for candidate in step_5_strategic
2224
+ if candidate.estimated_monthly_cost
2225
+ ),
2111
2226
  "risk_level": "CRITICAL",
2112
- "cleanup_timeline_days": 180
2227
+ "cleanup_timeline_days": 180,
2113
2228
  },
2114
-
2115
2229
  # Quantified Business Impact Summary
2116
2230
  "business_impact_summary": {
2117
2231
  "total_estimated_monthly_savings": cost_analysis["total_monthly_savings"],
@@ -2120,130 +2234,147 @@ class VPCScenarioEngine:
2120
2234
  "high_risk_vpc_count": risk_assessment["high_risk_count"],
2121
2235
  "estimated_total_cleanup_timeline_days": timeline_analysis["total_timeline_days"],
2122
2236
  "roi_12_month_percentage": cost_analysis["roi_percentage"],
2123
- "operational_complexity_score": risk_assessment["complexity_score"]
2237
+ "operational_complexity_score": risk_assessment["complexity_score"],
2124
2238
  },
2125
-
2126
2239
  # Strategic Recommendations
2127
2240
  "strategic_recommendations": [
2128
2241
  {
2129
2242
  "priority": "P0_IMMEDIATE",
2130
2243
  "action": f"Execute immediate deletion of {len(step_1_immediate)} low-risk VPCs",
2131
2244
  "business_value": f"${cost_analysis['immediate_savings_monthly']:.2f}/month immediate cost reduction",
2132
- "timeline": "1 day execution"
2245
+ "timeline": "1 day execution",
2133
2246
  },
2134
2247
  {
2135
2248
  "priority": "P1_SHORT_TERM",
2136
2249
  "action": f"Investigate and cleanup {len(step_2_investigation)} candidates requiring analysis",
2137
2250
  "business_value": f"${cost_analysis['investigation_savings_monthly']:.2f}/month potential savings",
2138
- "timeline": "7 days investigation + cleanup"
2251
+ "timeline": "7 days investigation + cleanup",
2139
2252
  },
2140
2253
  {
2141
2254
  "priority": "P2_MEDIUM_TERM",
2142
2255
  "action": f"Governance approval workflow for {len(step_3_governance)} compliance-required VPCs",
2143
2256
  "business_value": f"${cost_analysis['governance_savings_monthly']:.2f}/month with regulatory compliance",
2144
- "timeline": "21 days approval + execution"
2257
+ "timeline": "21 days approval + execution",
2145
2258
  },
2146
2259
  {
2147
2260
  "priority": "P3_LONG_TERM",
2148
2261
  "action": f"Complex migration planning for {len(step_4_complex)} high-dependency VPCs",
2149
2262
  "business_value": f"${cost_analysis['complex_savings_monthly']:.2f}/month strategic optimization",
2150
- "timeline": "90 days migration + validation"
2263
+ "timeline": "90 days migration + validation",
2151
2264
  },
2152
2265
  {
2153
2266
  "priority": "P4_STRATEGIC",
2154
2267
  "action": f"Strategic architecture review for {len(step_5_strategic)} critical VPCs",
2155
2268
  "business_value": f"${cost_analysis['strategic_savings_monthly']:.2f}/month enterprise transformation",
2156
- "timeline": "180 days comprehensive analysis"
2157
- }
2269
+ "timeline": "180 days comprehensive analysis",
2270
+ },
2158
2271
  ],
2159
-
2160
2272
  "compliance_validation": {
2161
2273
  "cis_benchmark_alignment": True,
2162
2274
  "sox_audit_readiness": True,
2163
2275
  "gdpr_data_protection": True,
2164
2276
  "change_management_process": True,
2165
- "stakeholder_approval_gates": True
2166
- }
2277
+ "stakeholder_approval_gates": True,
2278
+ },
2167
2279
  }
2168
-
2280
+
2169
2281
  console.print(f"[green]✅ Business Analysis Complete[/green]")
2170
- console.print(f"[yellow]📈 Total Annual Savings Potential: ${cost_analysis['total_annual_savings']:,.2f}[/yellow]")
2282
+ console.print(
2283
+ f"[yellow]📈 Total Annual Savings Potential: ${cost_analysis['total_annual_savings']:,.2f}[/yellow]"
2284
+ )
2171
2285
  console.print(f"[blue]📊 Average Risk Score: {risk_assessment['average_risk_score']:.1f}/10[/blue]")
2172
-
2286
+
2173
2287
  return analysis_results
2174
2288
 
2175
2289
  def _analyze_immediate_deletion_candidates(self, candidates: List[VPCCandidate]) -> List[VPCCandidate]:
2176
2290
  """Step 1: Analyze VPCs safe for immediate deletion."""
2177
2291
  return [
2178
- candidate for candidate in candidates
2179
- if (candidate.eni_count == 0 and
2180
- not candidate.load_balancers_present and
2181
- not candidate.tgw_peering_attached and
2182
- not candidate.is_default and
2183
- candidate.decision in [VPCCleanupDecision.DELETE, VPCCleanupDecision.UNUSED])
2292
+ candidate
2293
+ for candidate in candidates
2294
+ if (
2295
+ candidate.eni_count == 0
2296
+ and not candidate.load_balancers_present
2297
+ and not candidate.tgw_peering_attached
2298
+ and not candidate.is_default
2299
+ and candidate.decision in [VPCCleanupDecision.DELETE, VPCCleanupDecision.UNUSED]
2300
+ )
2184
2301
  ]
2185
-
2302
+
2186
2303
  def _analyze_investigation_required_candidates(self, candidates: List[VPCCandidate]) -> List[VPCCandidate]:
2187
2304
  """Step 2: Analyze VPCs requiring investigation before cleanup."""
2188
2305
  return [
2189
- candidate for candidate in candidates
2190
- if (candidate.eni_count <= 2 and
2191
- not candidate.load_balancers_present and
2192
- not candidate.tgw_peering_attached and
2193
- candidate.decision in [VPCCleanupDecision.INVESTIGATE, VPCCleanupDecision.UNUSED])
2306
+ candidate
2307
+ for candidate in candidates
2308
+ if (
2309
+ candidate.eni_count <= 2
2310
+ and not candidate.load_balancers_present
2311
+ and not candidate.tgw_peering_attached
2312
+ and candidate.decision in [VPCCleanupDecision.INVESTIGATE, VPCCleanupDecision.UNUSED]
2313
+ )
2194
2314
  ]
2195
-
2315
+
2196
2316
  def _analyze_governance_approval_candidates(self, candidates: List[VPCCandidate]) -> List[VPCCandidate]:
2197
2317
  """Step 3: Analyze VPCs requiring governance approval."""
2198
2318
  return [
2199
- candidate for candidate in candidates
2200
- if (candidate.is_default or
2201
- not candidate.flow_logs_enabled or
2202
- candidate.iac_managed or
2203
- candidate.decision == VPCCleanupDecision.COMPLIANCE_REQUIRED)
2319
+ candidate
2320
+ for candidate in candidates
2321
+ if (
2322
+ candidate.is_default
2323
+ or not candidate.flow_logs_enabled
2324
+ or candidate.iac_managed
2325
+ or candidate.decision == VPCCleanupDecision.COMPLIANCE_REQUIRED
2326
+ )
2204
2327
  ]
2205
-
2328
+
2206
2329
  def _analyze_complex_migration_candidates(self, candidates: List[VPCCandidate]) -> List[VPCCandidate]:
2207
2330
  """Step 4: Analyze VPCs requiring complex migration planning."""
2208
2331
  return [
2209
- candidate for candidate in candidates
2210
- if (candidate.load_balancers_present or
2211
- candidate.tgw_peering_attached or
2212
- candidate.eni_count > 5 or
2213
- candidate.decision == VPCCleanupDecision.MIGRATE)
2332
+ candidate
2333
+ for candidate in candidates
2334
+ if (
2335
+ candidate.load_balancers_present
2336
+ or candidate.tgw_peering_attached
2337
+ or candidate.eni_count > 5
2338
+ or candidate.decision == VPCCleanupDecision.MIGRATE
2339
+ )
2214
2340
  ]
2215
-
2341
+
2216
2342
  def _analyze_strategic_review_candidates(self, candidates: List[VPCCandidate]) -> List[VPCCandidate]:
2217
2343
  """Step 5: Analyze VPCs requiring strategic architectural review."""
2218
2344
  return [
2219
- candidate for candidate in candidates
2220
- if (candidate.cidr_overlapping or
2221
- candidate.decision in [VPCCleanupDecision.KEEP, VPCCleanupDecision.CRITICAL] or
2222
- (candidate.eni_count > 10 and candidate.load_balancers_present and candidate.tgw_peering_attached))
2345
+ candidate
2346
+ for candidate in candidates
2347
+ if (
2348
+ candidate.cidr_overlapping
2349
+ or candidate.decision in [VPCCleanupDecision.KEEP, VPCCleanupDecision.CRITICAL]
2350
+ or (candidate.eni_count > 10 and candidate.load_balancers_present and candidate.tgw_peering_attached)
2351
+ )
2223
2352
  ]
2224
-
2353
+
2225
2354
  async def _calculate_cost_impact_analysis(self, candidates: List[VPCCandidate]) -> Dict[str, float]:
2226
2355
  """Calculate comprehensive cost impact analysis."""
2227
2356
  # Base VPC costs (estimated per VPC per month)
2228
2357
  base_vpc_cost_monthly = 0.0 # VPCs themselves are free
2229
2358
  nat_gateway_cost_monthly = self._get_dynamic_nat_gateway_cost() # Dynamic NAT Gateway pricing
2230
-
2359
+
2231
2360
  step_1_candidates = self._analyze_immediate_deletion_candidates(candidates)
2232
2361
  step_2_candidates = self._analyze_investigation_required_candidates(candidates)
2233
2362
  step_3_candidates = self._analyze_governance_approval_candidates(candidates)
2234
2363
  step_4_candidates = self._analyze_complex_migration_candidates(candidates)
2235
2364
  step_5_candidates = self._analyze_strategic_review_candidates(candidates)
2236
-
2365
+
2237
2366
  # Estimate savings based on ENI count and infrastructure
2238
2367
  immediate_savings = len(step_1_candidates) * 15.0 # Conservative estimate
2239
2368
  investigation_savings = len(step_2_candidates) * 25.0
2240
2369
  governance_savings = len(step_3_candidates) * 35.0
2241
2370
  complex_savings = len(step_4_candidates) * 50.0
2242
2371
  strategic_savings = len(step_5_candidates) * 75.0
2243
-
2244
- total_monthly = immediate_savings + investigation_savings + governance_savings + complex_savings + strategic_savings
2372
+
2373
+ total_monthly = (
2374
+ immediate_savings + investigation_savings + governance_savings + complex_savings + strategic_savings
2375
+ )
2245
2376
  total_annual = total_monthly * 12
2246
-
2377
+
2247
2378
  return {
2248
2379
  "immediate_savings_monthly": immediate_savings,
2249
2380
  "investigation_savings_monthly": investigation_savings,
@@ -2252,21 +2383,21 @@ class VPCScenarioEngine:
2252
2383
  "strategic_savings_monthly": strategic_savings,
2253
2384
  "total_monthly_savings": total_monthly,
2254
2385
  "total_annual_savings": total_annual,
2255
- "roi_percentage": (total_annual / max(1, total_annual * 0.1)) * 100 # Assume 10% cleanup cost
2386
+ "roi_percentage": (total_annual / max(1, total_annual * 0.1)) * 100, # Assume 10% cleanup cost
2256
2387
  }
2257
-
2388
+
2258
2389
  async def _calculate_operational_risk_scores(self, candidates: List[VPCCandidate]) -> Dict[str, Any]:
2259
2390
  """Calculate operational risk scores for all candidates."""
2260
2391
  risk_scores = []
2261
2392
  high_risk_count = 0
2262
2393
  complexity_factors = []
2263
-
2394
+
2264
2395
  for candidate in candidates:
2265
2396
  risk_score = 0.0
2266
-
2397
+
2267
2398
  # ENI count risk (active workloads)
2268
2399
  risk_score += min(30, candidate.eni_count * 3)
2269
-
2400
+
2270
2401
  # Infrastructure complexity risk
2271
2402
  if candidate.load_balancers_present:
2272
2403
  risk_score += 20
@@ -2278,12 +2409,12 @@ class VPCScenarioEngine:
2278
2409
  risk_score += 10
2279
2410
  if candidate.cidr_overlapping:
2280
2411
  risk_score += 10
2281
-
2412
+
2282
2413
  risk_scores.append(risk_score)
2283
-
2414
+
2284
2415
  if risk_score >= 60:
2285
2416
  high_risk_count += 1
2286
-
2417
+
2287
2418
  # Complexity score (0-10 scale)
2288
2419
  complexity = 0
2289
2420
  complexity += 1 if candidate.eni_count > 0 else 0
@@ -2292,13 +2423,13 @@ class VPCScenarioEngine:
2292
2423
  complexity += 1 if candidate.is_default else 0
2293
2424
  complexity += 1 if candidate.iac_managed else 0
2294
2425
  complexity_factors.append(complexity)
2295
-
2426
+
2296
2427
  return {
2297
2428
  "average_risk_score": sum(risk_scores) / len(risk_scores) if risk_scores else 0,
2298
2429
  "high_risk_count": high_risk_count,
2299
- "complexity_score": sum(complexity_factors) / len(complexity_factors) if complexity_factors else 0
2430
+ "complexity_score": sum(complexity_factors) / len(complexity_factors) if complexity_factors else 0,
2300
2431
  }
2301
-
2432
+
2302
2433
  def _calculate_cleanup_timeline_estimates(self, candidates: List[VPCCandidate]) -> Dict[str, Any]:
2303
2434
  """Calculate cleanup timeline estimates."""
2304
2435
  step_1_candidates = self._analyze_immediate_deletion_candidates(candidates)
@@ -2306,113 +2437,119 @@ class VPCScenarioEngine:
2306
2437
  step_3_candidates = self._analyze_governance_approval_candidates(candidates)
2307
2438
  step_4_candidates = self._analyze_complex_migration_candidates(candidates)
2308
2439
  step_5_candidates = self._analyze_strategic_review_candidates(candidates)
2309
-
2440
+
2310
2441
  # Timeline estimates in days
2311
2442
  timeline_estimates = {
2312
2443
  "immediate": 1 if step_1_candidates else 0,
2313
2444
  "investigation": 7 if step_2_candidates else 0,
2314
2445
  "governance": 21 if step_3_candidates else 0,
2315
2446
  "complex": 90 if step_4_candidates else 0,
2316
- "strategic": 180 if step_5_candidates else 0
2447
+ "strategic": 180 if step_5_candidates else 0,
2317
2448
  }
2318
-
2449
+
2319
2450
  # Calculate total timeline (parallel execution considered)
2320
2451
  total_timeline = max(timeline_estimates.values()) if any(timeline_estimates.values()) else 0
2321
-
2452
+
2322
2453
  return {
2323
2454
  "step_timelines": timeline_estimates,
2324
2455
  "total_timeline_days": total_timeline,
2325
- "parallel_execution_possible": len([t for t in timeline_estimates.values() if t > 0]) > 1
2456
+ "parallel_execution_possible": len([t for t in timeline_estimates.values() if t > 0]) > 1,
2326
2457
  }
2327
-
2458
+
2328
2459
  async def validate_candidates_with_mcp(self, candidates: Optional[List[VPCCandidate]] = None) -> Dict[str, float]:
2329
2460
  """
2330
2461
  Validate VPC candidates using MCP-style AWS API validation.
2331
-
2462
+
2332
2463
  Returns validation summary with accuracy metrics.
2333
2464
  """
2334
2465
  if candidates is None:
2335
2466
  candidates = self.vpc_candidates
2336
-
2467
+
2337
2468
  print_info(f"Starting MCP validation for {len(candidates)} VPC candidates")
2338
-
2469
+
2339
2470
  validation_summary = {
2340
- 'total_candidates': len(candidates),
2341
- 'validated_successfully': 0,
2342
- 'validation_failures': 0,
2343
- 'average_accuracy': 0.0,
2344
- 'mcp_target_achieved': False
2471
+ "total_candidates": len(candidates),
2472
+ "validated_successfully": 0,
2473
+ "validation_failures": 0,
2474
+ "average_accuracy": 0.0,
2475
+ "mcp_target_achieved": False,
2345
2476
  }
2346
-
2477
+
2347
2478
  total_accuracy = 0.0
2348
-
2479
+
2349
2480
  with Progress(
2350
2481
  SpinnerColumn(),
2351
2482
  TextColumn("[progress.description]{task.description}"),
2352
2483
  BarColumn(),
2353
2484
  TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
2354
2485
  ) as progress:
2355
-
2356
2486
  validation_task = progress.add_task("MCP Validation Progress", total=len(candidates))
2357
-
2487
+
2358
2488
  for candidate in candidates:
2359
2489
  success, accuracy, details = await self.mcp_validator.validate_vpc_candidate(candidate)
2360
-
2490
+
2361
2491
  # Update candidate with validation results
2362
2492
  candidate.mcp_validated = success
2363
2493
  candidate.mcp_accuracy = accuracy
2364
2494
  candidate.last_validated = datetime.now()
2365
-
2495
+
2366
2496
  # Update summary statistics
2367
2497
  if success:
2368
- validation_summary['validated_successfully'] += 1
2498
+ validation_summary["validated_successfully"] += 1
2369
2499
  else:
2370
- validation_summary['validation_failures'] += 1
2371
-
2500
+ validation_summary["validation_failures"] += 1
2501
+
2372
2502
  total_accuracy += accuracy
2373
2503
  self.mcp_validation_count += 1
2374
-
2504
+
2375
2505
  progress.advance(validation_task)
2376
-
2506
+
2377
2507
  # Calculate final accuracy metrics
2378
- validation_summary['average_accuracy'] = total_accuracy / len(candidates) if candidates else 0.0
2379
- validation_summary['mcp_target_achieved'] = validation_summary['average_accuracy'] >= 99.5
2380
-
2381
- self.total_accuracy_score = validation_summary['average_accuracy']
2382
-
2508
+ validation_summary["average_accuracy"] = total_accuracy / len(candidates) if candidates else 0.0
2509
+ validation_summary["mcp_target_achieved"] = validation_summary["average_accuracy"] >= 99.5
2510
+
2511
+ self.total_accuracy_score = validation_summary["average_accuracy"]
2512
+
2383
2513
  # Display validation results
2384
- if validation_summary['mcp_target_achieved']:
2385
- print_success(f"✅ MCP Validation: {validation_summary['average_accuracy']:.1f}% accuracy (≥99.5% target achieved)")
2514
+ if validation_summary["mcp_target_achieved"]:
2515
+ print_success(
2516
+ f"✅ MCP Validation: {validation_summary['average_accuracy']:.1f}% accuracy (≥99.5% target achieved)"
2517
+ )
2386
2518
  else:
2387
- print_warning(f"⚠️ MCP Validation: {validation_summary['average_accuracy']:.1f}% accuracy (below 99.5% target)")
2388
-
2519
+ print_warning(
2520
+ f"⚠️ MCP Validation: {validation_summary['average_accuracy']:.1f}% accuracy (below 99.5% target)"
2521
+ )
2522
+
2389
2523
  return validation_summary
2390
-
2524
+
2391
2525
  def execute_5step_validation_analysis(self) -> Dict[ValidationStep, ValidationStepResult]:
2392
2526
  """
2393
2527
  Execute enhanced 5-step comprehensive dual validation analysis with business intelligence.
2394
-
2528
+
2395
2529
  Returns detailed results for each validation step with quantified business metrics:
2396
2530
  - Step 1: Immediate Deletion (0 ENI, no LB, no TGW, non-default) - LOW risk, 1 day
2397
- - Step 2: Investigation Required (≤2 ENI, minimal infrastructure) - MEDIUM-LOW risk, 7 days
2531
+ - Step 2: Investigation Required (≤2 ENI, minimal infrastructure) - MEDIUM-LOW risk, 7 days
2398
2532
  - Step 3: Governance Approval (default VPCs, no flow logs, IaC managed) - MEDIUM risk, 21 days
2399
2533
  - Step 4: Complex Migration (load balancers, TGW, >5 ENI) - HIGH risk, 90 days
2400
2534
  - Step 5: Strategic Review (CIDR overlap, critical VPCs, complex architecture) - CRITICAL risk, 180 days
2401
2535
  """
2402
2536
  print_header("Enhanced 5-Step Business Intelligence Analysis", "Enterprise Framework latest version")
2403
-
2537
+
2404
2538
  results = {}
2405
2539
  total_vpcs = len(self.vpc_candidates)
2406
-
2540
+
2407
2541
  # Step 1: Immediate Deletion Candidates (Enhanced criteria per WIP.md)
2408
2542
  immediate_candidates = [
2409
- vpc for vpc in self.vpc_candidates
2410
- if (vpc.eni_count == 0 and
2411
- not vpc.load_balancers_present and
2412
- not vpc.tgw_peering_attached and
2413
- not vpc.is_default)
2543
+ vpc
2544
+ for vpc in self.vpc_candidates
2545
+ if (
2546
+ vpc.eni_count == 0
2547
+ and not vpc.load_balancers_present
2548
+ and not vpc.tgw_peering_attached
2549
+ and not vpc.is_default
2550
+ )
2414
2551
  ]
2415
-
2552
+
2416
2553
  step1_result = ValidationStepResult(
2417
2554
  step=ValidationStep.IMMEDIATE_DELETION,
2418
2555
  vpc_count=len(immediate_candidates),
@@ -2422,22 +2559,26 @@ class VPCScenarioEngine:
2422
2559
  recommendations=[
2423
2560
  "Execute immediate automated deletion within 1 day",
2424
2561
  "No traffic analysis required - zero active resources",
2425
- "Implement batch deletion via Runbooks automation"
2562
+ "Implement batch deletion via Runbooks automation",
2426
2563
  ],
2427
2564
  risk_assessment="LOW risk - no active resources or dependencies detected",
2428
- timeline_estimate="1 day"
2565
+ timeline_estimate="1 day",
2429
2566
  )
2430
2567
  results[ValidationStep.IMMEDIATE_DELETION] = step1_result
2431
-
2432
- # Step 2: Investigation Required (Enhanced criteria per WIP.md)
2568
+
2569
+ # Step 2: Investigation Required (Enhanced criteria per WIP.md)
2433
2570
  investigation_candidates = [
2434
- vpc for vpc in self.vpc_candidates
2435
- if (vpc.eni_count > 0 and vpc.eni_count <= 2 and
2436
- not vpc.load_balancers_present and
2437
- not vpc.tgw_peering_attached and
2438
- vpc not in immediate_candidates)
2571
+ vpc
2572
+ for vpc in self.vpc_candidates
2573
+ if (
2574
+ vpc.eni_count > 0
2575
+ and vpc.eni_count <= 2
2576
+ and not vpc.load_balancers_present
2577
+ and not vpc.tgw_peering_attached
2578
+ and vpc not in immediate_candidates
2579
+ )
2439
2580
  ]
2440
-
2581
+
2441
2582
  step2_result = ValidationStepResult(
2442
2583
  step=ValidationStep.INVESTIGATION_REQUIRED,
2443
2584
  vpc_count=len(investigation_candidates),
@@ -2447,21 +2588,24 @@ class VPCScenarioEngine:
2447
2588
  recommendations=[
2448
2589
  "Conduct 7-day traffic analysis using VPC Flow Logs",
2449
2590
  "Verify ENI attachment status and usage patterns",
2450
- "Coordinate with resource owners for cleanup approval"
2591
+ "Coordinate with resource owners for cleanup approval",
2451
2592
  ],
2452
2593
  risk_assessment="MEDIUM-LOW risk - minimal infrastructure requires validation",
2453
- timeline_estimate="7 days"
2594
+ timeline_estimate="7 days",
2454
2595
  )
2455
2596
  results[ValidationStep.INVESTIGATION_REQUIRED] = step2_result
2456
-
2597
+
2457
2598
  # Step 3: Governance Approval (Enhanced criteria per WIP.md)
2458
2599
  governance_candidates = [
2459
- vpc for vpc in self.vpc_candidates
2460
- if ((vpc.is_default or not vpc.flow_logs_enabled or vpc.iac_managed) and
2461
- vpc not in immediate_candidates and
2462
- vpc not in investigation_candidates)
2600
+ vpc
2601
+ for vpc in self.vpc_candidates
2602
+ if (
2603
+ (vpc.is_default or not vpc.flow_logs_enabled or vpc.iac_managed)
2604
+ and vpc not in immediate_candidates
2605
+ and vpc not in investigation_candidates
2606
+ )
2463
2607
  ]
2464
-
2608
+
2465
2609
  step3_result = ValidationStepResult(
2466
2610
  step=ValidationStep.GOVERNANCE_APPROVAL,
2467
2611
  vpc_count=len(governance_candidates),
@@ -2471,22 +2615,25 @@ class VPCScenarioEngine:
2471
2615
  recommendations=[
2472
2616
  "Obtain management approval for default VPC deletion",
2473
2617
  "Enable VPC Flow Logs before deletion analysis",
2474
- "Coordinate with Infrastructure-as-Code teams for managed resources"
2618
+ "Coordinate with Infrastructure-as-Code teams for managed resources",
2475
2619
  ],
2476
2620
  risk_assessment="MEDIUM risk - requires governance approval and compliance validation",
2477
- timeline_estimate="21 days"
2621
+ timeline_estimate="21 days",
2478
2622
  )
2479
2623
  results[ValidationStep.GOVERNANCE_APPROVAL] = step3_result
2480
-
2624
+
2481
2625
  # Step 4: Complex Migration (Enhanced criteria per WIP.md)
2482
2626
  complex_candidates = [
2483
- vpc for vpc in self.vpc_candidates
2484
- if ((vpc.load_balancers_present or vpc.tgw_peering_attached or vpc.eni_count > 5) and
2485
- vpc not in immediate_candidates and
2486
- vpc not in investigation_candidates and
2487
- vpc not in governance_candidates)
2627
+ vpc
2628
+ for vpc in self.vpc_candidates
2629
+ if (
2630
+ (vpc.load_balancers_present or vpc.tgw_peering_attached or vpc.eni_count > 5)
2631
+ and vpc not in immediate_candidates
2632
+ and vpc not in investigation_candidates
2633
+ and vpc not in governance_candidates
2634
+ )
2488
2635
  ]
2489
-
2636
+
2490
2637
  step4_result = ValidationStepResult(
2491
2638
  step=ValidationStep.COMPLEX_MIGRATION,
2492
2639
  vpc_count=len(complex_candidates),
@@ -2496,26 +2643,27 @@ class VPCScenarioEngine:
2496
2643
  recommendations=[
2497
2644
  "Design comprehensive migration strategy for load balancer dependencies",
2498
2645
  "Plan Transit Gateway detachment with connectivity analysis",
2499
- "Coordinate multi-team migration with 90-day phased approach"
2646
+ "Coordinate multi-team migration with 90-day phased approach",
2500
2647
  ],
2501
2648
  risk_assessment="HIGH risk - complex infrastructure requires careful migration planning",
2502
- timeline_estimate="90 days"
2649
+ timeline_estimate="90 days",
2503
2650
  )
2504
2651
  results[ValidationStep.COMPLEX_MIGRATION] = step4_result
2505
-
2652
+
2506
2653
  # Step 5: Strategic Review (Enhanced criteria per WIP.md)
2507
2654
  strategic_candidates = [
2508
- vpc for vpc in self.vpc_candidates
2509
- if vpc not in (immediate_candidates + investigation_candidates +
2510
- governance_candidates + complex_candidates)
2655
+ vpc
2656
+ for vpc in self.vpc_candidates
2657
+ if vpc not in (immediate_candidates + investigation_candidates + governance_candidates + complex_candidates)
2511
2658
  ]
2512
-
2659
+
2513
2660
  # Enhance strategic candidates with CIDR overlap analysis
2514
2661
  cidr_overlap_candidates = [
2515
- vpc for vpc in strategic_candidates
2662
+ vpc
2663
+ for vpc in strategic_candidates
2516
2664
  if vpc.overlapping # CIDR overlap detected
2517
2665
  ]
2518
-
2666
+
2519
2667
  step5_result = ValidationStepResult(
2520
2668
  step=ValidationStep.STRATEGIC_REVIEW,
2521
2669
  vpc_count=len(strategic_candidates),
@@ -2526,15 +2674,15 @@ class VPCScenarioEngine:
2526
2674
  "Conduct enterprise architectural review with solutions architect",
2527
2675
  "Analyze CIDR overlap impact on network architecture",
2528
2676
  "Evaluate long-term strategic consolidation opportunities",
2529
- "Consider 180-day strategic migration planning"
2677
+ "Consider 180-day strategic migration planning",
2530
2678
  ],
2531
2679
  risk_assessment="CRITICAL risk - strategic architectural decisions required",
2532
- timeline_estimate="180 days"
2680
+ timeline_estimate="180 days",
2533
2681
  )
2534
2682
  results[ValidationStep.STRATEGIC_REVIEW] = step5_result
2535
-
2683
+
2536
2684
  self.validation_results = results
2537
-
2685
+
2538
2686
  # Enhanced display with business intelligence metrics
2539
2687
  summary_table = Table(title="Enhanced 5-Step Business Intelligence Analysis")
2540
2688
  summary_table.add_column("Step", style="cyan", no_wrap=True)
@@ -2543,17 +2691,17 @@ class VPCScenarioEngine:
2543
2691
  summary_table.add_column("Percentage", justify="right", style="green")
2544
2692
  summary_table.add_column("Timeline", justify="right", style="blue")
2545
2693
  summary_table.add_column("Business Impact", style="magenta")
2546
-
2694
+
2547
2695
  # Add risk level and business impact columns
2548
2696
  risk_levels = ["LOW", "MEDIUM-LOW", "MEDIUM", "HIGH", "CRITICAL"]
2549
2697
  business_impacts = [
2550
2698
  "Quick wins - immediate savings",
2551
2699
  "Short-term validation - low effort",
2552
- "Compliance improvement - governance value",
2700
+ "Compliance improvement - governance value",
2553
2701
  "Complex migration - strategic planning",
2554
- "Architecture consolidation - long-term value"
2702
+ "Architecture consolidation - long-term value",
2555
2703
  ]
2556
-
2704
+
2557
2705
  for i, step_result in enumerate(results.values()):
2558
2706
  summary_table.add_row(
2559
2707
  step_result.step.value.split(":")[0],
@@ -2561,90 +2709,97 @@ class VPCScenarioEngine:
2561
2709
  str(step_result.vpc_count),
2562
2710
  f"{step_result.percentage:.1f}%",
2563
2711
  step_result.timeline_estimate,
2564
- business_impacts[i]
2712
+ business_impacts[i],
2565
2713
  )
2566
-
2714
+
2567
2715
  console.print(summary_table)
2568
-
2716
+
2569
2717
  return results
2570
-
2718
+
2571
2719
  def generate_business_impact_summary(self) -> BusinessImpactSummary:
2572
2720
  """
2573
2721
  Generate enhanced business impact summary with quantified business metrics.
2574
-
2722
+
2575
2723
  Includes comprehensive cost impact analysis, risk assessment, timeline estimation,
2576
2724
  and ROI calculation as required for enterprise decision making.
2577
2725
  """
2578
2726
  if not self.validation_results:
2579
2727
  raise ValueError("Must execute validation analysis before generating business impact")
2580
-
2728
+
2581
2729
  total_vpcs = len(self.vpc_candidates)
2582
-
2730
+
2583
2731
  # Extract step results
2584
2732
  step1_immediate = self.validation_results[ValidationStep.IMMEDIATE_DELETION]
2585
- step2_investigation = self.validation_results[ValidationStep.INVESTIGATION_REQUIRED]
2733
+ step2_investigation = self.validation_results[ValidationStep.INVESTIGATION_REQUIRED]
2586
2734
  step3_governance = self.validation_results[ValidationStep.GOVERNANCE_APPROVAL]
2587
2735
  step4_complex = self.validation_results[ValidationStep.COMPLEX_MIGRATION]
2588
2736
  step5_strategic = self.validation_results[ValidationStep.STRATEGIC_REVIEW]
2589
-
2737
+
2590
2738
  # Cost Impact Analysis: Monthly and annual savings projections by step category
2591
2739
  # Dynamic cost calculation based on real AWS pricing - NO hardcoded values
2592
2740
  vpc_base_cost_monthly = self._get_dynamic_vpc_cost_estimate() # Real AWS pricing integration
2593
2741
  step1_monthly_savings = step1_immediate.vpc_count * vpc_base_cost_monthly
2594
2742
  step2_monthly_savings = step2_investigation.vpc_count * (vpc_base_cost_monthly * 0.7) # 70% of base cost
2595
- step3_monthly_savings = step3_governance.vpc_count * (vpc_base_cost_monthly * 0.8) # 80% of base cost
2596
- step4_monthly_savings = step4_complex.vpc_count * (vpc_base_cost_monthly * 1.2) # 120% due to complex resources
2597
- step5_monthly_savings = step5_strategic.vpc_count * (vpc_base_cost_monthly * 1.5) # 150% strategic value
2598
-
2599
- total_monthly_savings = (step1_monthly_savings + step2_monthly_savings +
2600
- step3_monthly_savings + step4_monthly_savings + step5_monthly_savings)
2743
+ step3_monthly_savings = step3_governance.vpc_count * (vpc_base_cost_monthly * 0.8) # 80% of base cost
2744
+ step4_monthly_savings = step4_complex.vpc_count * (vpc_base_cost_monthly * 1.2) # 120% due to complex resources
2745
+ step5_monthly_savings = step5_strategic.vpc_count * (vpc_base_cost_monthly * 1.5) # 150% strategic value
2746
+
2747
+ total_monthly_savings = (
2748
+ step1_monthly_savings
2749
+ + step2_monthly_savings
2750
+ + step3_monthly_savings
2751
+ + step4_monthly_savings
2752
+ + step5_monthly_savings
2753
+ )
2601
2754
  total_annual_savings = total_monthly_savings * 12
2602
-
2755
+
2603
2756
  # Risk Assessment: Average risk scores with high-risk VPC identification
2604
2757
  risk_scores = {
2605
- ValidationStep.IMMEDIATE_DELETION: 1.0, # LOW risk
2606
- ValidationStep.INVESTIGATION_REQUIRED: 2.5, # MEDIUM-LOW risk
2607
- ValidationStep.GOVERNANCE_APPROVAL: 4.0, # MEDIUM risk
2608
- ValidationStep.COMPLEX_MIGRATION: 7.0, # HIGH risk
2609
- ValidationStep.STRATEGIC_REVIEW: 9.0 # CRITICAL risk
2758
+ ValidationStep.IMMEDIATE_DELETION: 1.0, # LOW risk
2759
+ ValidationStep.INVESTIGATION_REQUIRED: 2.5, # MEDIUM-LOW risk
2760
+ ValidationStep.GOVERNANCE_APPROVAL: 4.0, # MEDIUM risk
2761
+ ValidationStep.COMPLEX_MIGRATION: 7.0, # HIGH risk
2762
+ ValidationStep.STRATEGIC_REVIEW: 9.0, # CRITICAL risk
2610
2763
  }
2611
-
2764
+
2612
2765
  weighted_risk_score = 0.0
2613
2766
  for step, result in self.validation_results.items():
2614
2767
  if result.vpc_count > 0:
2615
2768
  weighted_risk_score += (result.vpc_count / total_vpcs) * risk_scores[step]
2616
-
2769
+
2617
2770
  high_risk_vpcs = step4_complex.vpc_count + step5_strategic.vpc_count
2618
-
2771
+
2619
2772
  # Timeline Estimation: Parallel execution planning with resource coordination
2620
2773
  parallel_execution_plan = {
2621
2774
  "Phase 1 (Days 1-7)": f"Execute {step1_immediate.vpc_count} immediate deletions in parallel",
2622
2775
  "Phase 2 (Days 8-14)": f"Begin traffic analysis for {step2_investigation.vpc_count} investigation candidates",
2623
2776
  "Phase 3 (Days 15-35)": f"Governance approval process for {step3_governance.vpc_count} VPCs",
2624
2777
  "Phase 4 (Days 36-125)": f"Complex migration planning for {step4_complex.vpc_count} VPCs",
2625
- "Phase 5 (Days 126-305)": f"Strategic architectural review for {step5_strategic.vpc_count} VPCs"
2778
+ "Phase 5 (Days 126-305)": f"Strategic architectural review for {step5_strategic.vpc_count} VPCs",
2626
2779
  }
2627
-
2780
+
2628
2781
  # ROI Calculation: 12-month return on investment with cleanup cost considerations
2629
2782
  cleanup_labor_hours = (
2630
- step1_immediate.vpc_count * 0.5 + # 30 minutes per immediate deletion
2631
- step2_investigation.vpc_count * 8 + # 8 hours per investigation
2632
- step3_governance.vpc_count * 16 + # 16 hours per governance approval
2633
- step4_complex.vpc_count * 40 + # 40 hours per complex migration
2634
- step5_strategic.vpc_count * 80 # 80 hours per strategic review
2783
+ step1_immediate.vpc_count * 0.5 # 30 minutes per immediate deletion
2784
+ + step2_investigation.vpc_count * 8 # 8 hours per investigation
2785
+ + step3_governance.vpc_count * 16 # 16 hours per governance approval
2786
+ + step4_complex.vpc_count * 40 # 40 hours per complex migration
2787
+ + step5_strategic.vpc_count * 80 # 80 hours per strategic review
2635
2788
  )
2636
-
2789
+
2637
2790
  labor_cost_per_hour = self._get_dynamic_labor_rate() # Enterprise DevOps engineer rate (dynamic)
2638
2791
  total_cleanup_cost = cleanup_labor_hours * labor_cost_per_hour
2639
-
2640
- roi_12_months = ((total_annual_savings - total_cleanup_cost) / total_cleanup_cost * 100) if total_cleanup_cost > 0 else 0
2792
+
2793
+ roi_12_months = (
2794
+ ((total_annual_savings - total_cleanup_cost) / total_cleanup_cost * 100) if total_cleanup_cost > 0 else 0
2795
+ )
2641
2796
  payback_months = (total_cleanup_cost / total_monthly_savings) if total_monthly_savings > 0 else 0
2642
-
2797
+
2643
2798
  # Enhanced key metrics
2644
2799
  security_value_pct = step1_immediate.percentage
2645
2800
  default_vpc_count = len([vpc for vpc in self.vpc_candidates if vpc.is_default])
2646
2801
  zero_dependencies_pct = (step1_immediate.vpc_count / total_vpcs * 100) if total_vpcs > 0 else 0
2647
-
2802
+
2648
2803
  business_impact = BusinessImpactSummary(
2649
2804
  security_value_percentage=security_value_pct,
2650
2805
  immediate_deletion_ready=step1_immediate.vpc_count,
@@ -2658,12 +2813,12 @@ class VPCScenarioEngine:
2658
2813
  f"Phase 2: Investigation Required ({step2_investigation.vpc_count} VPCs - 7 days)",
2659
2814
  f"Phase 3: Governance Approval ({step3_governance.vpc_count} VPCs - 21 days)",
2660
2815
  f"Phase 4: Complex Migration ({step4_complex.vpc_count} VPCs - 90 days)",
2661
- f"Phase 5: Strategic Review ({step5_strategic.vpc_count} VPCs - 180 days)"
2816
+ f"Phase 5: Strategic Review ({step5_strategic.vpc_count} VPCs - 180 days)",
2662
2817
  ],
2663
2818
  estimated_annual_savings=total_annual_savings,
2664
- risk_reduction_score=((10.0 - weighted_risk_score) * 10) # Convert to 0-100 scale
2819
+ risk_reduction_score=((10.0 - weighted_risk_score) * 10), # Convert to 0-100 scale
2665
2820
  )
2666
-
2821
+
2667
2822
  # Store enhanced business metrics
2668
2823
  business_impact.monthly_cost_savings = total_monthly_savings
2669
2824
  business_impact.cleanup_cost_estimate = total_cleanup_cost
@@ -2673,106 +2828,109 @@ class VPCScenarioEngine:
2673
2828
  business_impact.high_risk_vpcs_count = high_risk_vpcs
2674
2829
  business_impact.parallel_execution_plan = parallel_execution_plan
2675
2830
  business_impact.total_cleanup_hours = cleanup_labor_hours
2676
-
2831
+
2677
2832
  self.business_impact = business_impact
2678
2833
  return business_impact
2679
-
2834
+
2680
2835
  def _get_dynamic_vpc_cost_estimate(self) -> float:
2681
2836
  """
2682
2837
  Get dynamic VPC base cost estimate from real AWS pricing.
2683
-
2838
+
2684
2839
  Returns:
2685
2840
  float: Monthly base cost estimate for VPC infrastructure
2686
2841
  """
2687
2842
  try:
2688
2843
  # Use AWS Pricing API to get real-time VPC cost estimates
2689
2844
  # This replaces hardcoded $45.00 with dynamic pricing
2690
- pricing_client = self.session.client('pricing', region_name='us-east-1')
2691
-
2845
+ pricing_client = self.session.client("pricing", region_name="us-east-1")
2846
+
2692
2847
  # Get NAT Gateway pricing (primary VPC cost component)
2693
2848
  nat_gateway_response = pricing_client.get_products(
2694
- ServiceCode='AmazonVPC',
2849
+ ServiceCode="AmazonVPC",
2695
2850
  Filters=[
2696
- {'Type': 'TERM_MATCH', 'Field': 'productFamily', 'Value': 'NAT Gateway'},
2697
- {'Type': 'TERM_MATCH', 'Field': 'location', 'Value': 'US East (N. Virginia)'}
2851
+ {"Type": "TERM_MATCH", "Field": "productFamily", "Value": "NAT Gateway"},
2852
+ {"Type": "TERM_MATCH", "Field": "location", "Value": "US East (N. Virginia)"},
2698
2853
  ],
2699
- MaxResults=1
2854
+ MaxResults=1,
2700
2855
  )
2701
-
2702
- if nat_gateway_response.get('PriceList'):
2703
- price_data = json.loads(nat_gateway_response['PriceList'][0])
2704
- terms = price_data.get('terms', {}).get('OnDemand', {})
2856
+
2857
+ if nat_gateway_response.get("PriceList"):
2858
+ price_data = json.loads(nat_gateway_response["PriceList"][0])
2859
+ terms = price_data.get("terms", {}).get("OnDemand", {})
2705
2860
  if terms:
2706
2861
  term_data = list(terms.values())[0]
2707
- price_dims = term_data.get('priceDimensions', {})
2862
+ price_dims = term_data.get("priceDimensions", {})
2708
2863
  if price_dims:
2709
2864
  price_dim = list(price_dims.values())[0]
2710
- hourly_rate = float(price_dim.get('pricePerUnit', {}).get('USD', '0.045'))
2865
+ hourly_rate = float(price_dim.get("pricePerUnit", {}).get("USD", "0.045"))
2711
2866
  monthly_rate = hourly_rate * 24 * 30 # Convert to monthly
2712
2867
  return monthly_rate
2713
-
2868
+
2714
2869
  # Fallback to environment variable or calculated estimate
2715
2870
  import os
2716
- env_base_cost = os.getenv('VPC_BASE_MONTHLY_COST')
2871
+
2872
+ env_base_cost = os.getenv("VPC_BASE_MONTHLY_COST")
2717
2873
  if env_base_cost:
2718
2874
  return float(env_base_cost)
2719
-
2875
+
2720
2876
  # Final fallback: calculated estimate based on typical VPC components
2721
2877
  # NAT Gateway (~$32/month) + Data processing (~$10/month) + VPC endpoints (~$7/month)
2722
2878
  return 49.0 # Calculated estimate, not hardcoded baseline
2723
-
2879
+
2724
2880
  except Exception as e:
2725
- self.console.print(f"[yellow]Warning: Could not fetch dynamic pricing, using calculated estimate: {e}[/yellow]")
2881
+ self.console.print(
2882
+ f"[yellow]Warning: Could not fetch dynamic pricing, using calculated estimate: {e}[/yellow]"
2883
+ )
2726
2884
  # Return calculated estimate based on AWS pricing structure
2727
2885
  return 49.0
2728
-
2886
+
2729
2887
  def _get_dynamic_labor_rate(self) -> float:
2730
2888
  """
2731
2889
  Get dynamic labor rate for enterprise DevOps engineers.
2732
-
2890
+
2733
2891
  Returns:
2734
2892
  float: Hourly rate for enterprise DevOps engineer
2735
2893
  """
2736
2894
  import os
2737
-
2895
+
2738
2896
  # Check for environment variable configuration
2739
- env_labor_rate = os.getenv('ENTERPRISE_DEVOPS_HOURLY_RATE')
2897
+ env_labor_rate = os.getenv("ENTERPRISE_DEVOPS_HOURLY_RATE")
2740
2898
  if env_labor_rate:
2741
2899
  return float(env_labor_rate)
2742
-
2900
+
2743
2901
  # Use market-based rate calculation (not hardcoded)
2744
2902
  # Based on enterprise DevOps engineer market rates
2745
2903
  base_rate = 120.0 # Market research base
2746
2904
  enterprise_multiplier = 1.25 # Enterprise premium
2747
2905
  return base_rate * enterprise_multiplier
2748
-
2906
+
2749
2907
  def export_candidate_table_markdown(self) -> str:
2750
2908
  """
2751
2909
  Export VPC candidates as markdown table with comprehensive columns.
2752
-
2753
- Columns: #, Account_ID, VPC_ID, VPC_Name, CIDR_Block, Overlapping, Is_Default,
2754
- ENI_Count, Tags, Flow_Logs, TGW/Peering, LBs_Present, IaC, Timeline,
2910
+
2911
+ Columns: #, Account_ID, VPC_ID, VPC_Name, CIDR_Block, Overlapping, Is_Default,
2912
+ ENI_Count, Tags, Flow_Logs, TGW/Peering, LBs_Present, IaC, Timeline,
2755
2913
  Decision, Owners/Approvals, Notes
2756
2914
  """
2757
2915
  if not self.vpc_candidates:
2758
2916
  return "No VPC candidates available for export."
2759
-
2917
+
2760
2918
  markdown_lines = [
2761
2919
  "# VPC Cleanup Candidates - Comprehensive Analysis",
2762
2920
  "",
2763
2921
  "| # | Account_ID | VPC_ID | VPC_Name | CIDR_Block | Overlapping | Is_Default | ENI_Count | Tags | Flow_Logs | TGW/Peering | LBs_Present | IaC | Timeline | Decision | Owners/Approvals | Notes |",
2764
- "|---|------------|--------|----------|------------|-------------|------------|-----------|------|-----------|-------------|-------------|-----|----------|----------|------------------|-------|"
2922
+ "|---|------------|--------|----------|------------|-------------|------------|-----------|------|-----------|-------------|-------------|-----|----------|----------|------------------|-------|",
2765
2923
  ]
2766
-
2924
+
2767
2925
  for candidate in self.vpc_candidates:
2768
2926
  # Format tags as key=value pairs
2769
2927
  tags_str = "; ".join([f"{k}={v}" for k, v in candidate.tags.items()][:3]) # Limit to first 3 tags
2770
2928
  if len(candidate.tags) > 3:
2771
- tags_str += f" (+{len(candidate.tags)-3} more)"
2772
-
2929
+ tags_str += f" (+{len(candidate.tags) - 3} more)"
2930
+
2773
2931
  # Format owners/approvals
2774
2932
  owners_str = "; ".join(candidate.owners_approvals) if candidate.owners_approvals else "None"
2775
-
2933
+
2776
2934
  markdown_lines.append(
2777
2935
  f"| {candidate.sequence_number} | "
2778
2936
  f"{candidate.account_id} | "
@@ -2792,22 +2950,24 @@ class VPCScenarioEngine:
2792
2950
  f"{owners_str} | "
2793
2951
  f"{candidate.notes} |"
2794
2952
  )
2795
-
2953
+
2796
2954
  # Add MCP validation summary
2797
2955
  if self.total_accuracy_score > 0:
2798
- markdown_lines.extend([
2799
- "",
2800
- "## MCP Validation Summary",
2801
- "",
2802
- f"- **Total Candidates Validated**: {len(self.vpc_candidates)}",
2803
- f"- **Average Validation Accuracy**: {self.total_accuracy_score:.1f}%",
2804
- f"- **MCP Target Achievement**: {'✅ Yes' if self.total_accuracy_score >= 99.5 else '⚠️ No'} (≥99.5% target)",
2805
- f"- **Validation Timestamp**: {datetime.now().isoformat()}",
2806
- ""
2807
- ])
2808
-
2956
+ markdown_lines.extend(
2957
+ [
2958
+ "",
2959
+ "## MCP Validation Summary",
2960
+ "",
2961
+ f"- **Total Candidates Validated**: {len(self.vpc_candidates)}",
2962
+ f"- **Average Validation Accuracy**: {self.total_accuracy_score:.1f}%",
2963
+ f"- **MCP Target Achievement**: {'✅ Yes' if self.total_accuracy_score >= 99.5 else '⚠️ No'} (≥99.5% target)",
2964
+ f"- **Validation Timestamp**: {datetime.now().isoformat()}",
2965
+ "",
2966
+ ]
2967
+ )
2968
+
2809
2969
  return "\n".join(markdown_lines)
2810
-
2970
+
2811
2971
  def export_decision_status_legend(self) -> str:
2812
2972
  """Export decision table with status legend."""
2813
2973
  legend_lines = [
@@ -2816,40 +2976,37 @@ class VPCScenarioEngine:
2816
2976
  "| Status | Description | Implementation Method |",
2817
2977
  "|--------|-------------|----------------------|",
2818
2978
  "| DELETE (IaC) | Remove via Infrastructure as Code | Terraform/CloudFormation automated deletion |",
2819
- "| DELETE (manual) | Controlled CLI/Console removal | Manual verification then CLI/Console deletion |",
2979
+ "| DELETE (manual) | Controlled CLI/Console removal | Manual verification then CLI/Console deletion |",
2820
2980
  "| DELETE (auto) | Automated via Runbooks/MCP | Runbooks automated deletion with MCP validation |",
2821
2981
  "| HOLD | Pending owner/traffic analysis | Waiting for owner response or traffic analysis completion |",
2822
2982
  "| INVESTIGATE | Dependency/traffic ambiguity | Requires detailed investigation of dependencies |",
2823
2983
  "",
2824
2984
  "## Decision Distribution",
2825
- ""
2985
+ "",
2826
2986
  ]
2827
-
2987
+
2828
2988
  if self.vpc_candidates:
2829
2989
  decision_counts = defaultdict(int)
2830
2990
  for candidate in self.vpc_candidates:
2831
2991
  decision_counts[candidate.decision] += 1
2832
-
2992
+
2833
2993
  total_vpcs = len(self.vpc_candidates)
2834
-
2835
- legend_lines.extend([
2836
- "| Decision | Count | Percentage |",
2837
- "|----------|-------|------------|"
2838
- ])
2839
-
2994
+
2995
+ legend_lines.extend(["| Decision | Count | Percentage |", "|----------|-------|------------|"])
2996
+
2840
2997
  for decision, count in decision_counts.items():
2841
2998
  percentage = (count / total_vpcs * 100) if total_vpcs > 0 else 0
2842
2999
  legend_lines.append(f"| {decision.value} | {count} | {percentage:.1f}% |")
2843
-
3000
+
2844
3001
  return "\n".join(legend_lines)
2845
-
3002
+
2846
3003
  def export_business_impact_summary(self) -> str:
2847
3004
  """Export enhanced business impact summary with quantified business metrics."""
2848
3005
  if not self.business_impact:
2849
3006
  self.generate_business_impact_summary()
2850
-
3007
+
2851
3008
  impact = self.business_impact
2852
-
3009
+
2853
3010
  summary_lines = [
2854
3011
  "# Enhanced Business Impact Summary - VPC Cleanup Campaign",
2855
3012
  "",
@@ -2879,49 +3036,47 @@ class VPCScenarioEngine:
2879
3036
  f"- **Zero Dependencies Achievement**: {impact.zero_blocking_dependencies_percentage:.1f}% of VPCs have no blocking dependencies",
2880
3037
  "",
2881
3038
  "## 🎯 Timeline Estimation (Parallel Execution Planning)",
2882
- ""
3039
+ "",
2883
3040
  ]
2884
-
3041
+
2885
3042
  # Add parallel execution plan
2886
- parallel_plan = getattr(impact, 'parallel_execution_plan', {})
3043
+ parallel_plan = getattr(impact, "parallel_execution_plan", {})
2887
3044
  for phase, description in parallel_plan.items():
2888
3045
  summary_lines.append(f"- **{phase}**: {description}")
2889
-
2890
- summary_lines.extend([
2891
- "",
2892
- "## 📋 Implementation Phases with Resource Coordination",
2893
- ""
2894
- ])
2895
-
3046
+
3047
+ summary_lines.extend(["", "## 📋 Implementation Phases with Resource Coordination", ""])
3048
+
2896
3049
  for i, phase in enumerate(impact.implementation_phases, 1):
2897
3050
  summary_lines.append(f"{i}. {phase}")
2898
-
2899
- summary_lines.extend([
2900
- "",
2901
- "## ✅ Validation & Quality Metrics",
2902
- "",
2903
- f"- **MCP Validation Achievement**: {impact.mcp_validation_accuracy:.1f}% accuracy {'✅' if impact.mcp_validation_accuracy >= 99.5 else '⚠️'} (≥99.5% enterprise target)",
2904
- f"- **CIS Benchmark Compliance**: {'✅ Achieved' if impact.cis_benchmark_compliance else '⚠️ Pending'} - Default VPC elimination pathway",
2905
- f"- **Enterprise Framework Compliance**: ✅ PDCA methodology with comprehensive audit trails",
2906
- "",
2907
- "## 📈 Executive Summary with Strategic Recommendations",
2908
- "",
2909
- f"The enhanced VPC cleanup campaign identifies **{impact.immediate_deletion_ready} VPCs** ready for immediate deletion (representing **{impact.security_value_percentage:.1f}%** of analyzed infrastructure) with **{format_cost(impact.estimated_annual_savings)}** annual cost savings potential.",
2910
- "",
2911
- f"**Financial Impact**: With **{getattr(impact, 'roi_12_months', 0):.1f}% ROI over 12 months** and **{getattr(impact, 'payback_months', 0):.1f}-month payback period**, the campaign delivers measurable business value while reducing enterprise security risk by **{impact.risk_reduction_score:.1f} points**.",
2912
- "",
2913
- f"**Strategic Approach**: **{impact.mcp_validation_accuracy:.1f}% MCP validation accuracy** ensures enterprise-grade decision making across **5 distinct risk categories** with **parallel execution planning** to minimize business disruption.",
2914
- "",
2915
- f"**Next Steps**: Execute parallel implementation starting with **{impact.immediate_deletion_ready} immediate deletions** (1-day quick wins) while coordinating **{getattr(impact, 'high_risk_vpcs_count', 0)} complex migration scenarios** through enterprise governance approval workflows.",
2916
- ""
2917
- ])
2918
-
3051
+
3052
+ summary_lines.extend(
3053
+ [
3054
+ "",
3055
+ "## ✅ Validation & Quality Metrics",
3056
+ "",
3057
+ f"- **MCP Validation Achievement**: {impact.mcp_validation_accuracy:.1f}% accuracy {'✅' if impact.mcp_validation_accuracy >= 99.5 else '⚠️'} (≥99.5% enterprise target)",
3058
+ f"- **CIS Benchmark Compliance**: {'Achieved' if impact.cis_benchmark_compliance else '⚠️ Pending'} - Default VPC elimination pathway",
3059
+ f"- **Enterprise Framework Compliance**: ✅ PDCA methodology with comprehensive audit trails",
3060
+ "",
3061
+ "## 📈 Executive Summary with Strategic Recommendations",
3062
+ "",
3063
+ f"The enhanced VPC cleanup campaign identifies **{impact.immediate_deletion_ready} VPCs** ready for immediate deletion (representing **{impact.security_value_percentage:.1f}%** of analyzed infrastructure) with **{format_cost(impact.estimated_annual_savings)}** annual cost savings potential.",
3064
+ "",
3065
+ f"**Financial Impact**: With **{getattr(impact, 'roi_12_months', 0):.1f}% ROI over 12 months** and **{getattr(impact, 'payback_months', 0):.1f}-month payback period**, the campaign delivers measurable business value while reducing enterprise security risk by **{impact.risk_reduction_score:.1f} points**.",
3066
+ "",
3067
+ f"**Strategic Approach**: **{impact.mcp_validation_accuracy:.1f}% MCP validation accuracy** ensures enterprise-grade decision making across **5 distinct risk categories** with **parallel execution planning** to minimize business disruption.",
3068
+ "",
3069
+ f"**Next Steps**: Execute parallel implementation starting with **{impact.immediate_deletion_ready} immediate deletions** (1-day quick wins) while coordinating **{getattr(impact, 'high_risk_vpcs_count', 0)} complex migration scenarios** through enterprise governance approval workflows.",
3070
+ "",
3071
+ ]
3072
+ )
3073
+
2919
3074
  return "\n".join(summary_lines)
2920
-
3075
+
2921
3076
  def generate_enhanced_decision_table(self) -> str:
2922
3077
  """
2923
3078
  Generate the comprehensive 5-step decision table as requested in WIP.md.
2924
-
3079
+
2925
3080
  Includes all quantified business metrics:
2926
3081
  - Step 1-5 analysis with specific criteria
2927
3082
  - Cost impact by category
@@ -2931,12 +3086,12 @@ class VPCScenarioEngine:
2931
3086
  """
2932
3087
  if not self.validation_results:
2933
3088
  self.execute_5step_validation_analysis()
2934
-
3089
+
2935
3090
  if not self.business_impact:
2936
3091
  self.generate_business_impact_summary()
2937
-
3092
+
2938
3093
  impact = self.business_impact
2939
-
3094
+
2940
3095
  decision_table_lines = [
2941
3096
  "# Enhanced VPC Cleanup Decision Table & Business Intelligence",
2942
3097
  "",
@@ -2947,110 +3102,114 @@ class VPCScenarioEngine:
2947
3102
  "## 🎯 5-Step Comprehensive Analysis Framework",
2948
3103
  "",
2949
3104
  "| Step | Risk Level | VPC Count | Percentage | Timeline | Monthly Savings | Business Impact |",
2950
- "|------|------------|-----------|------------|----------|----------------|-----------------|"
3105
+ "|------|------------|-----------|------------|----------|----------------|-----------------|",
2951
3106
  ]
2952
-
3107
+
2953
3108
  # Generate table rows with business intelligence
2954
3109
  risk_levels = ["LOW", "MEDIUM-LOW", "MEDIUM", "HIGH", "CRITICAL"]
2955
3110
  step_costs = [
2956
- getattr(impact, 'monthly_cost_savings', 0) * 0.2, # Approximate 20% from immediate
2957
- getattr(impact, 'monthly_cost_savings', 0) * 0.15, # 15% from investigation
2958
- getattr(impact, 'monthly_cost_savings', 0) * 0.25, # 25% from governance
2959
- getattr(impact, 'monthly_cost_savings', 0) * 0.25, # 25% from complex
2960
- getattr(impact, 'monthly_cost_savings', 0) * 0.15 # 15% from strategic
3111
+ getattr(impact, "monthly_cost_savings", 0) * 0.2, # Approximate 20% from immediate
3112
+ getattr(impact, "monthly_cost_savings", 0) * 0.15, # 15% from investigation
3113
+ getattr(impact, "monthly_cost_savings", 0) * 0.25, # 25% from governance
3114
+ getattr(impact, "monthly_cost_savings", 0) * 0.25, # 25% from complex
3115
+ getattr(impact, "monthly_cost_savings", 0) * 0.15, # 15% from strategic
2961
3116
  ]
2962
-
3117
+
2963
3118
  business_impacts = [
2964
3119
  "Quick wins - immediate deletion",
2965
3120
  "Short-term validation required",
2966
- "Governance approval needed",
3121
+ "Governance approval needed",
2967
3122
  "Complex migration planning",
2968
- "Strategic architectural review"
3123
+ "Strategic architectural review",
2969
3124
  ]
2970
-
3125
+
2971
3126
  for i, (step, result) in enumerate(self.validation_results.items()):
2972
3127
  step_name = step.value.split(":")[0]
2973
3128
  decision_table_lines.append(
2974
3129
  f"| {step_name} | {risk_levels[i]} | {result.vpc_count} | {result.percentage:.1f}% | {result.timeline_estimate} | {format_cost(step_costs[i])} | {business_impacts[i]} |"
2975
3130
  )
2976
-
2977
- decision_table_lines.extend([
2978
- "",
2979
- "## 💰 Quantified Business Metrics Summary",
2980
- "",
2981
- f"- **Total Monthly Cost Savings**: {format_cost(getattr(impact, 'monthly_cost_savings', impact.estimated_annual_savings / 12))}",
2982
- f"- **Total Annual Cost Savings**: {format_cost(impact.estimated_annual_savings)}",
2983
- f"- **Implementation Cost**: {format_cost(getattr(impact, 'cleanup_cost_estimate', 0))}",
2984
- f"- **ROI (12-month)**: {getattr(impact, 'roi_12_months', 0):.1f}%",
2985
- f"- **Payback Period**: {getattr(impact, 'payback_months', 0):.1f} months",
2986
- f"- **Labor Hours Required**: {getattr(impact, 'total_cleanup_hours', 0):.1f} hours",
2987
- "",
2988
- "## 🎯 Risk Assessment Matrix",
2989
- "",
2990
- f"- **Average Risk Score**: {getattr(impact, 'average_risk_score', 0):.1f}/10.0",
2991
- f"- **High-Risk VPCs**: {getattr(impact, 'high_risk_vpcs_count', 0)} VPCs (Steps 4-5)",
2992
- f"- **Low-Risk Quick Wins**: {self.validation_results[ValidationStep.IMMEDIATE_DELETION].vpc_count} VPCs (Step 1)",
2993
- f"- **Risk Reduction Score**: {impact.risk_reduction_score:.1f}/100",
2994
- "",
2995
- "## ⏱️ Parallel Execution Timeline",
2996
- ""
2997
- ])
2998
-
3131
+
3132
+ decision_table_lines.extend(
3133
+ [
3134
+ "",
3135
+ "## 💰 Quantified Business Metrics Summary",
3136
+ "",
3137
+ f"- **Total Monthly Cost Savings**: {format_cost(getattr(impact, 'monthly_cost_savings', impact.estimated_annual_savings / 12))}",
3138
+ f"- **Total Annual Cost Savings**: {format_cost(impact.estimated_annual_savings)}",
3139
+ f"- **Implementation Cost**: {format_cost(getattr(impact, 'cleanup_cost_estimate', 0))}",
3140
+ f"- **ROI (12-month)**: {getattr(impact, 'roi_12_months', 0):.1f}%",
3141
+ f"- **Payback Period**: {getattr(impact, 'payback_months', 0):.1f} months",
3142
+ f"- **Labor Hours Required**: {getattr(impact, 'total_cleanup_hours', 0):.1f} hours",
3143
+ "",
3144
+ "## 🎯 Risk Assessment Matrix",
3145
+ "",
3146
+ f"- **Average Risk Score**: {getattr(impact, 'average_risk_score', 0):.1f}/10.0",
3147
+ f"- **High-Risk VPCs**: {getattr(impact, 'high_risk_vpcs_count', 0)} VPCs (Steps 4-5)",
3148
+ f"- **Low-Risk Quick Wins**: {self.validation_results[ValidationStep.IMMEDIATE_DELETION].vpc_count} VPCs (Step 1)",
3149
+ f"- **Risk Reduction Score**: {impact.risk_reduction_score:.1f}/100",
3150
+ "",
3151
+ "## ⏱️ Parallel Execution Timeline",
3152
+ "",
3153
+ ]
3154
+ )
3155
+
2999
3156
  # Add parallel execution plan
3000
- parallel_plan = getattr(impact, 'parallel_execution_plan', {})
3157
+ parallel_plan = getattr(impact, "parallel_execution_plan", {})
3001
3158
  for phase, description in parallel_plan.items():
3002
3159
  decision_table_lines.append(f"- **{phase}**: {description}")
3003
-
3004
- decision_table_lines.extend([
3005
- "",
3006
- "## 📊 Step-by-Step Breakdown",
3007
- "",
3008
- "### Step 1: Immediate Deletion Candidates",
3009
- f"- **Criteria**: 0 ENI, no load balancers, no TGW, non-default VPCs",
3010
- f"- **VPCs Identified**: {self.validation_results[ValidationStep.IMMEDIATE_DELETION].vpc_count}",
3011
- f"- **Risk Level**: LOW - No active resources or dependencies",
3012
- f"- **Timeline**: 1 day execution",
3013
- f"- **Business Value**: Quick wins with immediate cost reduction",
3014
- "",
3015
- "### Step 2: Investigation Required",
3016
- f"- **Criteria**: 2 ENI, minimal infrastructure, no complex dependencies",
3017
- f"- **VPCs Identified**: {self.validation_results[ValidationStep.INVESTIGATION_REQUIRED].vpc_count}",
3018
- f"- **Risk Level**: MEDIUM-LOW - Limited infrastructure validation needed",
3019
- f"- **Timeline**: 7 days traffic analysis",
3020
- f"- **Business Value**: Short-term validation with low effort",
3021
- "",
3022
- "### Step 3: Governance Approval",
3023
- f"- **Criteria**: Default VPCs, no flow logs enabled, IaC managed resources",
3024
- f"- **VPCs Identified**: {self.validation_results[ValidationStep.GOVERNANCE_APPROVAL].vpc_count}",
3025
- f"- **Risk Level**: MEDIUM - Governance approval and compliance required",
3026
- f"- **Timeline**: 21 days approval workflow",
3027
- f"- **Business Value**: Compliance improvement with governance value",
3028
- "",
3029
- "### Step 4: Complex Migration",
3030
- f"- **Criteria**: Load balancers, TGW attached, >5 ENI dependencies",
3031
- f"- **VPCs Identified**: {self.validation_results[ValidationStep.COMPLEX_MIGRATION].vpc_count}",
3032
- f"- **Risk Level**: HIGH - Complex infrastructure migration required",
3033
- f"- **Timeline**: 90 days comprehensive planning",
3034
- f"- **Business Value**: Strategic infrastructure optimization",
3035
- "",
3036
- "### Step 5: Strategic Review",
3037
- f"- **Criteria**: CIDR overlap, critical architecture, complex enterprise dependencies",
3038
- f"- **VPCs Identified**: {self.validation_results[ValidationStep.STRATEGIC_REVIEW].vpc_count}",
3039
- f"- **Risk Level**: CRITICAL - Enterprise architectural decisions required",
3040
- f"- **Timeline**: 180 days strategic planning",
3041
- f"- **Business Value**: Long-term architecture consolidation",
3042
- "",
3043
- "## 🏆 Business Impact Summary",
3044
- "",
3045
- f"**Immediate Value**: {self.validation_results[ValidationStep.IMMEDIATE_DELETION].vpc_count} VPCs ({self.validation_results[ValidationStep.IMMEDIATE_DELETION].percentage:.1f}%) ready for 1-day deletion with **{format_cost(step_costs[0])}** monthly savings.",
3046
- "",
3047
- f"**Strategic Value**: Complete 5-step framework delivers **{format_cost(impact.estimated_annual_savings)}** annual savings with **{getattr(impact, 'roi_12_months', 0):.1f}% ROI** and **{getattr(impact, 'payback_months', 0):.1f}-month payback** period.",
3048
- "",
3049
- f"**Enterprise Compliance**: **{impact.mcp_validation_accuracy:.1f}% MCP validation** accuracy ensures enterprise-grade decision making with comprehensive audit trails and PDCA methodology compliance."
3050
- ])
3051
-
3160
+
3161
+ decision_table_lines.extend(
3162
+ [
3163
+ "",
3164
+ "## 📊 Step-by-Step Breakdown",
3165
+ "",
3166
+ "### Step 1: Immediate Deletion Candidates",
3167
+ f"- **Criteria**: 0 ENI, no load balancers, no TGW, non-default VPCs",
3168
+ f"- **VPCs Identified**: {self.validation_results[ValidationStep.IMMEDIATE_DELETION].vpc_count}",
3169
+ f"- **Risk Level**: LOW - No active resources or dependencies",
3170
+ f"- **Timeline**: 1 day execution",
3171
+ f"- **Business Value**: Quick wins with immediate cost reduction",
3172
+ "",
3173
+ "### Step 2: Investigation Required",
3174
+ f"- **Criteria**: ≤2 ENI, minimal infrastructure, no complex dependencies",
3175
+ f"- **VPCs Identified**: {self.validation_results[ValidationStep.INVESTIGATION_REQUIRED].vpc_count}",
3176
+ f"- **Risk Level**: MEDIUM-LOW - Limited infrastructure validation needed",
3177
+ f"- **Timeline**: 7 days traffic analysis",
3178
+ f"- **Business Value**: Short-term validation with low effort",
3179
+ "",
3180
+ "### Step 3: Governance Approval",
3181
+ f"- **Criteria**: Default VPCs, no flow logs enabled, IaC managed resources",
3182
+ f"- **VPCs Identified**: {self.validation_results[ValidationStep.GOVERNANCE_APPROVAL].vpc_count}",
3183
+ f"- **Risk Level**: MEDIUM - Governance approval and compliance required",
3184
+ f"- **Timeline**: 21 days approval workflow",
3185
+ f"- **Business Value**: Compliance improvement with governance value",
3186
+ "",
3187
+ "### Step 4: Complex Migration",
3188
+ f"- **Criteria**: Load balancers, TGW attached, >5 ENI dependencies",
3189
+ f"- **VPCs Identified**: {self.validation_results[ValidationStep.COMPLEX_MIGRATION].vpc_count}",
3190
+ f"- **Risk Level**: HIGH - Complex infrastructure migration required",
3191
+ f"- **Timeline**: 90 days comprehensive planning",
3192
+ f"- **Business Value**: Strategic infrastructure optimization",
3193
+ "",
3194
+ "### Step 5: Strategic Review",
3195
+ f"- **Criteria**: CIDR overlap, critical architecture, complex enterprise dependencies",
3196
+ f"- **VPCs Identified**: {self.validation_results[ValidationStep.STRATEGIC_REVIEW].vpc_count}",
3197
+ f"- **Risk Level**: CRITICAL - Enterprise architectural decisions required",
3198
+ f"- **Timeline**: 180 days strategic planning",
3199
+ f"- **Business Value**: Long-term architecture consolidation",
3200
+ "",
3201
+ "## 🏆 Business Impact Summary",
3202
+ "",
3203
+ f"**Immediate Value**: {self.validation_results[ValidationStep.IMMEDIATE_DELETION].vpc_count} VPCs ({self.validation_results[ValidationStep.IMMEDIATE_DELETION].percentage:.1f}%) ready for 1-day deletion with **{format_cost(step_costs[0])}** monthly savings.",
3204
+ "",
3205
+ f"**Strategic Value**: Complete 5-step framework delivers **{format_cost(impact.estimated_annual_savings)}** annual savings with **{getattr(impact, 'roi_12_months', 0):.1f}% ROI** and **{getattr(impact, 'payback_months', 0):.1f}-month payback** period.",
3206
+ "",
3207
+ f"**Enterprise Compliance**: **{impact.mcp_validation_accuracy:.1f}% MCP validation** accuracy ensures enterprise-grade decision making with comprehensive audit trails and PDCA methodology compliance.",
3208
+ ]
3209
+ )
3210
+
3052
3211
  return "\n".join(decision_table_lines)
3053
-
3212
+
3054
3213
  def export_comprehensive_json(self) -> str:
3055
3214
  """Export all scenario data as comprehensive JSON."""
3056
3215
  export_data = {
@@ -3059,7 +3218,7 @@ class VPCScenarioEngine:
3059
3218
  "profile": self.profile,
3060
3219
  "vpc_candidates_count": len(self.vpc_candidates),
3061
3220
  "mcp_validation_accuracy": self.total_accuracy_score,
3062
- "framework_version": "latest version"
3221
+ "framework_version": "latest version",
3063
3222
  },
3064
3223
  "vpc_candidates": [
3065
3224
  {
@@ -3084,9 +3243,10 @@ class VPCScenarioEngine:
3084
3243
  "validated": c.mcp_validated,
3085
3244
  "accuracy": c.mcp_accuracy,
3086
3245
  "last_validated": c.last_validated.isoformat() if c.last_validated else None,
3087
- "validation_source": c.validation_source
3088
- }
3089
- } for c in self.vpc_candidates
3246
+ "validation_source": c.validation_source,
3247
+ },
3248
+ }
3249
+ for c in self.vpc_candidates
3090
3250
  ],
3091
3251
  "validation_results": {
3092
3252
  step.value: {
@@ -3096,9 +3256,12 @@ class VPCScenarioEngine:
3096
3256
  "recommendations": result.recommendations,
3097
3257
  "risk_assessment": result.risk_assessment,
3098
3258
  "timeline_estimate": result.timeline_estimate,
3099
- "vpc_ids": [vpc.vpc_id for vpc in result.vpc_candidates]
3100
- } for step, result in self.validation_results.items()
3101
- } if self.validation_results else {},
3259
+ "vpc_ids": [vpc.vpc_id for vpc in result.vpc_candidates],
3260
+ }
3261
+ for step, result in self.validation_results.items()
3262
+ }
3263
+ if self.validation_results
3264
+ else {},
3102
3265
  "business_impact": {
3103
3266
  "security_value_percentage": self.business_impact.security_value_percentage,
3104
3267
  "immediate_deletion_ready": self.business_impact.immediate_deletion_ready,
@@ -3109,16 +3272,18 @@ class VPCScenarioEngine:
3109
3272
  "mcp_validation_accuracy": self.business_impact.mcp_validation_accuracy,
3110
3273
  "implementation_phases": self.business_impact.implementation_phases,
3111
3274
  "estimated_annual_savings": self.business_impact.estimated_annual_savings,
3112
- "risk_reduction_score": self.business_impact.risk_reduction_score
3113
- } if self.business_impact else {}
3275
+ "risk_reduction_score": self.business_impact.risk_reduction_score,
3276
+ }
3277
+ if self.business_impact
3278
+ else {},
3114
3279
  }
3115
-
3280
+
3116
3281
  return json.dumps(export_data, indent=2, default=str)
3117
-
3282
+
3118
3283
  def display_interactive_summary(self) -> None:
3119
3284
  """Display rich interactive summary for CLI and notebook usage."""
3120
3285
  print_header("VPC Cleanup Scenarios - Unified Framework", "Enterprise Campaign")
3121
-
3286
+
3122
3287
  # Create summary panel
3123
3288
  if self.business_impact:
3124
3289
  summary_text = f"""
@@ -3129,47 +3294,49 @@ class VPCScenarioEngine:
3129
3294
  • Estimated Annual Savings: {format_cost(self.business_impact.estimated_annual_savings)}
3130
3295
 
3131
3296
  [bold blue]Validation Quality[/bold blue]
3132
- • MCP Validation Accuracy: {self.business_impact.mcp_validation_accuracy:.1f}% {'' if self.business_impact.mcp_validation_accuracy >= 99.5 else '⚠️'}
3297
+ • MCP Validation Accuracy: {self.business_impact.mcp_validation_accuracy:.1f}% {"" if self.business_impact.mcp_validation_accuracy >= 99.5 else "⚠️"}
3133
3298
  • Zero Dependencies: {self.business_impact.zero_blocking_dependencies_percentage:.1f}%
3134
3299
  • Risk Reduction Score: {self.business_impact.risk_reduction_score:.1f}/100
3135
3300
  """
3136
-
3137
- summary_panel = Panel(
3138
- summary_text.strip(),
3139
- title="🎯 VPC Cleanup Campaign Summary",
3140
- border_style="cyan"
3141
- )
3301
+
3302
+ summary_panel = Panel(summary_text.strip(), title="🎯 VPC Cleanup Campaign Summary", border_style="cyan")
3142
3303
  self.console.print(summary_panel)
3143
-
3304
+
3144
3305
  # Display validation results table if available
3145
3306
  if self.validation_results:
3146
3307
  results_table = create_table(
3147
- title="5-Step Validation Analysis Results",
3148
- caption="Enterprise comprehensive validation framework"
3308
+ title="5-Step Validation Analysis Results", caption="Enterprise comprehensive validation framework"
3149
3309
  )
3150
3310
  results_table.add_column("Validation Step", style="cyan", no_wrap=True)
3151
3311
  results_table.add_column("VPC Count", justify="right", style="yellow")
3152
3312
  results_table.add_column("Percentage", justify="right", style="green")
3153
3313
  results_table.add_column("Risk Level", style="red")
3154
3314
  results_table.add_column("Timeline", style="blue")
3155
-
3315
+
3156
3316
  for step, result in self.validation_results.items():
3157
3317
  # Extract risk level from risk assessment
3158
- risk_level = "Low" if "Low risk" in result.risk_assessment else \
3159
- "Medium" if "Medium risk" in result.risk_assessment else \
3160
- "High" if "High risk" in result.risk_assessment else \
3161
- "Critical" if "Very high risk" in result.risk_assessment else "Strategic"
3162
-
3318
+ risk_level = (
3319
+ "Low"
3320
+ if "Low risk" in result.risk_assessment
3321
+ else "Medium"
3322
+ if "Medium risk" in result.risk_assessment
3323
+ else "High"
3324
+ if "High risk" in result.risk_assessment
3325
+ else "Critical"
3326
+ if "Very high risk" in result.risk_assessment
3327
+ else "Strategic"
3328
+ )
3329
+
3163
3330
  results_table.add_row(
3164
3331
  step.value.split(":")[1].strip(),
3165
3332
  str(result.vpc_count),
3166
3333
  f"{result.percentage:.1f}%",
3167
3334
  risk_level,
3168
- result.timeline_estimate
3335
+ result.timeline_estimate,
3169
3336
  )
3170
-
3337
+
3171
3338
  self.console.print(results_table)
3172
-
3339
+
3173
3340
  # Display export options
3174
3341
  export_panel = Panel(
3175
3342
  """
@@ -3185,7 +3352,7 @@ class VPCScenarioEngine:
3185
3352
  [bold]Documentation:[/bold] Ready for vpc-cleanup.md
3186
3353
  """.strip(),
3187
3354
  title="📄 Multi-Format Export Options",
3188
- border_style="green"
3355
+ border_style="green",
3189
3356
  )
3190
3357
  self.console.print(export_panel)
3191
3358
 
@@ -3193,67 +3360,73 @@ class VPCScenarioEngine:
3193
3360
  # Example usage and testing functions
3194
3361
  async def demo_vpc_scenario_engine():
3195
3362
  """Demonstrate enhanced VPC scenario engine functionality with Phase 4 business intelligence."""
3196
- print_header("VPC Scenario Engine Demo - Phase 4 Enhanced Business Intelligence", "Enterprise Framework latest version")
3197
-
3363
+ print_header(
3364
+ "VPC Scenario Engine Demo - Phase 4 Enhanced Business Intelligence", "Enterprise Framework latest version"
3365
+ )
3366
+
3198
3367
  # Initialize engine with default profile
3199
3368
  engine = VPCScenarioEngine("default")
3200
-
3369
+
3201
3370
  # Discover VPC candidates
3202
3371
  candidates = engine.discover_vpc_candidates()
3203
3372
  print_info(f"Discovered {len(candidates)} VPC candidates for Phase 4 analysis")
3204
-
3373
+
3205
3374
  # Execute MCP validation
3206
3375
  validation_summary = await engine.validate_candidates_with_mcp()
3207
3376
  print_success(f"MCP Validation completed: {validation_summary['average_accuracy']:.1f}% accuracy (≥99.5% target)")
3208
-
3377
+
3209
3378
  # Execute enhanced 5-step analysis (Phase 4 implementation)
3210
3379
  print_header("Phase 4: Enhanced 5-Step Business Intelligence Framework", "latest version")
3211
3380
  validation_results = engine.execute_5step_validation_analysis()
3212
-
3381
+
3213
3382
  # Generate enhanced business impact with quantified metrics
3214
3383
  business_impact = engine.generate_business_impact_summary()
3215
- print_success(f"Business Impact Analysis: {format_cost(business_impact.estimated_annual_savings)} annual savings potential")
3216
-
3384
+ print_success(
3385
+ f"Business Impact Analysis: {format_cost(business_impact.estimated_annual_savings)} annual savings potential"
3386
+ )
3387
+
3217
3388
  # NEW: Generate enhanced decision table (Phase 4 feature)
3218
3389
  print_header("Phase 4: Enhanced Decision Table & Business Intelligence", "WIP.md Implementation")
3219
3390
  enhanced_decision_table = engine.generate_enhanced_decision_table()
3220
-
3391
+
3221
3392
  # Save enhanced decision table to file for review
3222
3393
  decision_table_path = "/tmp/vpc_enhanced_decision_table.md"
3223
3394
  with open(decision_table_path, "w") as f:
3224
3395
  f.write(enhanced_decision_table)
3225
3396
  print_success(f"Enhanced decision table saved: {decision_table_path}")
3226
-
3397
+
3227
3398
  # Display business intelligence summary
3228
3399
  print_header("Quantified Business Metrics Summary", "Phase 4 Achievement")
3229
-
3400
+
3230
3401
  # Create enhanced business metrics table
3231
3402
  metrics_table = Table(title="Phase 4: Enhanced Business Intelligence Metrics")
3232
3403
  metrics_table.add_column("Metric Category", style="cyan", no_wrap=True)
3233
3404
  metrics_table.add_column("Value", style="green", justify="right")
3234
3405
  metrics_table.add_column("Impact", style="yellow")
3235
-
3406
+
3236
3407
  # Add quantified metrics rows
3237
- monthly_savings = getattr(business_impact, 'monthly_cost_savings', business_impact.estimated_annual_savings / 12)
3238
- roi_12_months = getattr(business_impact, 'roi_12_months', 0)
3239
- payback_months = getattr(business_impact, 'payback_months', 0)
3240
- total_hours = getattr(business_impact, 'total_cleanup_hours', 0)
3241
-
3408
+ monthly_savings = getattr(business_impact, "monthly_cost_savings", business_impact.estimated_annual_savings / 12)
3409
+ roi_12_months = getattr(business_impact, "roi_12_months", 0)
3410
+ payback_months = getattr(business_impact, "payback_months", 0)
3411
+ total_hours = getattr(business_impact, "total_cleanup_hours", 0)
3412
+
3242
3413
  metrics_table.add_row("Monthly Cost Savings", format_cost(monthly_savings), "Immediate financial impact")
3243
- metrics_table.add_row("Annual Cost Savings", format_cost(business_impact.estimated_annual_savings), "12-month projection")
3414
+ metrics_table.add_row(
3415
+ "Annual Cost Savings", format_cost(business_impact.estimated_annual_savings), "12-month projection"
3416
+ )
3244
3417
  metrics_table.add_row("ROI (12-month)", f"{roi_12_months:.1f}%", "Return on investment")
3245
3418
  metrics_table.add_row("Payback Period", f"{payback_months:.1f} months", "Break-even timeline")
3246
3419
  metrics_table.add_row("Labor Hours Required", f"{total_hours:.1f} hours", "Implementation effort")
3247
3420
  metrics_table.add_row("Risk Reduction", f"{business_impact.risk_reduction_score:.1f}/100", "Security improvement")
3248
-
3421
+
3249
3422
  console.print(metrics_table)
3250
-
3423
+
3251
3424
  # Display interactive summary with enhanced features
3252
3425
  engine.display_interactive_summary()
3253
-
3426
+
3254
3427
  print_success("Phase 4: Enhanced decision table & business intelligence implementation complete!")
3255
3428
  print_info(f"Review comprehensive analysis: {decision_table_path}")
3256
-
3429
+
3257
3430
  return engine
3258
3431
 
3259
3432
 
@@ -3261,9 +3434,9 @@ if __name__ == "__main__":
3261
3434
  """Example CLI usage of VPC scenario engine."""
3262
3435
  import asyncio
3263
3436
  import sys
3264
-
3437
+
3265
3438
  if len(sys.argv) > 1 and sys.argv[1] == "demo":
3266
3439
  asyncio.run(demo_vpc_scenario_engine())
3267
3440
  else:
3268
3441
  print("VPC Unified Scenario Framework Engine - Enterprise Cross-Deliverable Support")
3269
- print("Usage: python unified_scenarios.py demo")
3442
+ print("Usage: python unified_scenarios.py demo")