runbooks 1.1.4__py3-none-any.whl → 1.1.6__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 (273) 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 +135 -91
  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 +17 -12
  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 +99 -79
  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 +315 -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/aws_decorators.py +2 -3
  113. runbooks/inventory/check_cloudtrail_compliance.py +2 -4
  114. runbooks/inventory/check_controltower_readiness.py +152 -151
  115. runbooks/inventory/check_landingzone_readiness.py +85 -84
  116. runbooks/inventory/cloud_foundations_integration.py +144 -149
  117. runbooks/inventory/collectors/aws_comprehensive.py +1 -1
  118. runbooks/inventory/collectors/aws_networking.py +109 -99
  119. runbooks/inventory/collectors/base.py +4 -0
  120. runbooks/inventory/core/collector.py +495 -313
  121. runbooks/inventory/core/formatter.py +11 -0
  122. runbooks/inventory/draw_org_structure.py +8 -9
  123. runbooks/inventory/drift_detection_cli.py +69 -96
  124. runbooks/inventory/ec2_vpc_utils.py +2 -2
  125. runbooks/inventory/find_cfn_drift_detection.py +5 -7
  126. runbooks/inventory/find_cfn_orphaned_stacks.py +7 -9
  127. runbooks/inventory/find_cfn_stackset_drift.py +5 -6
  128. runbooks/inventory/find_ec2_security_groups.py +48 -42
  129. runbooks/inventory/find_landingzone_versions.py +4 -6
  130. runbooks/inventory/find_vpc_flow_logs.py +7 -9
  131. runbooks/inventory/inventory_mcp_cli.py +48 -46
  132. runbooks/inventory/inventory_modules.py +103 -91
  133. runbooks/inventory/list_cfn_stacks.py +9 -10
  134. runbooks/inventory/list_cfn_stackset_operation_results.py +1 -3
  135. runbooks/inventory/list_cfn_stackset_operations.py +79 -57
  136. runbooks/inventory/list_cfn_stacksets.py +8 -10
  137. runbooks/inventory/list_config_recorders_delivery_channels.py +49 -39
  138. runbooks/inventory/list_ds_directories.py +65 -53
  139. runbooks/inventory/list_ec2_availability_zones.py +2 -4
  140. runbooks/inventory/list_ec2_ebs_volumes.py +32 -35
  141. runbooks/inventory/list_ec2_instances.py +23 -28
  142. runbooks/inventory/list_ecs_clusters_and_tasks.py +26 -34
  143. runbooks/inventory/list_elbs_load_balancers.py +22 -20
  144. runbooks/inventory/list_enis_network_interfaces.py +26 -33
  145. runbooks/inventory/list_guardduty_detectors.py +2 -4
  146. runbooks/inventory/list_iam_policies.py +2 -4
  147. runbooks/inventory/list_iam_roles.py +5 -7
  148. runbooks/inventory/list_iam_saml_providers.py +4 -6
  149. runbooks/inventory/list_lambda_functions.py +38 -38
  150. runbooks/inventory/list_org_accounts.py +6 -8
  151. runbooks/inventory/list_org_accounts_users.py +55 -44
  152. runbooks/inventory/list_rds_db_instances.py +31 -33
  153. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  154. runbooks/inventory/list_route53_hosted_zones.py +3 -5
  155. runbooks/inventory/list_servicecatalog_provisioned_products.py +37 -41
  156. runbooks/inventory/list_sns_topics.py +2 -4
  157. runbooks/inventory/list_ssm_parameters.py +4 -7
  158. runbooks/inventory/list_vpc_subnets.py +2 -4
  159. runbooks/inventory/list_vpcs.py +7 -10
  160. runbooks/inventory/mcp_inventory_validator.py +554 -468
  161. runbooks/inventory/mcp_vpc_validator.py +359 -442
  162. runbooks/inventory/organizations_discovery.py +63 -55
  163. runbooks/inventory/recover_cfn_stack_ids.py +7 -8
  164. runbooks/inventory/requirements.txt +0 -1
  165. runbooks/inventory/rich_inventory_display.py +35 -34
  166. runbooks/inventory/run_on_multi_accounts.py +3 -5
  167. runbooks/inventory/unified_validation_engine.py +281 -253
  168. runbooks/inventory/verify_ec2_security_groups.py +1 -1
  169. runbooks/inventory/vpc_analyzer.py +735 -697
  170. runbooks/inventory/vpc_architecture_validator.py +293 -348
  171. runbooks/inventory/vpc_dependency_analyzer.py +384 -380
  172. runbooks/inventory/vpc_flow_analyzer.py +1 -1
  173. runbooks/main.py +49 -34
  174. runbooks/main_final.py +91 -60
  175. runbooks/main_minimal.py +22 -10
  176. runbooks/main_optimized.py +131 -100
  177. runbooks/main_ultra_minimal.py +7 -2
  178. runbooks/mcp/__init__.py +36 -0
  179. runbooks/mcp/integration.py +679 -0
  180. runbooks/monitoring/performance_monitor.py +9 -4
  181. runbooks/operate/dynamodb_operations.py +3 -1
  182. runbooks/operate/ec2_operations.py +145 -137
  183. runbooks/operate/iam_operations.py +146 -152
  184. runbooks/operate/networking_cost_heatmap.py +29 -8
  185. runbooks/operate/rds_operations.py +223 -254
  186. runbooks/operate/s3_operations.py +107 -118
  187. runbooks/operate/vpc_operations.py +646 -616
  188. runbooks/remediation/base.py +1 -1
  189. runbooks/remediation/commons.py +10 -7
  190. runbooks/remediation/commvault_ec2_analysis.py +70 -66
  191. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  192. runbooks/remediation/multi_account.py +24 -21
  193. runbooks/remediation/rds_snapshot_list.py +86 -60
  194. runbooks/remediation/remediation_cli.py +92 -146
  195. runbooks/remediation/universal_account_discovery.py +83 -79
  196. runbooks/remediation/workspaces_list.py +46 -41
  197. runbooks/security/__init__.py +19 -0
  198. runbooks/security/assessment_runner.py +1150 -0
  199. runbooks/security/baseline_checker.py +812 -0
  200. runbooks/security/cloudops_automation_security_validator.py +509 -535
  201. runbooks/security/compliance_automation_engine.py +17 -17
  202. runbooks/security/config/__init__.py +2 -2
  203. runbooks/security/config/compliance_config.py +50 -50
  204. runbooks/security/config_template_generator.py +63 -76
  205. runbooks/security/enterprise_security_framework.py +1 -1
  206. runbooks/security/executive_security_dashboard.py +519 -508
  207. runbooks/security/multi_account_security_controls.py +959 -1210
  208. runbooks/security/real_time_security_monitor.py +422 -444
  209. runbooks/security/security_baseline_tester.py +1 -1
  210. runbooks/security/security_cli.py +143 -112
  211. runbooks/security/test_2way_validation.py +439 -0
  212. runbooks/security/two_way_validation_framework.py +852 -0
  213. runbooks/sre/production_monitoring_framework.py +167 -177
  214. runbooks/tdd/__init__.py +15 -0
  215. runbooks/tdd/cli.py +1071 -0
  216. runbooks/utils/__init__.py +14 -17
  217. runbooks/utils/logger.py +7 -2
  218. runbooks/utils/version_validator.py +50 -47
  219. runbooks/validation/__init__.py +6 -6
  220. runbooks/validation/cli.py +9 -3
  221. runbooks/validation/comprehensive_2way_validator.py +745 -704
  222. runbooks/validation/mcp_validator.py +906 -228
  223. runbooks/validation/terraform_citations_validator.py +104 -115
  224. runbooks/validation/terraform_drift_detector.py +461 -454
  225. runbooks/vpc/README.md +617 -0
  226. runbooks/vpc/__init__.py +8 -1
  227. runbooks/vpc/analyzer.py +577 -0
  228. runbooks/vpc/cleanup_wrapper.py +476 -413
  229. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  230. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  231. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  232. runbooks/vpc/config.py +92 -97
  233. runbooks/vpc/cost_engine.py +411 -148
  234. runbooks/vpc/cost_explorer_integration.py +553 -0
  235. runbooks/vpc/cross_account_session.py +101 -106
  236. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  237. runbooks/vpc/eni_gate_validator.py +961 -0
  238. runbooks/vpc/heatmap_engine.py +185 -160
  239. runbooks/vpc/mcp_no_eni_validator.py +680 -639
  240. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  241. runbooks/vpc/networking_wrapper.py +15 -8
  242. runbooks/vpc/pdca_remediation_planner.py +528 -0
  243. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  244. runbooks/vpc/runbooks_adapter.py +1167 -241
  245. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  246. runbooks/vpc/test_data_loader.py +358 -0
  247. runbooks/vpc/tests/conftest.py +314 -4
  248. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  249. runbooks/vpc/tests/test_cost_engine.py +0 -2
  250. runbooks/vpc/topology_generator.py +326 -0
  251. runbooks/vpc/unified_scenarios.py +1297 -1124
  252. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  253. runbooks-1.1.6.dist-info/METADATA +327 -0
  254. runbooks-1.1.6.dist-info/RECORD +489 -0
  255. runbooks/finops/README.md +0 -414
  256. runbooks/finops/accuracy_cross_validator.py +0 -647
  257. runbooks/finops/business_cases.py +0 -950
  258. runbooks/finops/dashboard_router.py +0 -922
  259. runbooks/finops/ebs_optimizer.py +0 -973
  260. runbooks/finops/embedded_mcp_validator.py +0 -1629
  261. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  262. runbooks/finops/finops_dashboard.py +0 -584
  263. runbooks/finops/finops_scenarios.py +0 -1218
  264. runbooks/finops/legacy_migration.py +0 -730
  265. runbooks/finops/multi_dashboard.py +0 -1519
  266. runbooks/finops/single_dashboard.py +0 -1113
  267. runbooks/finops/unlimited_scenarios.py +0 -393
  268. runbooks-1.1.4.dist-info/METADATA +0 -800
  269. runbooks-1.1.4.dist-info/RECORD +0 -468
  270. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/WHEEL +0 -0
  271. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/entry_points.txt +0 -0
  272. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/licenses/LICENSE +0 -0
  273. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/top_level.txt +0 -0
