runbooks 0.9.5__py3-none-any.whl → 0.9.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/_platform/__init__.py +19 -0
  3. runbooks/_platform/core/runbooks_wrapper.py +478 -0
  4. runbooks/cloudops/cost_optimizer.py +330 -0
  5. runbooks/cloudops/interfaces.py +3 -3
  6. runbooks/finops/README.md +1 -1
  7. runbooks/finops/automation_core.py +643 -0
  8. runbooks/finops/business_cases.py +414 -16
  9. runbooks/finops/cli.py +23 -0
  10. runbooks/finops/compute_cost_optimizer.py +865 -0
  11. runbooks/finops/ebs_cost_optimizer.py +718 -0
  12. runbooks/finops/ebs_optimizer.py +909 -0
  13. runbooks/finops/elastic_ip_optimizer.py +675 -0
  14. runbooks/finops/embedded_mcp_validator.py +330 -14
  15. runbooks/finops/enterprise_wrappers.py +827 -0
  16. runbooks/finops/legacy_migration.py +730 -0
  17. runbooks/finops/nat_gateway_optimizer.py +1160 -0
  18. runbooks/finops/network_cost_optimizer.py +1387 -0
  19. runbooks/finops/notebook_utils.py +596 -0
  20. runbooks/finops/reservation_optimizer.py +956 -0
  21. runbooks/finops/validation_framework.py +753 -0
  22. runbooks/finops/workspaces_analyzer.py +593 -0
  23. runbooks/inventory/__init__.py +7 -0
  24. runbooks/inventory/collectors/aws_networking.py +357 -6
  25. runbooks/inventory/mcp_vpc_validator.py +1091 -0
  26. runbooks/inventory/vpc_analyzer.py +1107 -0
  27. runbooks/inventory/vpc_architecture_validator.py +939 -0
  28. runbooks/inventory/vpc_dependency_analyzer.py +845 -0
  29. runbooks/main.py +425 -39
  30. runbooks/operate/vpc_operations.py +1479 -16
  31. runbooks/remediation/commvault_ec2_analysis.py +5 -4
  32. runbooks/remediation/dynamodb_optimize.py +2 -2
  33. runbooks/remediation/rds_instance_list.py +1 -1
  34. runbooks/remediation/rds_snapshot_list.py +5 -4
  35. runbooks/remediation/workspaces_list.py +2 -2
  36. runbooks/security/compliance_automation.py +2 -2
  37. runbooks/vpc/tests/test_config.py +2 -2
  38. {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/METADATA +1 -1
  39. {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/RECORD +43 -24
  40. {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/WHEEL +0 -0
  41. {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/entry_points.txt +0 -0
  42. {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/licenses/LICENSE +0 -0
  43. {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,66 @@
1
1
  """
2
- VPC Operations Module - GitHub Issue #96 TOP PRIORITY
2
+ AWSO-5 Enhanced VPC Operations Module - Enterprise VPC Cleanup Framework
3
+
4
+ Strategic Migration: VPC operations enhanced with discovery capabilities from migrated vpc module
5
+ following FAANG SDLC "Do one thing and do it well" principle with enterprise safety validation.
6
+
7
+ **VPC Module Migration Integration**:
8
+ - Discovery logic migrated to inventory/vpc_analyzer.py for "Do one thing and do it well"
9
+ - Operations logic enhanced with vpc module capabilities (networking_wrapper.py patterns)
10
+ - Manager interface integration (manager_interface.py business logic)
11
+ - Network cost engine integration (cost_engine.py patterns)
12
+ - Rich formatting integration (rich_formatters.py standards)
13
+
14
+ **AWSO-5 Integration**: Complete 12-step VPC cleanup framework with:
15
+ - ENI gate validation (critical blocking check)
16
+ - Comprehensive dependency cleanup (NAT, IGW, RT, Endpoints, TGW, Peering)
17
+ - Evidence bundle generation with SHA256 verification
18
+ - Default VPC elimination for CIS Benchmark compliance
19
+ - Security posture enhancement across 60+1 AWS Landing Zone
3
20
 
4
21
  Enterprise-grade VPC and NAT Gateway operations for multi-account AWS environments.
5
22
  Addresses manager-raised VPC infrastructure automation requirements with cost optimization focus.
6
23
 
7
- This module provides comprehensive VPC lifecycle management including:
8
- - NAT Gateway operations ($45/month cost optimization)
9
- - VPC creation and deletion with best practices
24
+ **AWSO-5 CAPABILITIES** (Critical security-focused cleanup):
25
+ - 12-step dependency analysis and cleanup framework
26
+ - Default VPC elimination (8 identified VPCs for security compliance)
27
+ - ENI gate validation preventing accidental workload disruption
28
+ - Comprehensive evidence collection with audit trails
29
+ - IaC detection and integration for managed infrastructure
30
+ - Enterprise approval workflows with platform lead oversight
31
+
32
+ **ENHANCED CAPABILITIES** (integrated from vpc module):
33
+ - VPC creation/deletion with enterprise best practices
34
+ - Advanced NAT Gateway operations with cost analysis ($45/month optimization)
35
+ - VPC endpoint management and optimization
36
+ - Transit Gateway attachment operations
10
37
  - VPC peering and cross-account connectivity
11
- - Network security optimization
12
- - Cost analysis and recommendations
38
+ - Network security optimization and attack surface reduction
39
+ - Business-friendly manager interface for non-technical users
40
+
41
+ This module provides comprehensive VPC lifecycle management including:
42
+ - AWSO-5 VPC cleanup with 12-step dependency resolution
43
+ - NAT Gateway operations with cost optimization focus
44
+ - VPC infrastructure management with enterprise best practices
45
+ - Cross-account connectivity and network security
46
+ - Manager dashboard interface for business users
47
+ - Cost analysis and recommendations with enterprise MCP validation
48
+
49
+ **Security Focus Features**:
50
+ - Default VPC identification and elimination
51
+ - Attack surface reduction through systematic cleanup
52
+ - CIS Benchmark compliance enhancement
53
+ - Evidence-based validation with ≥99.5% MCP accuracy
13
54
 
14
55
  Features:
15
- - Multi-account support (1-200+ accounts)
56
+ - Multi-account support (1-200+ accounts) across validated Landing Zone
16
57
  - Rich CLI integration with beautiful terminal output
17
- - Enterprise safety (dry-run, confirmation, rollback)
18
- - Cost optimization integration
19
- - Comprehensive error handling and logging
58
+ - Enterprise safety (dry-run, confirmation, rollback, approval workflows)
59
+ - AWSO-5 framework integration with comprehensive dependency analysis
60
+ - Cost optimization integration with existing finops patterns
61
+ - Manager dashboard interface for executive decision making
62
+ - Comprehensive error handling and logging with audit trails
63
+ - SHA256-verified evidence bundle generation for compliance
20
64
  """
21
65
 
22
66
  import time
@@ -28,9 +72,52 @@ import boto3
28
72
  from botocore.exceptions import ClientError
29
73
  from loguru import logger
30
74
 
31
- from runbooks.common.rich_utils import RichConsole
75
+ from runbooks.common.rich_utils import (
76
+ console, create_table, print_warning, print_success, print_error,
77
+ print_info, print_header, create_panel
78
+ )
32
79
  from runbooks.operate.base import BaseOperation, OperationContext, OperationResult, OperationStatus
33
80
 
81
+ # VPC Module Migration Integration - Discovery capabilities
82
+ from runbooks.inventory.vpc_analyzer import VPCAnalyzer, VPCDiscoveryResult, AWSOAnalysis
83
+
84
+
85
+ class RichConsoleWrapper:
86
+ """Wrapper to provide missing methods for VPC operations."""
87
+
88
+ def __init__(self, console_instance):
89
+ self.console = console_instance
90
+
91
+ def print(self, *args, **kwargs):
92
+ return self.console.print(*args, **kwargs)
93
+
94
+ def print_panel(self, content, subtitle=None, title="Panel"):
95
+ """Print a panel with content."""
96
+ panel_content = content
97
+ if subtitle:
98
+ panel_content = f"{content}\n\n{subtitle}"
99
+ panel = create_panel(panel_content, title=title)
100
+ self.console.print(panel)
101
+
102
+ def print_table(self, table):
103
+ """Print a table."""
104
+ self.console.print(table)
105
+
106
+ def print_success(self, message):
107
+ return print_success(message)
108
+
109
+ def print_error(self, message):
110
+ return print_error(message)
111
+
112
+ def print_info(self, message):
113
+ return print_info(message)
114
+
115
+ def print_warning(self, message):
116
+ return print_warning(message)
117
+
118
+ def print_header(self, title, subtitle=None):
119
+ return print_header(title, subtitle)
120
+
34
121
 
35
122
  @dataclass
36
123
  class VPCConfiguration:
@@ -151,7 +238,7 @@ class VPCOperations(BaseOperation):
151
238
 
152
239
  def __init__(self, profile: Optional[str] = None, region: Optional[str] = None, dry_run: bool = False):
153
240
  """
154
- Initialize VPC Operations with Enterprise safety features.
241
+ Initialize VPC Operations with Enterprise safety features and VPC module migration integration.
155
242
 
156
243
  Args:
157
244
  profile: AWS profile for authentication
@@ -159,15 +246,27 @@ class VPCOperations(BaseOperation):
159
246
  dry_run: Enable dry-run mode for safe testing
160
247
  """
161
248
  super().__init__(profile, region, dry_run)
162
- self.rich_console = RichConsole()
249
+ self.rich_console = RichConsoleWrapper(console)
250
+
251
+ # VPC Module Migration Integration - Discovery capabilities
252
+ self.vpc_analyzer = VPCAnalyzer(
253
+ profile=profile,
254
+ region=region,
255
+ console=console,
256
+ dry_run=dry_run
257
+ )
163
258
 
164
259
  # Cost tracking for NAT Gateways ($45/month awareness)
165
260
  self.nat_gateway_monthly_cost = 45.0
166
261
 
167
262
  # Cost tracking for Elastic IPs ($3.60/month awareness)
168
263
  self.elastic_ip_monthly_cost = 3.60
264
+
265
+ # VPC module patterns integration
266
+ self.last_discovery_result = None
267
+ self.last_awso_analysis = None
169
268
 
170
- logger.info(f"VPC Operations initialized - Profile: {profile}, Region: {region}, Dry-run: {dry_run}")
269
+ logger.info(f"VPC Operations initialized with VPC Analyzer - Profile: {profile}, Region: {region}, Dry-run: {dry_run}")
171
270
 
172
271
  def execute_operation(self, context: OperationContext, operation_type: str, **kwargs) -> List[OperationResult]:
173
272
  """
@@ -239,12 +338,11 @@ class VPCOperations(BaseOperation):
239
338
 
240
339
  # Display cost and configuration info
241
340
  self.rich_console.print_panel(
242
- f"Creating VPC: {vpc_config.name}",
243
341
  f"CIDR Block: {vpc_config.cidr_block}\n"
244
342
  f"Region: {context.region}\n"
245
343
  f"DNS Hostnames: {vpc_config.enable_dns_hostnames}\n"
246
344
  f"Instance Tenancy: {vpc_config.instance_tenancy}",
247
- title="🏗️ VPC Creation",
345
+ title="🏗️ VPC Creation"
248
346
  )
249
347
 
250
348
  if context.dry_run:
@@ -724,6 +822,228 @@ class VPCOperations(BaseOperation):
724
822
 
725
823
  return [result]
726
824
 
825
+ # VPC Module Migration Integration Methods
826
+ def discover_vpc_topology_comprehensive(self, vpc_ids: Optional[List[str]] = None) -> VPCDiscoveryResult:
827
+ """
828
+ Comprehensive VPC topology discovery using migrated VPC module capabilities.
829
+
830
+ Integrates networking_wrapper.py discovery patterns with operate module operations.
831
+ Provides complete VPC topology analysis for AWSO-05 cleanup workflows.
832
+
833
+ Args:
834
+ vpc_ids: Optional list of specific VPC IDs to analyze
835
+
836
+ Returns:
837
+ VPCDiscoveryResult with complete topology information
838
+ """
839
+ self.rich_console.print_header("VPC Topology Discovery", "Enhanced with VPC Module Integration")
840
+
841
+ try:
842
+ # Use integrated VPC analyzer for discovery
843
+ discovery_result = self.vpc_analyzer.discover_vpc_topology(vpc_ids)
844
+ self.last_discovery_result = discovery_result
845
+
846
+ # Display enterprise summary with cost information
847
+ total_monthly_cost = sum([
848
+ nat['EstimatedMonthlyCost'] for nat in discovery_result.nat_gateways
849
+ ]) + sum([
850
+ ep['EstimatedMonthlyCost'] for ep in discovery_result.vpc_endpoints
851
+ ])
852
+
853
+ self.rich_console.print_panel(
854
+ "VPC Discovery Integration Complete",
855
+ f"Total VPCs: {len(discovery_result.vpcs)}\n"
856
+ f"NAT Gateways: {len(discovery_result.nat_gateways)}\n"
857
+ f"VPC Endpoints: {len(discovery_result.vpc_endpoints)}\n"
858
+ f"Network Interfaces: {len(discovery_result.network_interfaces)}\n"
859
+ f"Estimated Monthly Network Cost: ${total_monthly_cost:.2f}\n"
860
+ f"Discovery Timestamp: {discovery_result.discovery_timestamp}",
861
+ title="🔍 VPC Module Integration"
862
+ )
863
+
864
+ return discovery_result
865
+
866
+ except Exception as e:
867
+ logger.error(f"VPC topology discovery failed: {e}")
868
+ self.rich_console.print_error(f"❌ VPC discovery failed: {e}")
869
+ raise
870
+
871
+ def analyze_awso_dependencies_comprehensive(self, discovery_result: Optional[VPCDiscoveryResult] = None) -> AWSOAnalysis:
872
+ """
873
+ AWSO-05 dependency analysis using migrated VPC module capabilities.
874
+
875
+ Integrates cost_engine.py analysis patterns with AWSO-05 cleanup requirements.
876
+ Provides 12-step dependency validation for safe VPC cleanup operations.
877
+
878
+ Args:
879
+ discovery_result: Previous discovery result (uses last if None)
880
+
881
+ Returns:
882
+ AWSOAnalysis with comprehensive dependency mapping
883
+ """
884
+ self.rich_console.print_header("AWSO-05 Dependency Analysis", "12-Step Framework Integration")
885
+
886
+ try:
887
+ # Use integrated VPC analyzer for AWSO analysis
888
+ awso_analysis = self.vpc_analyzer.analyze_awso_dependencies(discovery_result)
889
+ self.last_awso_analysis = awso_analysis
890
+
891
+ # Display business-critical warnings
892
+ if awso_analysis.eni_gate_warnings:
893
+ self.rich_console.print_warning(
894
+ f"🚨 CRITICAL: {len(awso_analysis.eni_gate_warnings)} ENI gate warnings detected!\n"
895
+ "VPC cleanup may disrupt active workloads. Review migration requirements."
896
+ )
897
+
898
+ if awso_analysis.default_vpcs:
899
+ self.rich_console.print_info(
900
+ f"🎯 Default VPCs found: {len(awso_analysis.default_vpcs)}\n"
901
+ "CIS Benchmark compliance can be improved through cleanup."
902
+ )
903
+
904
+ # Display cleanup readiness status
905
+ cleanup_status = awso_analysis.evidence_bundle.get('CleanupReadiness', 'UNKNOWN')
906
+ status_style = "green" if cleanup_status == 'READY' else "yellow"
907
+
908
+ self.rich_console.print_panel(
909
+ "AWSO-05 Analysis Complete",
910
+ f"Default VPCs: {len(awso_analysis.default_vpcs)}\n"
911
+ f"ENI Warnings: {len(awso_analysis.eni_gate_warnings)}\n"
912
+ f"Cleanup Recommendations: {len(awso_analysis.cleanup_recommendations)}\n"
913
+ f"Cleanup Readiness: {cleanup_status}",
914
+ title="🎯 AWSO-05 Analysis Results",
915
+ style=status_style
916
+ )
917
+
918
+ return awso_analysis
919
+
920
+ except Exception as e:
921
+ logger.error(f"AWSO-05 analysis failed: {e}")
922
+ self.rich_console.print_error(f"❌ AWSO-05 analysis failed: {e}")
923
+ raise
924
+
925
+ def generate_vpc_evidence_bundle(self, output_dir: str = "./awso_evidence") -> Dict[str, str]:
926
+ """
927
+ Generate comprehensive evidence bundle using migrated VPC module capabilities.
928
+
929
+ Integrates manager_interface.py reporting patterns with AWSO-05 compliance requirements.
930
+ Creates SHA256-verified evidence bundle for audit trails and compliance.
931
+
932
+ Args:
933
+ output_dir: Directory to store evidence files
934
+
935
+ Returns:
936
+ Dict with generated file paths and checksums
937
+ """
938
+ self.rich_console.print_header("Evidence Bundle Generation", "Enterprise Compliance Integration")
939
+
940
+ try:
941
+ # Use integrated VPC analyzer for evidence generation
942
+ evidence_files = self.vpc_analyzer.generate_cleanup_evidence(output_dir)
943
+
944
+ if evidence_files:
945
+ self.rich_console.print_success(
946
+ f"✅ Evidence bundle generated successfully!\n"
947
+ f"Files created: {len(evidence_files)}\n"
948
+ f"Output directory: {output_dir}"
949
+ )
950
+
951
+ # Display evidence summary for manager interface compatibility
952
+ self.rich_console.print_panel(
953
+ "Evidence Bundle Summary",
954
+ "\n".join([f"• {evidence_type}: {file_path.split('/')[-1]}"
955
+ for evidence_type, file_path in evidence_files.items()]),
956
+ title="📋 AWSO-05 Evidence Files"
957
+ )
958
+ else:
959
+ self.rich_console.print_warning("⚠️ No evidence files generated - run discovery and analysis first")
960
+
961
+ return evidence_files
962
+
963
+ except Exception as e:
964
+ logger.error(f"Evidence bundle generation failed: {e}")
965
+ self.rich_console.print_error(f"❌ Evidence bundle generation failed: {e}")
966
+ raise
967
+
968
+ def execute_integrated_vpc_analysis(self, vpc_ids: Optional[List[str]] = None,
969
+ generate_evidence: bool = True) -> Dict[str, Any]:
970
+ """
971
+ Execute complete integrated VPC analysis workflow using migrated VPC module capabilities.
972
+
973
+ Combines networking_wrapper.py, cost_engine.py, and manager_interface.py patterns
974
+ into a single comprehensive analysis workflow for enterprise VPC management.
975
+
976
+ Args:
977
+ vpc_ids: Optional list of specific VPC IDs to analyze
978
+ generate_evidence: Whether to generate evidence bundle
979
+
980
+ Returns:
981
+ Dict with complete analysis results and evidence files
982
+ """
983
+ self.rich_console.print_header("Integrated VPC Analysis", "Complete VPC Module Integration")
984
+
985
+ workflow_results = {
986
+ 'discovery_result': None,
987
+ 'awso_analysis': None,
988
+ 'evidence_files': None,
989
+ 'analysis_summary': {}
990
+ }
991
+
992
+ try:
993
+ # Step 1: VPC Topology Discovery
994
+ self.rich_console.print_info("🔍 Step 1: VPC Topology Discovery...")
995
+ discovery_result = self.discover_vpc_topology_comprehensive(vpc_ids)
996
+ workflow_results['discovery_result'] = discovery_result
997
+
998
+ # Step 2: AWSO-05 Dependency Analysis
999
+ self.rich_console.print_info("🎯 Step 2: AWSO-05 Dependency Analysis...")
1000
+ awso_analysis = self.analyze_awso_dependencies_comprehensive(discovery_result)
1001
+ workflow_results['awso_analysis'] = awso_analysis
1002
+
1003
+ # Step 3: Evidence Bundle Generation (if requested)
1004
+ if generate_evidence:
1005
+ self.rich_console.print_info("📋 Step 3: Evidence Bundle Generation...")
1006
+ evidence_files = self.generate_vpc_evidence_bundle()
1007
+ workflow_results['evidence_files'] = evidence_files
1008
+
1009
+ # Step 4: Analysis Summary (manager interface compatibility)
1010
+ total_monthly_cost = sum([
1011
+ nat['EstimatedMonthlyCost'] for nat in discovery_result.nat_gateways
1012
+ ]) + sum([
1013
+ ep['EstimatedMonthlyCost'] for ep in discovery_result.vpc_endpoints
1014
+ ])
1015
+
1016
+ workflow_results['analysis_summary'] = {
1017
+ 'total_resources': discovery_result.total_resources,
1018
+ 'estimated_monthly_cost': total_monthly_cost,
1019
+ 'default_vpcs_found': len(awso_analysis.default_vpcs),
1020
+ 'eni_gate_warnings': len(awso_analysis.eni_gate_warnings),
1021
+ 'cleanup_recommendations': len(awso_analysis.cleanup_recommendations),
1022
+ 'cleanup_readiness': awso_analysis.evidence_bundle.get('CleanupReadiness', 'UNKNOWN'),
1023
+ 'cis_benchmark_compliance': awso_analysis.evidence_bundle.get('ComplianceStatus', {}).get('CISBenchmark', 'UNKNOWN')
1024
+ }
1025
+
1026
+ # Display comprehensive summary
1027
+ summary = workflow_results['analysis_summary']
1028
+ self.rich_console.print_panel(
1029
+ "Integrated VPC Analysis Complete",
1030
+ f"Total Resources Discovered: {summary['total_resources']}\n"
1031
+ f"Estimated Monthly Network Cost: ${summary['estimated_monthly_cost']:.2f}\n"
1032
+ f"Default VPCs (Security Risk): {summary['default_vpcs_found']}\n"
1033
+ f"ENI Gate Warnings: {summary['eni_gate_warnings']}\n"
1034
+ f"Cleanup Recommendations: {summary['cleanup_recommendations']}\n"
1035
+ f"Cleanup Readiness: {summary['cleanup_readiness']}\n"
1036
+ f"CIS Benchmark Status: {summary['cis_benchmark_compliance']}",
1037
+ title="🏆 VPC Module Integration Results"
1038
+ )
1039
+
1040
+ return workflow_results
1041
+
1042
+ except Exception as e:
1043
+ logger.error(f"Integrated VPC analysis failed: {e}")
1044
+ self.rich_console.print_error(f"❌ Integrated VPC analysis failed: {e}")
1045
+ raise
1046
+
727
1047
  def _discover_unused_eips(
728
1048
  self, context: OperationContext, target_region: Optional[str] = None
729
1049
  ) -> List[OperationResult]:
@@ -1036,3 +1356,1146 @@ class VPCOperations(BaseOperation):
1036
1356
  except Exception as e:
1037
1357
  logger.warning(f"Could not get all regions, using defaults: {e}")
1038
1358
  return ["us-east-1", "us-west-2", "eu-west-1", "ap-southeast-1"]
1359
+
1360
+
1361
+ # ============================================================================
1362
+ # ENHANCED VPC MANAGEMENT - VPC Module Migration Integration
1363
+ # ============================================================================
1364
+
1365
+ from enum import Enum
1366
+ from pathlib import Path
1367
+
1368
+ class BusinessPriority(Enum):
1369
+ """Business priority levels for manager decision making"""
1370
+ CRITICAL = "Critical"
1371
+ HIGH = "High"
1372
+ MEDIUM = "Medium"
1373
+ LOW = "Low"
1374
+
1375
+
1376
+ class RiskLevel(Enum):
1377
+ """Risk assessment levels for business decisions"""
1378
+ MINIMAL = "Minimal"
1379
+ LOW = "Low"
1380
+ MEDIUM = "Medium"
1381
+ HIGH = "High"
1382
+
1383
+
1384
+ @dataclass
1385
+ class BusinessRecommendation:
1386
+ """Business-focused recommendation structure migrated from vpc module"""
1387
+ title: str
1388
+ executive_summary: str
1389
+ monthly_savings: float
1390
+ annual_impact: float
1391
+ implementation_timeline: str
1392
+ business_priority: BusinessPriority
1393
+ risk_level: RiskLevel
1394
+ resource_requirements: List[str]
1395
+ success_metrics: List[str]
1396
+ approval_required: bool
1397
+ quick_win: bool
1398
+ strategic_value: str
1399
+
1400
+
1401
+ @dataclass
1402
+ class ManagerDashboardConfig:
1403
+ """Configuration for manager dashboard behavior"""
1404
+ safety_mode: bool = True
1405
+ auto_export: bool = True
1406
+ executive_summaries_only: bool = False
1407
+ approval_threshold: float = 1000.0
1408
+ target_savings_percentage: float = 30.0
1409
+ max_implementation_weeks: int = 12
1410
+ preferred_export_formats: List[str] = None
1411
+
1412
+ def __post_init__(self):
1413
+ if self.preferred_export_formats is None:
1414
+ self.preferred_export_formats = ["json", "csv", "excel"]
1415
+
1416
+
1417
+ class EnhancedVPCNetworkingManager(BaseOperation):
1418
+ """
1419
+ Enhanced VPC Networking Manager - Migrated capabilities from vpc module
1420
+
1421
+ Integrates networking_wrapper.py, manager_interface.py, and cost_engine.py
1422
+ capabilities into operate module following "Do one thing and do it well" principle.
1423
+
1424
+ Provides enterprise VPC management with:
1425
+ - Manager-friendly business interface
1426
+ - Cost optimization with MCP validation
1427
+ - Network topology management
1428
+ - Safety-first operations with approval workflows
1429
+ """
1430
+
1431
+ def __init__(self, dry_run: bool = True):
1432
+ super().__init__(dry_run=dry_run)
1433
+ self.operation_name = "enhanced_vpc_networking"
1434
+ self.manager_config = ManagerDashboardConfig()
1435
+ self.analysis_results = {}
1436
+ self.business_recommendations = []
1437
+ self.export_directory = Path("./tmp/manager_dashboard")
1438
+
1439
+ # Cost model integration from vpc cost_engine
1440
+ self.nat_gateway_hourly_cost = 0.045 # $0.045/hour
1441
+ self.nat_gateway_data_processing = 0.045 # $0.045/GB
1442
+ self.transit_gateway_monthly_cost = 36.50
1443
+ self.vpc_endpoint_hourly_cost = 0.01
1444
+
1445
+ def execute_operation(self, context: OperationContext, operation_type: str, **kwargs) -> List[OperationResult]:
1446
+ """Enhanced VPC operations with manager interface support"""
1447
+ if operation_type.startswith("analyze_network_topology"):
1448
+ return self._analyze_network_topology_comprehensive(context, **kwargs)
1449
+ elif operation_type.startswith("generate_manager_report"):
1450
+ return self._generate_manager_report(context, **kwargs)
1451
+ elif operation_type.startswith("optimize_vpc_costs"):
1452
+ return self._optimize_vpc_costs_comprehensive(context, **kwargs)
1453
+ elif operation_type.startswith("analyze_nat_gateway_usage"):
1454
+ return self._analyze_nat_gateway_usage_detailed(context, **kwargs)
1455
+ elif operation_type.startswith("manage_vpc_endpoints"):
1456
+ return self._manage_vpc_endpoints(context, **kwargs)
1457
+ else:
1458
+ # Fall back to base VPC operations
1459
+ return super().execute_operation(context, operation_type, **kwargs)
1460
+
1461
+ def _analyze_network_topology_comprehensive(self, context: OperationContext, **kwargs) -> List[OperationResult]:
1462
+ """
1463
+ Comprehensive network topology analysis migrated from networking_wrapper.py
1464
+ """
1465
+ result = self.create_operation_result(context, "analyze_network_topology", "vpc", "network-topology")
1466
+
1467
+ try:
1468
+ self.rich_console.print_header("Comprehensive Network Topology Analysis", "v0.9.1")
1469
+
1470
+ topology_analysis = {
1471
+ "timestamp": datetime.now().isoformat(),
1472
+ "account_id": context.account_id,
1473
+ "region": context.region,
1474
+ "vpc_topology": {},
1475
+ "cost_analysis": {},
1476
+ "optimization_opportunities": [],
1477
+ "business_recommendations": []
1478
+ }
1479
+
1480
+ ec2_client = self.get_client("ec2", context.region)
1481
+
1482
+ # Get comprehensive VPC data
1483
+ vpcs_response = self.execute_aws_call(ec2_client, "describe_vpcs")
1484
+ nat_response = self.execute_aws_call(ec2_client, "describe_nat_gateways")
1485
+ endpoints_response = self.execute_aws_call(ec2_client, "describe_vpc_endpoints")
1486
+
1487
+ # Process VPCs with enhanced metadata
1488
+ vpcs_data = []
1489
+ total_monthly_cost = 0
1490
+
1491
+ for vpc in vpcs_response["Vpcs"]:
1492
+ vpc_analysis = self._analyze_vpc_comprehensive(ec2_client, vpc, context)
1493
+ vpcs_data.append(vpc_analysis)
1494
+ total_monthly_cost += vpc_analysis.get("estimated_monthly_cost", 0)
1495
+
1496
+ # Process NAT Gateways
1497
+ nat_gateways_data = []
1498
+ for nat in nat_response["NatGateways"]:
1499
+ if nat["State"] != "deleted":
1500
+ nat_analysis = self._analyze_nat_gateway_costs(ec2_client, nat, context)
1501
+ nat_gateways_data.append(nat_analysis)
1502
+
1503
+ # Generate business recommendations
1504
+ business_recommendations = self._generate_business_recommendations(
1505
+ vpcs_data, nat_gateways_data, total_monthly_cost
1506
+ )
1507
+
1508
+ topology_analysis.update({
1509
+ "vpcs": vpcs_data,
1510
+ "nat_gateways": nat_gateways_data,
1511
+ "vpc_endpoints": self._analyze_vpc_endpoints(endpoints_response["VpcEndpoints"]),
1512
+ "total_monthly_cost": total_monthly_cost,
1513
+ "total_annual_cost": total_monthly_cost * 12,
1514
+ "business_recommendations": business_recommendations
1515
+ })
1516
+
1517
+ # Display results with Rich formatting
1518
+ self._display_topology_analysis(topology_analysis)
1519
+
1520
+ result.mark_completed(OperationStatus.SUCCESS)
1521
+ result.response_data = topology_analysis
1522
+
1523
+ except Exception as e:
1524
+ error_msg = f"Network topology analysis failed: {e}"
1525
+ result.mark_completed(OperationStatus.FAILED, error_msg)
1526
+ self.rich_console.print_error(f"❌ {error_msg}")
1527
+ logger.error(error_msg)
1528
+
1529
+ return [result]
1530
+
1531
+ def _analyze_vpc_comprehensive(self, ec2_client, vpc: Dict[str, Any], context: OperationContext) -> Dict[str, Any]:
1532
+ """Comprehensive VPC analysis with cost implications"""
1533
+ tags = {tag["Key"]: tag["Value"] for tag in vpc.get("Tags", [])}
1534
+
1535
+ vpc_analysis = {
1536
+ "vpc_id": vpc["VpcId"],
1537
+ "cidr_block": vpc["CidrBlock"],
1538
+ "state": vpc["State"],
1539
+ "name": tags.get("Name", vpc["VpcId"]),
1540
+ "tags": tags,
1541
+ "is_default": vpc.get("IsDefault", False),
1542
+ "subnets": [],
1543
+ "security_groups": [],
1544
+ "route_tables": [],
1545
+ "estimated_monthly_cost": 0,
1546
+ "optimization_opportunities": []
1547
+ }
1548
+
1549
+ try:
1550
+ # Get subnets
1551
+ subnets_response = self.execute_aws_call(
1552
+ ec2_client, "describe_subnets",
1553
+ Filters=[{"Name": "vpc-id", "Values": [vpc["VpcId"]]}]
1554
+ )
1555
+
1556
+ for subnet in subnets_response["Subnets"]:
1557
+ subnet_tags = {tag["Key"]: tag["Value"] for tag in subnet.get("Tags", [])}
1558
+ vpc_analysis["subnets"].append({
1559
+ "subnet_id": subnet["SubnetId"],
1560
+ "cidr_block": subnet["CidrBlock"],
1561
+ "availability_zone": subnet["AvailabilityZone"],
1562
+ "available_ip_address_count": subnet["AvailableIpAddressCount"],
1563
+ "map_public_ip_on_launch": subnet.get("MapPublicIpOnLaunch", False),
1564
+ "tags": subnet_tags,
1565
+ "name": subnet_tags.get("Name", subnet["SubnetId"])
1566
+ })
1567
+
1568
+ # Basic cost estimation (placeholder for more sophisticated analysis)
1569
+ if len(vpc_analysis["subnets"]) > 10:
1570
+ vpc_analysis["optimization_opportunities"].append({
1571
+ "type": "subnet_consolidation",
1572
+ "description": f"VPC has {len(vpc_analysis['subnets'])} subnets - consider consolidation",
1573
+ "potential_savings": "Reduced management overhead"
1574
+ })
1575
+
1576
+ except Exception as e:
1577
+ logger.warning(f"Failed to get detailed VPC data for {vpc['VpcId']}: {e}")
1578
+
1579
+ return vpc_analysis
1580
+
1581
+ def _analyze_nat_gateway_costs(self, ec2_client, nat: Dict[str, Any], context: OperationContext) -> Dict[str, Any]:
1582
+ """Detailed NAT Gateway cost analysis"""
1583
+ tags = {tag["Key"]: tag["Value"] for tag in nat.get("Tags", [])}
1584
+
1585
+ # Base monthly cost (24/7 * 30 days * $0.045/hour)
1586
+ base_monthly_cost = 24 * 30 * self.nat_gateway_hourly_cost
1587
+
1588
+ nat_analysis = {
1589
+ "nat_gateway_id": nat["NatGatewayId"],
1590
+ "state": nat["State"],
1591
+ "vpc_id": nat.get("VpcId"),
1592
+ "subnet_id": nat.get("SubnetId"),
1593
+ "connectivity_type": nat.get("ConnectivityType", "public"),
1594
+ "tags": tags,
1595
+ "name": tags.get("Name", nat["NatGatewayId"]),
1596
+ "base_monthly_cost": base_monthly_cost,
1597
+ "estimated_data_processing_cost": 0, # Would need CloudWatch metrics for accurate calculation
1598
+ "total_estimated_monthly_cost": base_monthly_cost,
1599
+ "optimization_recommendation": "monitor_usage"
1600
+ }
1601
+
1602
+ # Add optimization recommendations based on analysis
1603
+ if nat["State"] == "available":
1604
+ nat_analysis["optimization_recommendation"] = "monitor_usage"
1605
+ elif nat["State"] in ["pending", "failed"]:
1606
+ nat_analysis["optimization_recommendation"] = "investigate_health"
1607
+
1608
+ return nat_analysis
1609
+
1610
+ def _analyze_vpc_endpoints(self, endpoints: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
1611
+ """Analyze VPC endpoints with cost implications"""
1612
+ endpoints_analysis = []
1613
+
1614
+ for endpoint in endpoints:
1615
+ tags = {tag["Key"]: tag["Value"] for tag in endpoint.get("Tags", [])}
1616
+
1617
+ # Estimate monthly cost based on endpoint type
1618
+ if endpoint.get("VpcEndpointType") == "Interface":
1619
+ estimated_monthly_cost = 24 * 30 * self.vpc_endpoint_hourly_cost # Interface endpoints have hourly charges
1620
+ else:
1621
+ estimated_monthly_cost = 0 # Gateway endpoints are typically free
1622
+
1623
+ endpoints_analysis.append({
1624
+ "vpc_endpoint_id": endpoint["VpcEndpointId"],
1625
+ "vpc_id": endpoint.get("VpcId"),
1626
+ "service_name": endpoint.get("ServiceName"),
1627
+ "endpoint_type": endpoint.get("VpcEndpointType"),
1628
+ "state": endpoint.get("State"),
1629
+ "tags": tags,
1630
+ "name": tags.get("Name", endpoint["VpcEndpointId"]),
1631
+ "estimated_monthly_cost": estimated_monthly_cost,
1632
+ "route_table_ids": endpoint.get("RouteTableIds", []),
1633
+ "subnet_ids": endpoint.get("SubnetIds", [])
1634
+ })
1635
+
1636
+ return endpoints_analysis
1637
+
1638
+ def _generate_business_recommendations(self, vpcs_data: List[Dict], nat_data: List[Dict], total_cost: float) -> List[BusinessRecommendation]:
1639
+ """Generate business-focused recommendations"""
1640
+ recommendations = []
1641
+
1642
+ # NAT Gateway optimization recommendation
1643
+ active_nat_gateways = [nat for nat in nat_data if nat["state"] == "available"]
1644
+ if len(active_nat_gateways) > len(vpcs_data):
1645
+ potential_savings = (len(active_nat_gateways) - len(vpcs_data)) * 45.0 # $45/month per NAT Gateway
1646
+
1647
+ recommendations.append(BusinessRecommendation(
1648
+ title="NAT Gateway Consolidation Opportunity",
1649
+ executive_summary=f"Multiple NAT Gateways detected ({len(active_nat_gateways)}) across {len(vpcs_data)} VPCs",
1650
+ monthly_savings=potential_savings,
1651
+ annual_impact=potential_savings * 12,
1652
+ implementation_timeline="2-4 weeks",
1653
+ business_priority=BusinessPriority.HIGH if potential_savings > 90 else BusinessPriority.MEDIUM,
1654
+ risk_level=RiskLevel.LOW,
1655
+ resource_requirements=["Network engineer", "1-2 hours/NAT Gateway"],
1656
+ success_metrics=[f"Reduce monthly NAT Gateway costs by ${potential_savings:.2f}"],
1657
+ approval_required=potential_savings > self.manager_config.approval_threshold,
1658
+ quick_win=potential_savings > 50,
1659
+ strategic_value="Cost optimization without service impact"
1660
+ ))
1661
+
1662
+ # VPC complexity recommendation
1663
+ complex_vpcs = [vpc for vpc in vpcs_data if len(vpc.get("subnets", [])) > 15]
1664
+ if complex_vpcs:
1665
+ recommendations.append(BusinessRecommendation(
1666
+ title="VPC Architecture Simplification",
1667
+ executive_summary=f"Detected {len(complex_vpcs)} VPCs with high subnet complexity",
1668
+ monthly_savings=0, # Operational savings, not direct cost
1669
+ annual_impact=0,
1670
+ implementation_timeline="6-12 weeks",
1671
+ business_priority=BusinessPriority.MEDIUM,
1672
+ risk_level=RiskLevel.MEDIUM,
1673
+ resource_requirements=["Cloud architect", "Network engineer", "4-8 hours/VPC"],
1674
+ success_metrics=["Reduced operational complexity", "Improved maintainability"],
1675
+ approval_required=True,
1676
+ quick_win=False,
1677
+ strategic_value="Improved operational efficiency and reduced management overhead"
1678
+ ))
1679
+
1680
+ return recommendations
1681
+
1682
+ def _display_topology_analysis(self, topology_analysis: Dict[str, Any]) -> None:
1683
+ """Display topology analysis with Rich formatting"""
1684
+
1685
+ # Summary panel
1686
+ summary_text = (
1687
+ f"Total VPCs: {len(topology_analysis.get('vpcs', []))}\n"
1688
+ f"Total NAT Gateways: {len(topology_analysis.get('nat_gateways', []))}\n"
1689
+ f"Total VPC Endpoints: {len(topology_analysis.get('vpc_endpoints', []))}\n"
1690
+ f"Estimated monthly cost: ${topology_analysis.get('total_monthly_cost', 0):.2f}\n"
1691
+ f"Estimated annual cost: ${topology_analysis.get('total_annual_cost', 0):.2f}"
1692
+ )
1693
+
1694
+ self.rich_console.print_panel(
1695
+ "Network Topology Summary",
1696
+ summary_text,
1697
+ title="🏗️ Infrastructure Overview"
1698
+ )
1699
+
1700
+ # Business recommendations table
1701
+ recommendations = topology_analysis.get('business_recommendations', [])
1702
+ if recommendations:
1703
+ rec_data = []
1704
+ for rec in recommendations:
1705
+ rec_data.append([
1706
+ rec.title,
1707
+ rec.business_priority.value,
1708
+ f"${rec.monthly_savings:.2f}",
1709
+ f"${rec.annual_impact:.2f}",
1710
+ rec.implementation_timeline,
1711
+ "Yes" if rec.approval_required else "No"
1712
+ ])
1713
+
1714
+ self.rich_console.print_table(
1715
+ rec_data,
1716
+ headers=["Recommendation", "Priority", "Monthly Savings", "Annual Impact", "Timeline", "Approval Required"],
1717
+ title="💡 Business Optimization Recommendations"
1718
+ )
1719
+
1720
+ def _generate_manager_report(self, context: OperationContext, **kwargs) -> List[OperationResult]:
1721
+ """Generate manager-friendly business report"""
1722
+ result = self.create_operation_result(context, "generate_manager_report", "vpc", "manager-report")
1723
+
1724
+ try:
1725
+ self.rich_console.print_header("Manager Dashboard - VPC Cost Optimization", "v0.9.1")
1726
+
1727
+ # First run comprehensive analysis
1728
+ analysis_results = self._analyze_network_topology_comprehensive(context, **kwargs)
1729
+ analysis_data = analysis_results[0].response_data
1730
+
1731
+ # Generate executive summary
1732
+ executive_report = {
1733
+ "report_generated": datetime.now().isoformat(),
1734
+ "executive_summary": {
1735
+ "total_infrastructure_cost": analysis_data.get("total_monthly_cost", 0),
1736
+ "optimization_opportunities": len(analysis_data.get("business_recommendations", [])),
1737
+ "immediate_actions": [
1738
+ rec for rec in analysis_data.get("business_recommendations", [])
1739
+ if rec.quick_win and rec.business_priority in [BusinessPriority.HIGH, BusinessPriority.CRITICAL]
1740
+ ],
1741
+ "approval_required_items": [
1742
+ rec for rec in analysis_data.get("business_recommendations", [])
1743
+ if rec.approval_required
1744
+ ]
1745
+ },
1746
+ "detailed_analysis": analysis_data,
1747
+ "next_steps": self._generate_next_steps(analysis_data.get("business_recommendations", []))
1748
+ }
1749
+
1750
+ # Display executive summary
1751
+ self._display_executive_summary(executive_report["executive_summary"])
1752
+
1753
+ result.mark_completed(OperationStatus.SUCCESS)
1754
+ result.response_data = executive_report
1755
+
1756
+ except Exception as e:
1757
+ error_msg = f"Manager report generation failed: {e}"
1758
+ result.mark_completed(OperationStatus.FAILED, error_msg)
1759
+ self.rich_console.print_error(f"❌ {error_msg}")
1760
+ logger.error(error_msg)
1761
+
1762
+ return [result]
1763
+
1764
+ def _generate_next_steps(self, recommendations: List[BusinessRecommendation]) -> List[Dict[str, str]]:
1765
+ """Generate actionable next steps for managers"""
1766
+ next_steps = []
1767
+
1768
+ high_priority = [rec for rec in recommendations if rec.business_priority == BusinessPriority.HIGH]
1769
+ quick_wins = [rec for rec in recommendations if rec.quick_win]
1770
+
1771
+ if high_priority:
1772
+ next_steps.append({
1773
+ "action": "Review High Priority Items",
1774
+ "description": f"Review {len(high_priority)} high-priority optimization opportunities",
1775
+ "timeline": "This week"
1776
+ })
1777
+
1778
+ if quick_wins:
1779
+ next_steps.append({
1780
+ "action": "Implement Quick Wins",
1781
+ "description": f"Execute {len(quick_wins)} quick-win optimizations",
1782
+ "timeline": "Next 2 weeks"
1783
+ })
1784
+
1785
+ next_steps.append({
1786
+ "action": "Schedule Technical Review",
1787
+ "description": "Meet with technical team to discuss implementation details",
1788
+ "timeline": "Within 2 weeks"
1789
+ })
1790
+
1791
+ return next_steps
1792
+
1793
+ def _display_executive_summary(self, summary: Dict[str, Any]) -> None:
1794
+ """Display executive summary with business-friendly formatting"""
1795
+
1796
+ summary_text = (
1797
+ f"Monthly Infrastructure Cost: ${summary.get('total_infrastructure_cost', 0):.2f}\n"
1798
+ f"Optimization Opportunities: {summary.get('optimization_opportunities', 0)}\n"
1799
+ f"Quick Win Actions: {len(summary.get('immediate_actions', []))}\n"
1800
+ f"Items Requiring Approval: {len(summary.get('approval_required_items', []))}"
1801
+ )
1802
+
1803
+ self.rich_console.print_panel(
1804
+ "Executive Dashboard",
1805
+ summary_text,
1806
+ title="📊 Business Overview"
1807
+ )
1808
+
1809
+
1810
+ # =============================================================================
1811
+ # AWSO-5 VPC Cleanup Operations - Enterprise Security Framework
1812
+ # =============================================================================
1813
+
1814
+ @dataclass
1815
+ class VPCCleanupConfiguration:
1816
+ """AWSO-5 VPC cleanup configuration with enterprise safety controls."""
1817
+
1818
+ vpc_id: str
1819
+ dry_run: bool = True
1820
+ force_cleanup: bool = False
1821
+ approval_token: Optional[str] = None
1822
+ evidence_collection: bool = True
1823
+ platform_lead_approval: bool = False
1824
+ skip_eni_gate: bool = False # DANGEROUS: Only for emergency scenarios
1825
+
1826
+ def __post_init__(self):
1827
+ """Validation of cleanup configuration."""
1828
+ if self.force_cleanup and not self.approval_token:
1829
+ raise ValueError("Force cleanup requires approval token")
1830
+
1831
+ if self.skip_eni_gate and not self.platform_lead_approval:
1832
+ raise ValueError("Skipping ENI gate requires Platform Lead approval")
1833
+
1834
+
1835
+ @dataclass
1836
+ class VPCCleanupPlan:
1837
+ """AWSO-5 VPC cleanup execution plan with ordered steps."""
1838
+
1839
+ vpc_id: str
1840
+ cleanup_steps: List[Dict[str, Any]]
1841
+ estimated_duration_minutes: int
1842
+ risk_level: str # LOW, MEDIUM, HIGH
1843
+ requires_approval: bool
1844
+
1845
+ # Evidence collection
1846
+ pre_cleanup_evidence: Dict[str, Any]
1847
+ plan_hash: str
1848
+ plan_timestamp: str
1849
+
1850
+ @property
1851
+ def total_steps(self) -> int:
1852
+ """Total number of cleanup steps."""
1853
+ return len(self.cleanup_steps)
1854
+
1855
+ @property
1856
+ def blocking_steps(self) -> int:
1857
+ """Number of steps that could cause service disruption."""
1858
+ return len([step for step in self.cleanup_steps if step.get('risk_level') == 'HIGH'])
1859
+
1860
+
1861
+ class AWSO5VPCCleanupOperation(BaseOperation):
1862
+ """
1863
+ AWSO-5 VPC Cleanup Operation - Enterprise Security Framework.
1864
+
1865
+ Implements comprehensive VPC cleanup following the AWSO-5 12-step framework
1866
+ with enterprise safety controls, evidence collection, and approval workflows.
1867
+
1868
+ **Strategic Alignment**:
1869
+ - Security posture enhancement through default VPC elimination
1870
+ - Attack surface reduction via systematic dependency cleanup
1871
+ - CIS Benchmark compliance through infrastructure hygiene
1872
+ - Evidence-based validation with SHA256-verified audit trails
1873
+
1874
+ **Safety Controls**:
1875
+ - ENI gate validation (prevents accidental workload disruption)
1876
+ - Dry-run first approach with detailed execution plans
1877
+ - Platform Lead approval for high-risk operations
1878
+ - Comprehensive rollback procedures
1879
+ - Real-time monitoring and validation
1880
+ """
1881
+
1882
+ def __init__(self, context: OperationContext):
1883
+ """Initialize AWSO-5 VPC cleanup operation."""
1884
+ super().__init__(context)
1885
+ self.operation_type = "AWSO5_VPC_CLEANUP"
1886
+
1887
+ # Initialize dependency analyzer
1888
+ from runbooks.inventory.vpc_dependency_analyzer import VPCDependencyAnalyzer
1889
+ self.dependency_analyzer = VPCDependencyAnalyzer(
1890
+ session=self.context.session,
1891
+ region=self.context.region
1892
+ )
1893
+
1894
+ # Cleanup tracking
1895
+ self.cleanup_evidence: Dict[str, Any] = {}
1896
+ self.cleanup_plan: Optional[VPCCleanupPlan] = None
1897
+
1898
+ def execute_vpc_cleanup(
1899
+ self,
1900
+ config: VPCCleanupConfiguration,
1901
+ evidence_bundle_path: Optional[str] = None
1902
+ ) -> List[OperationResult]:
1903
+ """
1904
+ Execute AWSO-5 VPC cleanup with comprehensive safety validation.
1905
+
1906
+ Args:
1907
+ config: VPC cleanup configuration
1908
+ evidence_bundle_path: Optional path to save evidence bundle
1909
+
1910
+ Returns:
1911
+ Operation results with evidence and audit information
1912
+ """
1913
+ results = []
1914
+ operation_start = datetime.utcnow()
1915
+
1916
+ try:
1917
+ # Phase 1: Pre-cleanup Analysis & Validation
1918
+ self.rich_console.print_header("AWSO-5 VPC Cleanup Operation", "1.0.0")
1919
+ self.rich_console.print_info(f"Target VPC: {config.vpc_id}")
1920
+ self.rich_console.print_info(f"Mode: {'DRY-RUN' if config.dry_run else 'EXECUTE'}")
1921
+
1922
+ # Step 1: ENI Gate Validation (Critical Safety Check)
1923
+ if not config.skip_eni_gate:
1924
+ self.rich_console.print_info("Step 1: ENI Gate Validation (Critical Safety Check)")
1925
+ dependency_result = self.dependency_analyzer.analyze_vpc_dependencies(config.vpc_id)
1926
+
1927
+ if dependency_result.eni_count > 0:
1928
+ error_msg = f"ENI Gate FAILED: {dependency_result.eni_count} active ENIs detected"
1929
+ self.rich_console.print_error(f"❌ {error_msg}")
1930
+ self.rich_console.print_warning("⚠️ Active ENIs indicate running workloads!")
1931
+ self.rich_console.print_info("Next Steps:")
1932
+ self.rich_console.print_info("1. Investigate ENI owners and workload requirements")
1933
+ self.rich_console.print_info("2. Coordinate with application teams")
1934
+ self.rich_console.print_info("3. Consider migration vs cleanup options")
1935
+
1936
+ result = OperationResult(
1937
+ operation_id=self.context.operation_id,
1938
+ operation_type="AWSO5_ENI_GATE_CHECK",
1939
+ status=OperationStatus.FAILED,
1940
+ message=error_msg,
1941
+ details={
1942
+ 'eni_count': dependency_result.eni_count,
1943
+ 'vpc_id': config.vpc_id,
1944
+ 'recommendation': 'INVESTIGATE_REQUIRED',
1945
+ 'dependencies': [dep.__dict__ for dep in dependency_result.dependencies]
1946
+ }
1947
+ )
1948
+ return [result]
1949
+
1950
+ self.rich_console.print_success("✅ ENI Gate PASSED - No active ENIs detected")
1951
+ else:
1952
+ self.rich_console.print_warning("⚠️ ENI Gate SKIPPED (Platform Lead Approval Required)")
1953
+ dependency_result = self.dependency_analyzer.analyze_vpc_dependencies(config.vpc_id)
1954
+
1955
+ # Step 2: Generate Cleanup Plan
1956
+ self.rich_console.print_info("Step 2: Generating Comprehensive Cleanup Plan")
1957
+ self.cleanup_plan = self._generate_cleanup_plan(dependency_result, config)
1958
+
1959
+ # Display cleanup plan
1960
+ self._display_cleanup_plan(self.cleanup_plan)
1961
+
1962
+ # Step 3: Risk Assessment & Approval Gate
1963
+ if self.cleanup_plan.requires_approval and not config.approval_token:
1964
+ self.rich_console.print_warning("⚠️ This cleanup requires Platform Lead approval")
1965
+ self.rich_console.print_info("Required approvals:")
1966
+ if dependency_result.is_default:
1967
+ self.rich_console.print_info("• Platform Lead (Default VPC deletion)")
1968
+ if self.cleanup_plan.risk_level == "HIGH":
1969
+ self.rich_console.print_info("• Additional stakeholder review")
1970
+
1971
+ result = OperationResult(
1972
+ operation_id=self.context.operation_id,
1973
+ operation_type="AWSO5_APPROVAL_REQUIRED",
1974
+ status=OperationStatus.PENDING_APPROVAL,
1975
+ message="Platform Lead approval required for VPC cleanup",
1976
+ details={
1977
+ 'vpc_id': config.vpc_id,
1978
+ 'risk_level': self.cleanup_plan.risk_level,
1979
+ 'requires_approval_reason': 'Default VPC or High Risk Operation',
1980
+ 'cleanup_plan': self.cleanup_plan.__dict__
1981
+ }
1982
+ )
1983
+ return [result]
1984
+
1985
+ # Step 4: Execute Cleanup (Dry-run or Actual)
1986
+ if config.dry_run:
1987
+ self.rich_console.print_info("Step 3: DRY-RUN Mode - No actual changes will be made")
1988
+ result = self._execute_dry_run_cleanup(self.cleanup_plan, config)
1989
+ else:
1990
+ self.rich_console.print_info("Step 3: EXECUTING VPC Cleanup")
1991
+ result = self._execute_actual_cleanup(self.cleanup_plan, config)
1992
+
1993
+ # Step 5: Evidence Bundle Generation
1994
+ if config.evidence_collection:
1995
+ self.rich_console.print_info("Step 4: Generating Evidence Bundle")
1996
+ evidence_bundle = self._generate_evidence_bundle(
1997
+ dependency_result,
1998
+ self.cleanup_plan,
1999
+ result,
2000
+ evidence_bundle_path
2001
+ )
2002
+ result.details['evidence_bundle'] = evidence_bundle
2003
+
2004
+ results.append(result)
2005
+
2006
+ except Exception as e:
2007
+ error_msg = f"AWSO-5 VPC cleanup failed: {str(e)}"
2008
+ logger.exception(error_msg)
2009
+
2010
+ result = OperationResult(
2011
+ operation_id=self.context.operation_id,
2012
+ operation_type="AWSO5_VPC_CLEANUP_ERROR",
2013
+ status=OperationStatus.FAILED,
2014
+ message=error_msg,
2015
+ details={
2016
+ 'vpc_id': config.vpc_id,
2017
+ 'error_type': type(e).__name__,
2018
+ 'operation_duration': (datetime.utcnow() - operation_start).total_seconds()
2019
+ }
2020
+ )
2021
+ results.append(result)
2022
+
2023
+ return results
2024
+
2025
+ def _generate_cleanup_plan(
2026
+ self,
2027
+ dependency_result,
2028
+ config: VPCCleanupConfiguration
2029
+ ) -> VPCCleanupPlan:
2030
+ """Generate comprehensive VPC cleanup plan based on dependency analysis."""
2031
+
2032
+ cleanup_steps = []
2033
+ risk_level = "LOW"
2034
+ estimated_duration = 5 # Base time in minutes
2035
+
2036
+ # Generate cleanup steps based on dependencies
2037
+ for dependency in dependency_result.dependencies:
2038
+ if dependency.is_blocking:
2039
+ step = {
2040
+ 'step_type': 'DEPENDENCY_CLEANUP',
2041
+ 'resource_type': dependency.resource_type,
2042
+ 'resource_id': dependency.resource_id,
2043
+ 'action': dependency.remediation_action,
2044
+ 'risk_level': 'HIGH' if dependency.resource_type in ['LoadBalancer', 'TransitGatewayAttachment'] else 'MEDIUM',
2045
+ 'estimated_minutes': self._estimate_cleanup_time(dependency.resource_type)
2046
+ }
2047
+ cleanup_steps.append(step)
2048
+ estimated_duration += step['estimated_minutes']
2049
+
2050
+ if step['risk_level'] == 'HIGH':
2051
+ risk_level = "HIGH"
2052
+ elif step['risk_level'] == 'MEDIUM' and risk_level != "HIGH":
2053
+ risk_level = "MEDIUM"
2054
+
2055
+ # Final VPC deletion step
2056
+ cleanup_steps.append({
2057
+ 'step_type': 'VPC_DELETION',
2058
+ 'resource_type': 'VPC',
2059
+ 'resource_id': config.vpc_id,
2060
+ 'action': 'Delete VPC (final step)',
2061
+ 'risk_level': 'MEDIUM',
2062
+ 'estimated_minutes': 2
2063
+ })
2064
+ estimated_duration += 2
2065
+
2066
+ # Calculate plan hash for integrity
2067
+ import hashlib
2068
+ import json
2069
+ plan_content = json.dumps(cleanup_steps, sort_keys=True)
2070
+ plan_hash = hashlib.sha256(plan_content.encode()).hexdigest()
2071
+
2072
+ return VPCCleanupPlan(
2073
+ vpc_id=config.vpc_id,
2074
+ cleanup_steps=cleanup_steps,
2075
+ estimated_duration_minutes=estimated_duration,
2076
+ risk_level=risk_level,
2077
+ requires_approval=dependency_result.is_default or risk_level == "HIGH",
2078
+ pre_cleanup_evidence=dependency_result.__dict__,
2079
+ plan_hash=plan_hash[:16], # Short hash for display
2080
+ plan_timestamp=datetime.utcnow().isoformat()
2081
+ )
2082
+
2083
+ def _estimate_cleanup_time(self, resource_type: str) -> int:
2084
+ """Estimate cleanup time in minutes for different resource types."""
2085
+ time_estimates = {
2086
+ 'NetworkInterface': 3,
2087
+ 'NatGateway': 5,
2088
+ 'InternetGateway': 2,
2089
+ 'RouteTable': 2,
2090
+ 'VpcEndpoint': 3,
2091
+ 'TransitGatewayAttachment': 10,
2092
+ 'VpcPeeringConnection': 3,
2093
+ 'ResolverEndpoint': 5,
2094
+ 'LoadBalancer': 8,
2095
+ 'SecurityGroup': 2,
2096
+ 'NetworkAcl': 2,
2097
+ 'FlowLog': 1
2098
+ }
2099
+ return time_estimates.get(resource_type, 3)
2100
+
2101
+ def _display_cleanup_plan(self, plan: VPCCleanupPlan) -> None:
2102
+ """Display comprehensive cleanup plan with Rich formatting."""
2103
+
2104
+ # Plan Summary
2105
+ summary_table = create_table(
2106
+ title="AWSO-5 VPC Cleanup Plan Summary"
2107
+ )
2108
+ summary_table.add_column("Metric", style="cyan")
2109
+ summary_table.add_column("Value", style="green")
2110
+
2111
+ summary_table.add_row("VPC ID", plan.vpc_id)
2112
+ summary_table.add_row("Total Steps", str(plan.total_steps))
2113
+ summary_table.add_row("Estimated Duration", f"{plan.estimated_duration_minutes} minutes")
2114
+ summary_table.add_row("Risk Level", plan.risk_level)
2115
+ summary_table.add_row("Requires Approval", "Yes" if plan.requires_approval else "No")
2116
+ summary_table.add_row("Plan Hash", plan.plan_hash)
2117
+
2118
+ self.rich_console.print("\n")
2119
+ self.rich_console.print(summary_table)
2120
+
2121
+ # Cleanup Steps Detail
2122
+ if plan.cleanup_steps:
2123
+ steps_table = create_table(
2124
+ title="Cleanup Execution Steps"
2125
+ )
2126
+ steps_table.add_column("Step", style="cyan")
2127
+ steps_table.add_column("Resource Type", style="blue")
2128
+ steps_table.add_column("Resource ID", style="green")
2129
+ steps_table.add_column("Action", style="yellow")
2130
+ steps_table.add_column("Risk", style="red")
2131
+ steps_table.add_column("Est. Time", style="magenta")
2132
+
2133
+ for i, step in enumerate(plan.cleanup_steps, 1):
2134
+ steps_table.add_row(
2135
+ str(i),
2136
+ step['resource_type'],
2137
+ step['resource_id'],
2138
+ step['action'],
2139
+ step['risk_level'],
2140
+ f"{step['estimated_minutes']}min"
2141
+ )
2142
+
2143
+ self.rich_console.print("\n")
2144
+ self.rich_console.print(steps_table)
2145
+
2146
+ # Risk Assessment
2147
+ if plan.risk_level == "HIGH":
2148
+ self.rich_console.print_warning("⚠️ HIGH RISK: This cleanup involves critical infrastructure components")
2149
+ elif plan.risk_level == "MEDIUM":
2150
+ self.rich_console.print_info("ℹ️ MEDIUM RISK: Standard cleanup with network dependencies")
2151
+ else:
2152
+ self.rich_console.print_success("✅ LOW RISK: Straightforward cleanup with minimal dependencies")
2153
+
2154
+ def _execute_dry_run_cleanup(
2155
+ self,
2156
+ plan: VPCCleanupPlan,
2157
+ config: VPCCleanupConfiguration
2158
+ ) -> OperationResult:
2159
+ """Execute dry-run cleanup showing what would be done."""
2160
+
2161
+ self.rich_console.print_success("🔍 DRY-RUN: Simulating cleanup execution")
2162
+
2163
+ simulated_results = []
2164
+ for i, step in enumerate(plan.cleanup_steps, 1):
2165
+ self.rich_console.print_info(f"Step {i}/{plan.total_steps}: Would {step['action']}")
2166
+ simulated_results.append({
2167
+ 'step': i,
2168
+ 'resource_type': step['resource_type'],
2169
+ 'resource_id': step['resource_id'],
2170
+ 'action': step['action'],
2171
+ 'simulated_result': 'SUCCESS',
2172
+ 'notes': 'Dry-run simulation - no actual changes made'
2173
+ })
2174
+ time.sleep(0.5) # Simulate processing time
2175
+
2176
+ self.rich_console.print_success("✅ DRY-RUN completed successfully")
2177
+ self.rich_console.print_info("Next Steps:")
2178
+ self.rich_console.print_info("1. Review cleanup plan and risk assessment")
2179
+ self.rich_console.print_info("2. Obtain required approvals if needed")
2180
+ self.rich_console.print_info("3. Execute with --dry-run=false when ready")
2181
+
2182
+ return OperationResult(
2183
+ operation_id=self.context.operation_id,
2184
+ operation_type="AWSO5_DRY_RUN_CLEANUP",
2185
+ status=OperationStatus.COMPLETED,
2186
+ message="Dry-run cleanup completed successfully",
2187
+ details={
2188
+ 'vpc_id': config.vpc_id,
2189
+ 'cleanup_plan': plan.__dict__,
2190
+ 'simulated_results': simulated_results,
2191
+ 'execution_mode': 'DRY_RUN'
2192
+ }
2193
+ )
2194
+
2195
+ def _execute_actual_cleanup(
2196
+ self,
2197
+ plan: VPCCleanupPlan,
2198
+ config: VPCCleanupConfiguration
2199
+ ) -> OperationResult:
2200
+ """Execute actual VPC cleanup with comprehensive error handling."""
2201
+
2202
+ self.rich_console.print_warning("⚠️ EXECUTING ACTUAL CLEANUP - This will make real changes!")
2203
+
2204
+ execution_results = []
2205
+ failed_steps = []
2206
+
2207
+ try:
2208
+ for i, step in enumerate(plan.cleanup_steps, 1):
2209
+ self.rich_console.print_info(f"Step {i}/{plan.total_steps}: {step['action']}")
2210
+
2211
+ try:
2212
+ # Execute cleanup step
2213
+ step_result = self._execute_cleanup_step(step, config)
2214
+ execution_results.append(step_result)
2215
+
2216
+ if step_result['success']:
2217
+ self.rich_console.print_success(f"✅ Step {i} completed: {step['resource_id']}")
2218
+ else:
2219
+ self.rich_console.print_error(f"❌ Step {i} failed: {step_result['error']}")
2220
+ failed_steps.append((i, step, step_result['error']))
2221
+
2222
+ # Decide whether to continue or abort
2223
+ if step['risk_level'] == 'HIGH':
2224
+ self.rich_console.print_error("🛑 ABORTING: High-risk step failed")
2225
+ break
2226
+
2227
+ except Exception as e:
2228
+ error_msg = f"Step {i} execution error: {str(e)}"
2229
+ self.rich_console.print_error(f"❌ {error_msg}")
2230
+ failed_steps.append((i, step, error_msg))
2231
+
2232
+ # Critical failure handling
2233
+ if step['risk_level'] == 'HIGH':
2234
+ self.rich_console.print_error("🛑 CRITICAL FAILURE: Aborting cleanup")
2235
+ break
2236
+
2237
+ # Final status assessment
2238
+ if not failed_steps:
2239
+ status = OperationStatus.COMPLETED
2240
+ message = "AWSO-5 VPC cleanup completed successfully"
2241
+ self.rich_console.print_success("✅ All cleanup steps completed successfully")
2242
+ elif len(failed_steps) < len(plan.cleanup_steps) // 2:
2243
+ status = OperationStatus.PARTIALLY_COMPLETED
2244
+ message = f"VPC cleanup partially completed ({len(failed_steps)} steps failed)"
2245
+ self.rich_console.print_warning(f"⚠️ Partial completion: {len(failed_steps)} steps failed")
2246
+ else:
2247
+ status = OperationStatus.FAILED
2248
+ message = f"VPC cleanup failed ({len(failed_steps)} steps failed)"
2249
+ self.rich_console.print_error(f"❌ Cleanup failed: {len(failed_steps)} steps failed")
2250
+
2251
+ # Post-cleanup validation
2252
+ self.rich_console.print_info("Performing post-cleanup validation...")
2253
+ post_validation = self._perform_post_cleanup_validation(config.vpc_id)
2254
+
2255
+ return OperationResult(
2256
+ operation_id=self.context.operation_id,
2257
+ operation_type="AWSO5_ACTUAL_CLEANUP",
2258
+ status=status,
2259
+ message=message,
2260
+ details={
2261
+ 'vpc_id': config.vpc_id,
2262
+ 'cleanup_plan': plan.__dict__,
2263
+ 'execution_results': execution_results,
2264
+ 'failed_steps': failed_steps,
2265
+ 'post_validation': post_validation,
2266
+ 'execution_mode': 'ACTUAL'
2267
+ }
2268
+ )
2269
+
2270
+ except Exception as e:
2271
+ error_msg = f"Critical cleanup error: {str(e)}"
2272
+ logger.exception(error_msg)
2273
+
2274
+ return OperationResult(
2275
+ operation_id=self.context.operation_id,
2276
+ operation_type="AWSO5_CLEANUP_ERROR",
2277
+ status=OperationStatus.FAILED,
2278
+ message=error_msg,
2279
+ details={
2280
+ 'vpc_id': config.vpc_id,
2281
+ 'error_type': type(e).__name__,
2282
+ 'partial_results': execution_results
2283
+ }
2284
+ )
2285
+
2286
+ def _execute_cleanup_step(self, step: Dict[str, Any], config: VPCCleanupConfiguration) -> Dict[str, Any]:
2287
+ """Execute a single cleanup step with AWS API calls."""
2288
+
2289
+ resource_type = step['resource_type']
2290
+ resource_id = step['resource_id']
2291
+
2292
+ try:
2293
+ if resource_type == 'NatGateway':
2294
+ self.context.session.client('ec2').delete_nat_gateway(NatGatewayId=resource_id)
2295
+
2296
+ elif resource_type == 'InternetGateway':
2297
+ ec2 = self.context.session.client('ec2')
2298
+ # First detach, then delete
2299
+ ec2.detach_internet_gateway(InternetGatewayId=resource_id, VpcId=config.vpc_id)
2300
+ ec2.delete_internet_gateway(InternetGatewayId=resource_id)
2301
+
2302
+ elif resource_type == 'RouteTable':
2303
+ ec2 = self.context.session.client('ec2')
2304
+ # Disassociate first, then delete
2305
+ route_tables = ec2.describe_route_tables(RouteTableIds=[resource_id])['RouteTables']
2306
+ for rt in route_tables:
2307
+ for assoc in rt.get('Associations', []):
2308
+ if not assoc.get('Main'):
2309
+ ec2.disassociate_route_table(AssociationId=assoc['RouteTableAssociationId'])
2310
+ ec2.delete_route_table(RouteTableId=resource_id)
2311
+
2312
+ elif resource_type == 'VpcEndpoint':
2313
+ self.context.session.client('ec2').delete_vpc_endpoints(VpcEndpointIds=[resource_id])
2314
+
2315
+ elif resource_type == 'TransitGatewayAttachment':
2316
+ self.context.session.client('ec2').delete_transit_gateway_vpc_attachment(
2317
+ TransitGatewayAttachmentId=resource_id
2318
+ )
2319
+
2320
+ elif resource_type == 'VpcPeeringConnection':
2321
+ self.context.session.client('ec2').delete_vpc_peering_connection(
2322
+ VpcPeeringConnectionId=resource_id
2323
+ )
2324
+
2325
+ elif resource_type == 'LoadBalancer':
2326
+ self.context.session.client('elbv2').delete_load_balancer(LoadBalancerArn=resource_id)
2327
+
2328
+ elif resource_type == 'SecurityGroup':
2329
+ self.context.session.client('ec2').delete_security_group(GroupId=resource_id)
2330
+
2331
+ elif resource_type == 'NetworkAcl':
2332
+ self.context.session.client('ec2').delete_network_acl(NetworkAclId=resource_id)
2333
+
2334
+ elif resource_type == 'FlowLog':
2335
+ self.context.session.client('ec2').delete_flow_logs(FlowLogIds=[resource_id])
2336
+
2337
+ elif resource_type == 'VPC':
2338
+ # Final VPC deletion
2339
+ self.context.session.client('ec2').delete_vpc(VpcId=resource_id)
2340
+
2341
+ else:
2342
+ return {
2343
+ 'success': False,
2344
+ 'resource_type': resource_type,
2345
+ 'resource_id': resource_id,
2346
+ 'error': f'Unknown resource type: {resource_type}'
2347
+ }
2348
+
2349
+ return {
2350
+ 'success': True,
2351
+ 'resource_type': resource_type,
2352
+ 'resource_id': resource_id,
2353
+ 'timestamp': datetime.utcnow().isoformat()
2354
+ }
2355
+
2356
+ except ClientError as e:
2357
+ return {
2358
+ 'success': False,
2359
+ 'resource_type': resource_type,
2360
+ 'resource_id': resource_id,
2361
+ 'error': f'AWS API Error: {e.response["Error"]["Code"]} - {e.response["Error"]["Message"]}'
2362
+ }
2363
+
2364
+ def _perform_post_cleanup_validation(self, vpc_id: str) -> Dict[str, Any]:
2365
+ """Perform post-cleanup validation to ensure VPC and dependencies are removed."""
2366
+
2367
+ validation_results = {
2368
+ 'vpc_exists': False,
2369
+ 'dependencies_remaining': [],
2370
+ 'validation_timestamp': datetime.utcnow().isoformat(),
2371
+ 'validation_passed': False
2372
+ }
2373
+
2374
+ try:
2375
+ # Check if VPC still exists
2376
+ ec2 = self.context.session.client('ec2')
2377
+ try:
2378
+ response = ec2.describe_vpcs(VpcIds=[vpc_id])
2379
+ if response['Vpcs']:
2380
+ validation_results['vpc_exists'] = True
2381
+ self.rich_console.print_warning(f"⚠️ VPC {vpc_id} still exists")
2382
+ except ClientError as e:
2383
+ if 'InvalidVpcID.NotFound' in str(e):
2384
+ validation_results['vpc_exists'] = False
2385
+ self.rich_console.print_success(f"✅ VPC {vpc_id} successfully deleted")
2386
+ else:
2387
+ raise
2388
+
2389
+ # Check for remaining dependencies
2390
+ if not validation_results['vpc_exists']:
2391
+ validation_results['validation_passed'] = True
2392
+ self.rich_console.print_success("✅ Post-cleanup validation PASSED")
2393
+ else:
2394
+ # Re-run dependency analysis
2395
+ dependency_result = self.dependency_analyzer.analyze_vpc_dependencies(vpc_id)
2396
+ validation_results['dependencies_remaining'] = [
2397
+ dep.__dict__ for dep in dependency_result.dependencies
2398
+ ]
2399
+ validation_results['validation_passed'] = len(dependency_result.dependencies) == 0
2400
+
2401
+ if validation_results['validation_passed']:
2402
+ self.rich_console.print_success("✅ Post-cleanup validation PASSED - No dependencies remain")
2403
+ else:
2404
+ self.rich_console.print_warning(f"⚠️ {len(dependency_result.dependencies)} dependencies still exist")
2405
+
2406
+ except Exception as e:
2407
+ validation_results['error'] = str(e)
2408
+ validation_results['validation_passed'] = False
2409
+ self.rich_console.print_error(f"❌ Post-cleanup validation failed: {str(e)}")
2410
+
2411
+ return validation_results
2412
+
2413
+ def _generate_evidence_bundle(
2414
+ self,
2415
+ dependency_result,
2416
+ cleanup_plan: VPCCleanupPlan,
2417
+ execution_result: OperationResult,
2418
+ evidence_bundle_path: Optional[str] = None
2419
+ ) -> Dict[str, Any]:
2420
+ """Generate comprehensive evidence bundle for AWSO-5 compliance."""
2421
+
2422
+ evidence_bundle = {
2423
+ 'metadata': {
2424
+ 'framework': 'AWSO-5',
2425
+ 'version': '1.0.0',
2426
+ 'vpc_id': cleanup_plan.vpc_id,
2427
+ 'timestamp': datetime.utcnow().isoformat(),
2428
+ 'analyst': 'AWSO5VPCCleanupOperation',
2429
+ 'operation_id': self.context.operation_id
2430
+ },
2431
+ 'pre_cleanup_analysis': dependency_result.__dict__,
2432
+ 'cleanup_plan': cleanup_plan.__dict__,
2433
+ 'execution_results': execution_result.details,
2434
+ 'evidence_artifacts': [],
2435
+ 'compliance_validation': {
2436
+ 'cis_benchmark_improvement': dependency_result.is_default,
2437
+ 'attack_surface_reduction': True if execution_result.status == OperationStatus.COMPLETED else False,
2438
+ 'security_posture_enhancement': len(dependency_result.dependencies) == 0
2439
+ }
2440
+ }
2441
+
2442
+ # Calculate evidence bundle hash
2443
+ import hashlib
2444
+ import json
2445
+ bundle_content = json.dumps(evidence_bundle, sort_keys=True, default=str)
2446
+ evidence_bundle['bundle_hash'] = hashlib.sha256(bundle_content.encode()).hexdigest()
2447
+
2448
+ # Save evidence bundle if path provided
2449
+ if evidence_bundle_path:
2450
+ with open(evidence_bundle_path, 'w') as f:
2451
+ json.dump(evidence_bundle, f, indent=2, default=str)
2452
+ self.rich_console.print_success(f"Evidence bundle saved: {evidence_bundle_path}")
2453
+
2454
+ self.rich_console.print_success(f"Evidence bundle generated with hash: {evidence_bundle['bundle_hash'][:16]}...")
2455
+
2456
+ return evidence_bundle
2457
+
2458
+
2459
+ def execute_vpc_cleanup(
2460
+ vpc_id: str,
2461
+ profile: Optional[str] = None,
2462
+ region: str = "us-east-1",
2463
+ dry_run: bool = True,
2464
+ approval_token: Optional[str] = None,
2465
+ evidence_bundle_path: Optional[str] = None
2466
+ ) -> List[OperationResult]:
2467
+ """
2468
+ CLI wrapper for AWSO-5 VPC cleanup operation.
2469
+
2470
+ Args:
2471
+ vpc_id: AWS VPC identifier to cleanup
2472
+ profile: AWS profile name
2473
+ region: AWS region
2474
+ dry_run: Execute in dry-run mode (default: True)
2475
+ approval_token: Platform lead approval token
2476
+ evidence_bundle_path: Path to save evidence bundle
2477
+
2478
+ Returns:
2479
+ Operation results with comprehensive cleanup information
2480
+ """
2481
+ session = boto3.Session(profile_name=profile) if profile else boto3.Session()
2482
+
2483
+ # Create operation context
2484
+ context = OperationContext(
2485
+ operation_id=f"awso5-cleanup-{vpc_id}-{int(datetime.utcnow().timestamp())}",
2486
+ region=region,
2487
+ session=session,
2488
+ dry_run=dry_run
2489
+ )
2490
+
2491
+ # Create cleanup configuration
2492
+ config = VPCCleanupConfiguration(
2493
+ vpc_id=vpc_id,
2494
+ dry_run=dry_run,
2495
+ approval_token=approval_token,
2496
+ evidence_collection=True
2497
+ )
2498
+
2499
+ # Execute cleanup operation
2500
+ cleanup_operation = AWSO5VPCCleanupOperation(context)
2501
+ return cleanup_operation.execute_vpc_cleanup(config, evidence_bundle_path)