@@ -2,9 +2,9 @@
2
2
  Enterprise Security Module - Enhanced Security Logging & VPC Security Assessment
3
3
  ===============================================================================
4
4
 
5
- Enterprise-grade security module providing enhanced security logging, VPC security
5
+ Enterprise-grade security module providing enhanced security logging, VPC security
6
6
  assessment, compliance framework integration, and risk classification for the
7
- CloudOps Runbooks platform. This module integrates with the three-bucket VPC
7
+ CloudOps Runbooks platform. This module integrates with the three-bucket VPC
8
8
  cleanup strategy and provides comprehensive security audit trails.
9
9
 
10
10
  Key Features:
@@ -37,14 +37,14 @@ from botocore.exceptions import ClientError, NoCredentialsError
37
37
  from runbooks.common.rich_utils import (
38
38
  console,
39
39
  create_panel,
40
- create_progress_bar,
40
+ create_progress_bar,
41
41
  create_table,
42
42
  print_error,
43
43
  print_info,
44
44
  print_success,
45
45
  print_warning,
46
46
  STATUS_INDICATORS,
47
- CLOUDOPS_THEME
47
+ CLOUDOPS_THEME,
48
48
  )
49
49
 
50
50
  # Profile management integration
@@ -58,16 +58,16 @@ except ImportError:
58
58
 
59
59
  class SecurityRiskLevel(Enum):
60
60
  """Security risk classification levels for enterprise decision making."""
61
-
61
+
62
62
  LOW = "LOW"
63
- MEDIUM = "MEDIUM"
63
+ MEDIUM = "MEDIUM"
64
64
  HIGH = "HIGH"
65
65
  CRITICAL = "CRITICAL"
66
66
 
67
67
 
68
68
  class ComplianceFramework(Enum):
69
69
  """Supported compliance frameworks for enterprise validation."""
70
-
70
+
71
71
  SOC2 = "SOC2"
72
72
  PCI_DSS = "PCI-DSS"
73
73
  HIPAA = "HIPAA"
@@ -79,7 +79,7 @@ class ComplianceFramework(Enum):
79
79
 
80
80
  class VPCSecurityAnalysis:
81
81
  """VPC Security Analysis results for cleanup integration."""
82
-
82
+
83
83
  def __init__(self, vpc_id: str, region: str):
84
84
  self.vpc_id = vpc_id
85
85
  self.region = region
@@ -91,7 +91,7 @@ class VPCSecurityAnalysis:
91
91
  self.findings: List[Dict[str, Any]] = []
92
92
  self.risk_level = SecurityRiskLevel.LOW
93
93
  self.compliance_status: Dict[str, bool] = {}
94
-
94
+
95
95
  def add_finding(self, severity: str, title: str, description: str, resource: str):
96
96
  """Add a security finding to the analysis."""
97
97
  finding = {
@@ -100,10 +100,10 @@ class VPCSecurityAnalysis:
100
100
  "description": description,
101
101
  "resource": resource,
102
102
  "timestamp": datetime.now(timezone.utc).isoformat(),
103
- "vpc_id": self.vpc_id
103
+ "vpc_id": self.vpc_id,
104
104
  }
105
105
  self.findings.append(finding)
106
-
106
+
107
107
  # Update overall risk level based on findings
108
108
  if severity == "HIGH" or severity == "CRITICAL":
109
109
  if self.risk_level in [SecurityRiskLevel.LOW, SecurityRiskLevel.MEDIUM]:
@@ -114,11 +114,11 @@ class VPCSecurityAnalysis:
114
114
 
115
115
  class EnterpriseSecurityLogger:
116
116
  """Enhanced security logger with enterprise audit trails and Rich CLI integration."""
117
-
117
+
118
118
  def __init__(self, module_name: str, log_dir: Optional[Path] = None):
119
119
  """
120
120
  Initialize enterprise security logger.
121
-
121
+
122
122
  Args:
123
123
  module_name: Name of the module requesting logging
124
124
  log_dir: Optional directory for security logs
@@ -126,33 +126,33 @@ class EnterpriseSecurityLogger:
126
126
  self.module_name = module_name
127
127
  self.log_dir = log_dir or Path.home() / ".runbooks" / "security-logs"
128
128
  self.log_dir.mkdir(parents=True, exist_ok=True)
129
-
129
+
130
130
  # Create security-specific log file
131
131
  self.log_file = self.log_dir / f"{module_name}-security-{datetime.now().strftime('%Y%m%d')}.jsonl"
132
-
132
+
133
133
  # Initialize standard logger as fallback
134
134
  self.logger = logging.getLogger(f"runbooks.security.{module_name}")
135
135
  self.logger.setLevel(logging.INFO)
136
-
136
+
137
137
  if not self.logger.handlers:
138
138
  # Console handler with Rich CLI integration
139
139
  console_handler = logging.StreamHandler()
140
- console_handler.setFormatter(logging.Formatter(
141
- f"{STATUS_INDICATORS['info']} %(asctime)s | SECURITY | %(message)s"
142
- ))
140
+ console_handler.setFormatter(
141
+ logging.Formatter(f"{STATUS_INDICATORS['info']} %(asctime)s | SECURITY | %(message)s")
142
+ )
143
143
  self.logger.addHandler(console_handler)
144
-
144
+
145
145
  # File handler for audit trails
146
146
  file_handler = logging.FileHandler(self.log_file)
147
- file_handler.setFormatter(logging.Formatter(
148
- '%(asctime)s | %(levelname)s | SECURITY | %(name)s | %(message)s'
149
- ))
147
+ file_handler.setFormatter(
148
+ logging.Formatter("%(asctime)s | %(levelname)s | SECURITY | %(name)s | %(message)s")
149
+ )
150
150
  self.logger.addHandler(file_handler)
151
-
151
+
152
152
  def log_security_event(self, event_type: str, message: str, metadata: Optional[Dict[str, Any]] = None):
153
153
  """
154
154
  Log a security event with comprehensive audit trail.
155
-
155
+
156
156
  Args:
157
157
  event_type: Type of security event (VPC_ANALYSIS, COMPLIANCE_CHECK, etc.)
158
158
  message: Human-readable message
@@ -164,23 +164,23 @@ class EnterpriseSecurityLogger:
164
164
  "event_type": event_type,
165
165
  "message": message,
166
166
  "metadata": metadata or {},
167
- "correlation_id": self._generate_correlation_id()
167
+ "correlation_id": self._generate_correlation_id(),
168
168
  }
169
-
169
+
170
170
  # Generate SHA256 hash for tamper detection
171
171
  event_hash = self._generate_event_hash(security_event)
172
172
  security_event["event_hash"] = event_hash
173
-
173
+
174
174
  # Write to audit file
175
- with open(self.log_file, 'a') as f:
176
- f.write(json.dumps(security_event) + '\n')
177
-
175
+ with open(self.log_file, "a") as f:
176
+ f.write(json.dumps(security_event) + "\n")
177
+
178
178
  # Rich CLI output
179
179
  console.print(f"{STATUS_INDICATORS['info']} [security]SECURITY[/security] | {event_type} | {message}")
180
-
180
+
181
181
  # Standard logger
182
182
  self.logger.info(f"{event_type} | {message} | Hash: {event_hash[:8]}...")
183
-
183
+
184
184
  def log_vpc_security_analysis(self, analysis: VPCSecurityAnalysis):
185
185
  """Log VPC security analysis results."""
186
186
  self.log_security_event(
@@ -194,21 +194,22 @@ class EnterpriseSecurityLogger:
194
194
  "compliance_status": analysis.compliance_status,
195
195
  "security_groups_count": len(analysis.security_groups),
196
196
  "nacls_count": len(analysis.nacls),
197
- "flow_logs_enabled": len(analysis.flow_logs) > 0
198
- }
197
+ "flow_logs_enabled": len(analysis.flow_logs) > 0,
198
+ },
199
199
  )
200
-
200
+
201
201
  def _generate_correlation_id(self) -> str:
202
202
  """Generate unique correlation ID for tracking operations."""
203
203
  import uuid
204
+
204
205
  return str(uuid.uuid4())[:8]
205
-
206
+
206
207
  def _generate_event_hash(self, event_data: Dict[str, Any]) -> str:
207
208
  """Generate SHA256 hash for security event integrity."""
208
209
  # Remove hash field if present to avoid circular reference
209
210
  event_copy = event_data.copy()
210
211
  event_copy.pop("event_hash", None)
211
-
212
+
212
213
  # Create deterministic string representation
213
214
  event_string = json.dumps(event_copy, sort_keys=True)
214
215
  return hashlib.sha256(event_string.encode()).hexdigest()
@@ -217,13 +218,13 @@ class EnterpriseSecurityLogger:
217
218
  def get_enhanced_logger(module_name: str) -> EnterpriseSecurityLogger:
218
219
  """
219
220
  Get enhanced security logger for enterprise audit trails.
220
-
221
+
221
222
  This is the main function called by VPC cleanup and other modules
222
223
  that need enhanced security logging capabilities.
223
-
224
+
224
225
  Args:
225
226
  module_name: Name of the requesting module
226
-
227
+
227
228
  Returns:
228
229
  EnterpriseSecurityLogger instance with audit trail capabilities
229
230
  """
@@ -233,111 +234,112 @@ def get_enhanced_logger(module_name: str) -> EnterpriseSecurityLogger:
233
234
  def assess_vpc_security_posture(vpc_id: str, profile: str, region: str = "us-east-1") -> VPCSecurityAnalysis:
234
235
  """
235
236
  Comprehensive VPC security posture assessment.
236
-
237
+
237
238
  Analyzes VPC security configuration including Security Groups, NACLs,
238
239
  Flow Logs, and route tables to identify security risks and compliance
239
240
  issues before VPC cleanup operations.
240
-
241
+
241
242
  Args:
242
243
  vpc_id: VPC ID to analyze
243
244
  profile: AWS profile for authentication
244
245
  region: AWS region (default: us-east-1)
245
-
246
+
246
247
  Returns:
247
248
  VPCSecurityAnalysis object with comprehensive security findings
248
249
  """
249
250
  console.print(f"{STATUS_INDICATORS['running']} [security]Assessing VPC security posture for {vpc_id}[/security]")
250
-
251
+
251
252
  analysis = VPCSecurityAnalysis(vpc_id, region)
252
-
253
+
253
254
  try:
254
255
  # Create AWS session with specified profile
255
256
  session = create_session(profile)
256
- ec2 = session.client('ec2', region_name=region)
257
-
257
+ ec2 = session.client("ec2", region_name=region)
258
+
258
259
  with create_progress_bar() as progress:
259
260
  task = progress.add_task("[security]Security Assessment[/security]", total=4)
260
-
261
+
261
262
  # 1. Analyze Security Groups
262
263
  progress.update(task, description="[security]Analyzing Security Groups[/security]")
263
264
  security_groups = _analyze_security_groups(ec2, vpc_id, analysis)
264
265
  analysis.security_groups = security_groups
265
266
  progress.advance(task)
266
-
267
+
267
268
  # 2. Analyze Network ACLs
268
269
  progress.update(task, description="[security]Analyzing Network ACLs[/security]")
269
270
  nacls = _analyze_network_acls(ec2, vpc_id, analysis)
270
271
  analysis.nacls = nacls
271
272
  progress.advance(task)
272
-
273
+
273
274
  # 3. Check VPC Flow Logs
274
275
  progress.update(task, description="[security]Checking VPC Flow Logs[/security]")
275
276
  flow_logs = _analyze_flow_logs(ec2, vpc_id, analysis)
276
277
  analysis.flow_logs = flow_logs
277
278
  progress.advance(task)
278
-
279
+
279
280
  # 4. Analyze Route Tables
280
281
  progress.update(task, description="[security]Analyzing Route Tables[/security]")
281
282
  route_tables = _analyze_route_tables(ec2, vpc_id, analysis)
282
283
  analysis.route_tables = route_tables
283
284
  progress.advance(task)
284
-
285
+
285
286
  # Log the security analysis
286
287
  logger = get_enhanced_logger("vpc_cleanup")
287
288
  logger.log_vpc_security_analysis(analysis)
288
-
289
+
289
290
  # Display results with Rich CLI
290
291
  _display_security_analysis_results(analysis)
291
-
292
- console.print(f"{STATUS_INDICATORS['success']} [security]VPC security assessment completed - Risk: {analysis.risk_level.value}[/security]")
293
-
292
+
293
+ console.print(
294
+ f"{STATUS_INDICATORS['success']} [security]VPC security assessment completed - Risk: {analysis.risk_level.value}[/security]"
295
+ )
296
+
294
297
  except ClientError as e:
295
298
  error_msg = f"AWS API error during VPC security assessment: {e}"
296
299
  console.print(f"{STATUS_INDICATORS['error']} [error]{error_msg}[/error]")
297
300
  analysis.add_finding("HIGH", "API Access Error", error_msg, vpc_id)
298
-
301
+
299
302
  except Exception as e:
300
303
  error_msg = f"Unexpected error during VPC security assessment: {e}"
301
304
  console.print(f"{STATUS_INDICATORS['error']} [error]{error_msg}[/error]")
302
305
  analysis.add_finding("MEDIUM", "Assessment Error", error_msg, vpc_id)
303
-
306
+
304
307
  return analysis
305
308
 
306
309
 
307
- def validate_compliance_requirements(
308
- resource_data: Dict[str, Any],
309
- frameworks: List[str]
310
- ) -> Dict[str, bool]:
310
+ def validate_compliance_requirements(resource_data: Dict[str, Any], frameworks: List[str]) -> Dict[str, bool]:
311
311
  """
312
312
  Validate resource configuration against compliance frameworks.
313
-
313
+
314
314
  Args:
315
315
  resource_data: Resource configuration data to validate
316
316
  frameworks: List of compliance frameworks to check against
317
-
317
+
318
318
  Returns:
319
319
  Dict mapping framework names to compliance status (True/False)
320
320
  """
321
321
  compliance_results = {}
322
-
322
+
323
323
  for framework in frameworks:
324
324
  try:
325
- framework_enum = ComplianceFramework(framework.upper().replace('-', '_'))
325
+ framework_enum = ComplianceFramework(framework.upper().replace("-", "_"))
326
326
  compliance_results[framework] = _check_framework_compliance(resource_data, framework_enum)
327
327
  except ValueError:
328
- console.print(f"{STATUS_INDICATORS['warning']} [warning]Unknown compliance framework: {framework}[/warning]")
328
+ console.print(
329
+ f"{STATUS_INDICATORS['warning']} [warning]Unknown compliance framework: {framework}[/warning]"
330
+ )
329
331
  compliance_results[framework] = False
330
-
332
+
331
333
  return compliance_results
332
334
 
333
335
 
334
336
  def evaluate_security_baseline(analysis_results: Dict[str, Any]) -> Dict[str, Any]:
335
337
  """
336
338
  Evaluate security baseline from analysis results.
337
-
339
+
338
340
  Args:
339
341
  analysis_results: Combined analysis results from VPC assessment
340
-
342
+
341
343
  Returns:
342
344
  Security baseline evaluation with recommendations
343
345
  """
@@ -346,25 +348,25 @@ def evaluate_security_baseline(analysis_results: Dict[str, Any]) -> Dict[str, An
346
348
  "max_score": 100,
347
349
  "recommendations": [],
348
350
  "critical_findings": [],
349
- "compliance_gaps": []
351
+ "compliance_gaps": [],
350
352
  }
351
-
353
+
352
354
  # Security Groups baseline (25 points)
353
- sg_score = _evaluate_security_groups_baseline(analysis_results.get('security_groups', []))
355
+ sg_score = _evaluate_security_groups_baseline(analysis_results.get("security_groups", []))
354
356
  baseline_evaluation["baseline_score"] += sg_score
355
-
357
+
356
358
  # Network ACLs baseline (25 points)
357
- nacl_score = _evaluate_nacls_baseline(analysis_results.get('nacls', []))
359
+ nacl_score = _evaluate_nacls_baseline(analysis_results.get("nacls", []))
358
360
  baseline_evaluation["baseline_score"] += nacl_score
359
-
361
+
360
362
  # Flow Logs baseline (25 points)
361
- flow_logs_score = _evaluate_flow_logs_baseline(analysis_results.get('flow_logs', []))
363
+ flow_logs_score = _evaluate_flow_logs_baseline(analysis_results.get("flow_logs", []))
362
364
  baseline_evaluation["baseline_score"] += flow_logs_score
363
-
365
+
364
366
  # Route Tables baseline (25 points)
365
- route_tables_score = _evaluate_route_tables_baseline(analysis_results.get('route_tables', []))
367
+ route_tables_score = _evaluate_route_tables_baseline(analysis_results.get("route_tables", []))
366
368
  baseline_evaluation["baseline_score"] += route_tables_score
367
-
369
+
368
370
  # Generate recommendations based on score
369
371
  if baseline_evaluation["baseline_score"] < 70:
370
372
  baseline_evaluation["recommendations"].append("Immediate security review required")
@@ -373,27 +375,27 @@ def evaluate_security_baseline(analysis_results: Dict[str, Any]) -> Dict[str, An
373
375
  baseline_evaluation["recommendations"].append("Security improvements recommended")
374
376
  else:
375
377
  baseline_evaluation["recommendations"].append("Security posture meets enterprise standards")
376
-
378
+
377
379
  return baseline_evaluation
378
380
 
379
381
 
380
382
  def classify_security_risk(resource_analysis: Dict[str, Any]) -> str:
381
383
  """
382
384
  Classify security risk level for enterprise decision making.
383
-
385
+
384
386
  Args:
385
387
  resource_analysis: Resource security analysis data
386
-
388
+
387
389
  Returns:
388
390
  Risk classification: LOW, MEDIUM, HIGH, or CRITICAL
389
391
  """
390
392
  risk_factors = []
391
-
393
+
392
394
  # Check for critical security misconfigurations
393
- findings = resource_analysis.get('findings', [])
394
- critical_count = len([f for f in findings if f.get('severity') == 'CRITICAL'])
395
- high_count = len([f for f in findings if f.get('severity') == 'HIGH'])
396
-
395
+ findings = resource_analysis.get("findings", [])
396
+ critical_count = len([f for f in findings if f.get("severity") == "CRITICAL"])
397
+ high_count = len([f for f in findings if f.get("severity") == "HIGH"])
398
+
397
399
  if critical_count > 0:
398
400
  return SecurityRiskLevel.CRITICAL.value
399
401
  elif high_count >= 3:
@@ -406,29 +408,28 @@ def classify_security_risk(resource_analysis: Dict[str, Any]) -> str:
406
408
 
407
409
  # Private helper functions for detailed security analysis
408
410
 
411
+
409
412
  def _analyze_security_groups(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -> List[Dict[str, Any]]:
410
413
  """Analyze Security Groups for security risks."""
411
414
  try:
412
- response = ec2_client.describe_security_groups(
413
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
414
- )
415
-
415
+ response = ec2_client.describe_security_groups(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
416
+
416
417
  security_groups = []
417
- for sg in response['SecurityGroups']:
418
+ for sg in response["SecurityGroups"]:
418
419
  sg_analysis = {
419
- 'group_id': sg['GroupId'],
420
- 'group_name': sg['GroupName'],
421
- 'description': sg['Description'],
422
- 'inbound_rules': sg.get('IpPermissions', []),
423
- 'outbound_rules': sg.get('IpPermissionsEgress', [])
420
+ "group_id": sg["GroupId"],
421
+ "group_name": sg["GroupName"],
422
+ "description": sg["Description"],
423
+ "inbound_rules": sg.get("IpPermissions", []),
424
+ "outbound_rules": sg.get("IpPermissionsEgress", []),
424
425
  }
425
-
426
+
426
427
  # Check for overly permissive rules
427
428
  _check_security_group_rules(sg, analysis)
428
429
  security_groups.append(sg_analysis)
429
-
430
+
430
431
  return security_groups
431
-
432
+
432
433
  except ClientError as e:
433
434
  analysis.add_finding("MEDIUM", "Security Groups Analysis Failed", str(e), vpc_id)
434
435
  return []
@@ -437,32 +438,30 @@ def _analyze_security_groups(ec2_client, vpc_id: str, analysis: VPCSecurityAnaly
437
438
  def _analyze_network_acls(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -> List[Dict[str, Any]]:
438
439
  """Analyze Network ACLs for security configuration."""
439
440
  try:
440
- response = ec2_client.describe_network_acls(
441
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
442
- )
443
-
441
+ response = ec2_client.describe_network_acls(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
442
+
444
443
  nacls = []
445
- for nacl in response['NetworkAcls']:
444
+ for nacl in response["NetworkAcls"]:
446
445
  nacl_analysis = {
447
- 'nacl_id': nacl['NetworkAclId'],
448
- 'is_default': nacl['IsDefault'],
449
- 'entries': nacl.get('Entries', []),
450
- 'associations': nacl.get('Associations', [])
446
+ "nacl_id": nacl["NetworkAclId"],
447
+ "is_default": nacl["IsDefault"],
448
+ "entries": nacl.get("Entries", []),
449
+ "associations": nacl.get("Associations", []),
451
450
  }
452
-
451
+
453
452
  # Check for default NACL usage (potential security risk)
454
- if nacl['IsDefault']:
453
+ if nacl["IsDefault"]:
455
454
  analysis.add_finding(
456
- "LOW",
455
+ "LOW",
457
456
  "Default NACL in use",
458
457
  "Consider creating custom NACLs for better security control",
459
- nacl['NetworkAclId']
458
+ nacl["NetworkAclId"],
460
459
  )
461
-
460
+
462
461
  nacls.append(nacl_analysis)
463
-
462
+
464
463
  return nacls
465
-
464
+
466
465
  except ClientError as e:
467
466
  analysis.add_finding("MEDIUM", "Network ACLs Analysis Failed", str(e), vpc_id)
468
467
  return []
@@ -472,33 +471,30 @@ def _analyze_flow_logs(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -
472
471
  """Check VPC Flow Logs configuration."""
473
472
  try:
474
473
  response = ec2_client.describe_flow_logs(
475
- Filters=[
476
- {'Name': 'resource-id', 'Values': [vpc_id]},
477
- {'Name': 'resource-type', 'Values': ['VPC']}
478
- ]
474
+ Filters=[{"Name": "resource-id", "Values": [vpc_id]}, {"Name": "resource-type", "Values": ["VPC"]}]
479
475
  )
480
-
481
- flow_logs = response.get('FlowLogs', [])
482
-
476
+
477
+ flow_logs = response.get("FlowLogs", [])
478
+
483
479
  if not flow_logs:
484
480
  analysis.add_finding(
485
481
  "MEDIUM",
486
482
  "VPC Flow Logs not enabled",
487
483
  "Enable VPC Flow Logs for network monitoring and security analysis",
488
- vpc_id
484
+ vpc_id,
489
485
  )
490
486
  else:
491
487
  for flow_log in flow_logs:
492
- if flow_log['FlowLogStatus'] != 'ACTIVE':
488
+ if flow_log["FlowLogStatus"] != "ACTIVE":
493
489
  analysis.add_finding(
494
490
  "MEDIUM",
495
491
  f"Flow Log {flow_log['FlowLogId']} not active",
496
492
  f"Flow Log status: {flow_log['FlowLogStatus']}",
497
- flow_log['FlowLogId']
493
+ flow_log["FlowLogId"],
498
494
  )
499
-
500
- return [{'flow_log_id': fl.get('FlowLogId'), 'status': fl.get('FlowLogStatus')} for fl in flow_logs]
501
-
495
+
496
+ return [{"flow_log_id": fl.get("FlowLogId"), "status": fl.get("FlowLogStatus")} for fl in flow_logs]
497
+
502
498
  except ClientError as e:
503
499
  analysis.add_finding("MEDIUM", "Flow Logs Analysis Failed", str(e), vpc_id)
504
500
  return []
@@ -507,34 +503,32 @@ def _analyze_flow_logs(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -
507
503
  def _analyze_route_tables(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -> List[Dict[str, Any]]:
508
504
  """Analyze Route Tables for security implications."""
509
505
  try:
510
- response = ec2_client.describe_route_tables(
511
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
512
- )
513
-
506
+ response = ec2_client.describe_route_tables(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
507
+
514
508
  route_tables = []
515
- for rt in response['RouteTables']:
509
+ for rt in response["RouteTables"]:
516
510
  rt_analysis = {
517
- 'route_table_id': rt['RouteTableId'],
518
- 'routes': rt.get('Routes', []),
519
- 'associations': rt.get('Associations', [])
511
+ "route_table_id": rt["RouteTableId"],
512
+ "routes": rt.get("Routes", []),
513
+ "associations": rt.get("Associations", []),
520
514
  }
521
-
515
+
522
516
  # Check for overly broad routes
523
- for route in rt.get('Routes', []):
524
- if route.get('DestinationCidrBlock') == '0.0.0.0/0':
525
- gateway_id = route.get('GatewayId', '')
526
- if gateway_id.startswith('igw-'):
517
+ for route in rt.get("Routes", []):
518
+ if route.get("DestinationCidrBlock") == "0.0.0.0/0":
519
+ gateway_id = route.get("GatewayId", "")
520
+ if gateway_id.startswith("igw-"):
527
521
  analysis.add_finding(
528
522
  "HIGH",
529
523
  "Public route detected",
530
524
  f"Route table {rt['RouteTableId']} has public internet access via {gateway_id}",
531
- rt['RouteTableId']
525
+ rt["RouteTableId"],
532
526
  )
533
-
527
+
534
528
  route_tables.append(rt_analysis)
535
-
529
+
536
530
  return route_tables
537
-
531
+
538
532
  except ClientError as e:
539
533
  analysis.add_finding("MEDIUM", "Route Tables Analysis Failed", str(e), vpc_id)
540
534
  return []
@@ -542,18 +536,18 @@ def _analyze_route_tables(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis
542
536
 
543
537
  def _check_security_group_rules(security_group: Dict[str, Any], analysis: VPCSecurityAnalysis):
544
538
  """Check Security Group rules for common security issues."""
545
- sg_id = security_group['GroupId']
546
-
539
+ sg_id = security_group["GroupId"]
540
+
547
541
  # Check inbound rules
548
- for rule in security_group.get('IpPermissions', []):
549
- for ip_range in rule.get('IpRanges', []):
550
- if ip_range.get('CidrIp') == '0.0.0.0/0':
542
+ for rule in security_group.get("IpPermissions", []):
543
+ for ip_range in rule.get("IpRanges", []):
544
+ if ip_range.get("CidrIp") == "0.0.0.0/0":
551
545
  ports = f"{rule.get('FromPort', 'All')}-{rule.get('ToPort', 'All')}"
552
546
  analysis.add_finding(
553
547
  "HIGH",
554
548
  "Overly permissive Security Group",
555
549
  f"Security Group {sg_id} allows inbound access from anywhere (0.0.0.0/0) on ports {ports}",
556
- sg_id
550
+ sg_id,
557
551
  )
558
552
 
559
553
 
@@ -561,40 +555,34 @@ def _check_framework_compliance(resource_data: Dict[str, Any], framework: Compli
561
555
  """Check resource compliance against specific framework."""
562
556
  if framework == ComplianceFramework.SOC2:
563
557
  # SOC2 requires logging and access controls
564
- return (
565
- resource_data.get('flow_logs_enabled', False) and
566
- len(resource_data.get('security_groups', [])) > 0
567
- )
558
+ return resource_data.get("flow_logs_enabled", False) and len(resource_data.get("security_groups", [])) > 0
568
559
  elif framework == ComplianceFramework.PCI_DSS:
569
560
  # PCI-DSS requires strict access controls
570
- findings = resource_data.get('findings', [])
571
- high_severity_findings = [f for f in findings if f.get('severity') in ['HIGH', 'CRITICAL']]
561
+ findings = resource_data.get("findings", [])
562
+ high_severity_findings = [f for f in findings if f.get("severity") in ["HIGH", "CRITICAL"]]
572
563
  return len(high_severity_findings) == 0
573
564
  elif framework == ComplianceFramework.HIPAA:
574
565
  # HIPAA requires encryption and access logging
575
- return (
576
- resource_data.get('flow_logs_enabled', False) and
577
- resource_data.get('baseline_score', 0) >= 85
578
- )
566
+ return resource_data.get("flow_logs_enabled", False) and resource_data.get("baseline_score", 0) >= 85
579
567
  else:
580
568
  # Default compliance check
581
- return resource_data.get('baseline_score', 0) >= 70
569
+ return resource_data.get("baseline_score", 0) >= 70
582
570
 
583
571
 
584
572
  def _evaluate_security_groups_baseline(security_groups: List[Dict[str, Any]]) -> int:
585
573
  """Evaluate Security Groups against security baseline (max 25 points)."""
586
574
  if not security_groups:
587
575
  return 0
588
-
576
+
589
577
  score = 25
590
578
  for sg in security_groups:
591
579
  # Check for overly permissive rules
592
- inbound_rules = sg.get('inbound_rules', [])
580
+ inbound_rules = sg.get("inbound_rules", [])
593
581
  for rule in inbound_rules:
594
- for ip_range in rule.get('IpRanges', []):
595
- if ip_range.get('CidrIp') == '0.0.0.0/0':
582
+ for ip_range in rule.get("IpRanges", []):
583
+ if ip_range.get("CidrIp") == "0.0.0.0/0":
596
584
  score -= 5 # Deduct points for open access
597
-
585
+
598
586
  return max(0, score)
599
587
 
600
588
 
@@ -602,12 +590,12 @@ def _evaluate_nacls_baseline(nacls: List[Dict[str, Any]]) -> int:
602
590
  """Evaluate Network ACLs against security baseline (max 25 points)."""
603
591
  if not nacls:
604
592
  return 10 # Partial score for having no custom NACLs
605
-
593
+
606
594
  score = 25
607
- default_nacl_count = len([n for n in nacls if n.get('is_default', False)])
595
+ default_nacl_count = len([n for n in nacls if n.get("is_default", False)])
608
596
  if default_nacl_count > 0:
609
597
  score -= 5 # Deduct for using default NACLs
610
-
598
+
611
599
  return max(10, score)
612
600
 
613
601
 
@@ -615,8 +603,8 @@ def _evaluate_flow_logs_baseline(flow_logs: List[Dict[str, Any]]) -> int:
615
603
  """Evaluate Flow Logs against security baseline (max 25 points)."""
616
604
  if not flow_logs:
617
605
  return 0 # No flow logs = no points
618
-
619
- active_flow_logs = len([fl for fl in flow_logs if fl.get('status') == 'ACTIVE'])
606
+
607
+ active_flow_logs = len([fl for fl in flow_logs if fl.get("status") == "ACTIVE"])
620
608
  return 25 if active_flow_logs > 0 else 10
621
609
 
622
610
 
@@ -624,37 +612,36 @@ def _evaluate_route_tables_baseline(route_tables: List[Dict[str, Any]]) -> int:
624
612
  """Evaluate Route Tables against security baseline (max 25 points)."""
625
613
  if not route_tables:
626
614
  return 0
627
-
615
+
628
616
  score = 25
629
617
  for rt in route_tables:
630
- for route in rt.get('routes', []):
631
- if (route.get('DestinationCidrBlock') == '0.0.0.0/0' and
632
- route.get('GatewayId', '').startswith('igw-')):
618
+ for route in rt.get("routes", []):
619
+ if route.get("DestinationCidrBlock") == "0.0.0.0/0" and route.get("GatewayId", "").startswith("igw-"):
633
620
  score -= 3 # Deduct for public routes
634
-
621
+
635
622
  return max(15, score)
636
623
 
637
624
 
638
625
  def _display_security_analysis_results(analysis: VPCSecurityAnalysis):
639
626
  """Display security analysis results with Rich CLI formatting."""
640
-
627
+
641
628
  # Create summary table
642
629
  table = create_table(
643
630
  title=f"VPC Security Analysis - {analysis.vpc_id}",
644
631
  columns=[
645
632
  {"name": "Component", "style": "cyan"},
646
633
  {"name": "Count", "style": "white"},
647
- {"name": "Status", "style": "green"}
648
- ]
634
+ {"name": "Status", "style": "green"},
635
+ ],
649
636
  )
650
-
637
+
651
638
  table.add_row("Security Groups", str(len(analysis.security_groups)), "✅ Analyzed")
652
639
  table.add_row("Network ACLs", str(len(analysis.nacls)), "✅ Analyzed")
653
640
  table.add_row("Flow Logs", str(len(analysis.flow_logs)), "✅ Checked" if analysis.flow_logs else "❌ Missing")
654
641
  table.add_row("Route Tables", str(len(analysis.route_tables)), "✅ Analyzed")
655
-
642
+
656
643
  console.print(table)
657
-
644
+
658
645
  # Display findings if any
659
646
  if analysis.findings:
660
647
  findings_table = create_table(
@@ -662,47 +649,43 @@ def _display_security_analysis_results(analysis: VPCSecurityAnalysis):
662
649
  columns=[
663
650
  {"name": "Severity", "style": "red bold"},
664
651
  {"name": "Finding", "style": "yellow"},
665
- {"name": "Resource", "style": "cyan"}
666
- ]
652
+ {"name": "Resource", "style": "cyan"},
653
+ ],
667
654
  )
668
-
655
+
669
656
  for finding in analysis.findings:
670
- findings_table.add_row(
671
- finding['severity'],
672
- finding['title'],
673
- finding['resource']
674
- )
675
-
657
+ findings_table.add_row(finding["severity"], finding["title"], finding["resource"])
658
+
676
659
  console.print(findings_table)
677
-
660
+
678
661
  # Risk level summary
679
662
  risk_style = {
680
663
  SecurityRiskLevel.LOW: "green",
681
- SecurityRiskLevel.MEDIUM: "yellow",
664
+ SecurityRiskLevel.MEDIUM: "yellow",
682
665
  SecurityRiskLevel.HIGH: "red",
683
- SecurityRiskLevel.CRITICAL: "red bold"
666
+ SecurityRiskLevel.CRITICAL: "red bold",
684
667
  }.get(analysis.risk_level, "white")
685
-
668
+
686
669
  risk_panel = create_panel(
687
670
  f"Overall Security Risk: [{risk_style}]{analysis.risk_level.value}[/{risk_style}]\n"
688
671
  f"Findings: {len(analysis.findings)}\n"
689
672
  f"Analysis Time: {analysis.timestamp.strftime('%Y-%m-%d %H:%M:%S UTC')}",
690
673
  title="[security]Security Risk Assessment[/security]",
691
- border_style=risk_style
674
+ border_style=risk_style,
692
675
  )
693
-
676
+
694
677
  console.print(risk_panel)
695
678
 
696
679
 
697
680
  # Export the main functions needed by VPC cleanup and other modules
698
681
  __all__ = [
699
682
  "get_enhanced_logger",
700
- "assess_vpc_security_posture",
683
+ "assess_vpc_security_posture",
701
684
  "validate_compliance_requirements",
702
685
  "evaluate_security_baseline",
703
686
  "classify_security_risk",
704
687
  "SecurityRiskLevel",
705
688
  "ComplianceFramework",
706
689
  "VPCSecurityAnalysis",
707
- "EnterpriseSecurityLogger"
708
- ]
690
+ "EnterpriseSecurityLogger",
691
+ ]