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
@@ -33,36 +33,36 @@ from runbooks.common.rich_utils import (
33
33
  print_success,
34
34
  print_warning,
35
35
  print_error,
36
- STATUS_INDICATORS
36
+ STATUS_INDICATORS,
37
37
  )
38
38
 
39
39
 
40
40
  class OperationType(Enum):
41
41
  """Classification of operation types for appropriate dry-run behavior."""
42
-
42
+
43
43
  # READ-ONLY Operations (inherently safe)
44
- DISCOVERY = "discovery" # inventory collect, scan
45
- ANALYSIS = "analysis" # finops dashboard, security assess, vpc analyze
46
- ASSESSMENT = "assessment" # cfat assess
47
- REPORTING = "reporting" # generate reports, export data
48
-
44
+ DISCOVERY = "discovery" # inventory collect, scan
45
+ ANALYSIS = "analysis" # finops dashboard, security assess, vpc analyze
46
+ ASSESSMENT = "assessment" # cfat assess
47
+ REPORTING = "reporting" # generate reports, export data
48
+
49
49
  # STATE-CHANGING Operations (require safety controls)
50
- RESOURCE_CREATE = "create" # EC2 instances, S3 buckets, VPCs
51
- RESOURCE_MODIFY = "modify" # Update configurations, scaling
52
- RESOURCE_DELETE = "delete" # Terminate, delete resources
53
- CONFIGURATION = "config" # Change settings, policies
54
- REMEDIATION = "remediation" # Security fixes, compliance actions
55
-
50
+ RESOURCE_CREATE = "create" # EC2 instances, S3 buckets, VPCs
51
+ RESOURCE_MODIFY = "modify" # Update configurations, scaling
52
+ RESOURCE_DELETE = "delete" # Terminate, delete resources
53
+ CONFIGURATION = "config" # Change settings, policies
54
+ REMEDIATION = "remediation" # Security fixes, compliance actions
55
+
56
56
  # HIGH-RISK Operations (explicit confirmation required)
57
- BULK_OPERATIONS = "bulk" # Multi-resource operations
58
- CROSS_ACCOUNT = "cross_account" # Operations affecting multiple accounts
59
- FINANCIAL = "financial" # Budget modifications, billing changes
57
+ BULK_OPERATIONS = "bulk" # Multi-resource operations
58
+ CROSS_ACCOUNT = "cross_account" # Operations affecting multiple accounts
59
+ FINANCIAL = "financial" # Budget modifications, billing changes
60
60
 
61
61
 
62
62
  @dataclass
63
63
  class DryRunContext:
64
64
  """Context information for dry-run operations."""
65
-
65
+
66
66
  enabled: bool
67
67
  operation_type: OperationType
68
68
  module_name: str
@@ -72,7 +72,7 @@ class DryRunContext:
72
72
  safety_level: str = "standard" # standard, high, critical
73
73
  requires_confirmation: bool = False
74
74
  audit_trail: List[Dict[str, Any]] = None
75
-
75
+
76
76
  def __post_init__(self):
77
77
  if self.audit_trail is None:
78
78
  self.audit_trail = []
@@ -81,79 +81,79 @@ class DryRunContext:
81
81
  class DryRunSafetyFramework:
82
82
  """
83
83
  Universal dry-run safety framework for enterprise operations.
84
-
84
+
85
85
  Provides consistent dry-run behavior, safety controls, and audit trails
86
86
  across all runbooks modules.
87
87
  """
88
-
88
+
89
89
  def __init__(self, console: Optional[Console] = None):
90
90
  self.console = console or Console()
91
91
  self.logger = logging.getLogger(__name__)
92
-
92
+
93
93
  # Safety configuration
94
94
  self.safety_configs = {
95
95
  OperationType.DISCOVERY: {
96
96
  "default_dry_run": False, # Discovery is inherently safe
97
97
  "requires_confirmation": False,
98
- "simulation_mode": True, # Can simulate API calls
99
- "warning_message": None
98
+ "simulation_mode": True, # Can simulate API calls
99
+ "warning_message": None,
100
100
  },
101
101
  OperationType.ANALYSIS: {
102
102
  "default_dry_run": False, # Analysis is read-only
103
103
  "requires_confirmation": False,
104
104
  "simulation_mode": False, # Real API calls for analysis
105
- "warning_message": None
105
+ "warning_message": None,
106
106
  },
107
107
  OperationType.ASSESSMENT: {
108
108
  "default_dry_run": False, # Assessment is read-only
109
109
  "requires_confirmation": False,
110
110
  "simulation_mode": False,
111
- "warning_message": None
111
+ "warning_message": None,
112
112
  },
113
113
  OperationType.RESOURCE_CREATE: {
114
- "default_dry_run": True, # Safety-first for resource creation
114
+ "default_dry_run": True, # Safety-first for resource creation
115
115
  "requires_confirmation": True,
116
116
  "simulation_mode": True,
117
- "warning_message": "⚠️ RESOURCE CREATION: This will create new AWS resources and incur costs"
117
+ "warning_message": "⚠️ RESOURCE CREATION: This will create new AWS resources and incur costs",
118
118
  },
119
119
  OperationType.RESOURCE_MODIFY: {
120
- "default_dry_run": True, # Safety-first for modifications
120
+ "default_dry_run": True, # Safety-first for modifications
121
121
  "requires_confirmation": True,
122
122
  "simulation_mode": True,
123
- "warning_message": "⚠️ RESOURCE MODIFICATION: This will modify existing AWS resources"
123
+ "warning_message": "⚠️ RESOURCE MODIFICATION: This will modify existing AWS resources",
124
124
  },
125
125
  OperationType.RESOURCE_DELETE: {
126
- "default_dry_run": True, # Safety-first for deletion
126
+ "default_dry_run": True, # Safety-first for deletion
127
127
  "requires_confirmation": True,
128
128
  "simulation_mode": True,
129
- "warning_message": "🚨 RESOURCE DELETION: This will permanently delete AWS resources"
129
+ "warning_message": "🚨 RESOURCE DELETION: This will permanently delete AWS resources",
130
130
  },
131
131
  OperationType.REMEDIATION: {
132
- "default_dry_run": True, # Safety-first for remediation
132
+ "default_dry_run": True, # Safety-first for remediation
133
133
  "requires_confirmation": True,
134
134
  "simulation_mode": True,
135
- "warning_message": "🔧 SECURITY REMEDIATION: This will apply security fixes to resources"
135
+ "warning_message": "🔧 SECURITY REMEDIATION: This will apply security fixes to resources",
136
136
  },
137
137
  OperationType.BULK_OPERATIONS: {
138
- "default_dry_run": True, # Safety-first for bulk operations
138
+ "default_dry_run": True, # Safety-first for bulk operations
139
139
  "requires_confirmation": True,
140
140
  "simulation_mode": True,
141
- "warning_message": "🔥 BULK OPERATION: This will affect multiple resources simultaneously"
141
+ "warning_message": "🔥 BULK OPERATION: This will affect multiple resources simultaneously",
142
142
  },
143
143
  OperationType.CROSS_ACCOUNT: {
144
- "default_dry_run": True, # Safety-first for cross-account
144
+ "default_dry_run": True, # Safety-first for cross-account
145
145
  "requires_confirmation": True,
146
146
  "simulation_mode": True,
147
- "warning_message": "🌐 CROSS-ACCOUNT OPERATION: This will affect multiple AWS accounts"
147
+ "warning_message": "🌐 CROSS-ACCOUNT OPERATION: This will affect multiple AWS accounts",
148
148
  },
149
149
  OperationType.FINANCIAL: {
150
- "default_dry_run": True, # Safety-first for financial operations
150
+ "default_dry_run": True, # Safety-first for financial operations
151
151
  "requires_confirmation": True,
152
152
  "simulation_mode": True,
153
- "warning_message": "💰 FINANCIAL OPERATION: This will modify budgets or billing configurations"
154
- }
153
+ "warning_message": "💰 FINANCIAL OPERATION: This will modify budgets or billing configurations",
154
+ },
155
155
  }
156
-
156
+
157
157
  def create_context(
158
158
  self,
159
159
  dry_run: bool,
@@ -161,11 +161,11 @@ class DryRunSafetyFramework:
161
161
  module_name: str,
162
162
  operation_name: str,
163
163
  target_resources: Optional[List[str]] = None,
164
- estimated_impact: Optional[str] = None
164
+ estimated_impact: Optional[str] = None,
165
165
  ) -> DryRunContext:
166
166
  """
167
167
  Create a dry-run context for an operation.
168
-
168
+
169
169
  Args:
170
170
  dry_run: User-specified dry-run flag
171
171
  operation_type: Type of operation being performed
@@ -173,25 +173,25 @@ class DryRunSafetyFramework:
173
173
  operation_name: Specific operation name
174
174
  target_resources: List of resources that will be affected
175
175
  estimated_impact: Human-readable impact description
176
-
176
+
177
177
  Returns:
178
178
  DryRunContext with appropriate safety settings
179
179
  """
180
180
  config = self.safety_configs.get(operation_type, self.safety_configs[OperationType.RESOURCE_MODIFY])
181
-
181
+
182
182
  # Determine actual dry-run state
183
183
  if dry_run is None:
184
184
  actual_dry_run = config["default_dry_run"]
185
185
  else:
186
186
  actual_dry_run = dry_run
187
-
187
+
188
188
  # Determine safety level
189
189
  safety_level = "standard"
190
190
  if operation_type in [OperationType.RESOURCE_DELETE, OperationType.BULK_OPERATIONS]:
191
191
  safety_level = "high"
192
192
  elif operation_type in [OperationType.CROSS_ACCOUNT, OperationType.FINANCIAL]:
193
193
  safety_level = "critical"
194
-
194
+
195
195
  context = DryRunContext(
196
196
  enabled=actual_dry_run,
197
197
  operation_type=operation_type,
@@ -200,29 +200,33 @@ class DryRunSafetyFramework:
200
200
  target_resources=target_resources or [],
201
201
  estimated_impact=estimated_impact,
202
202
  safety_level=safety_level,
203
- requires_confirmation=config["requires_confirmation"] and not actual_dry_run
203
+ requires_confirmation=config["requires_confirmation"] and not actual_dry_run,
204
204
  )
205
-
205
+
206
206
  # Log context creation
207
- self._add_audit_entry(context, "context_created", {
208
- "dry_run_enabled": actual_dry_run,
209
- "safety_level": safety_level,
210
- "requires_confirmation": context.requires_confirmation
211
- })
212
-
207
+ self._add_audit_entry(
208
+ context,
209
+ "context_created",
210
+ {
211
+ "dry_run_enabled": actual_dry_run,
212
+ "safety_level": safety_level,
213
+ "requires_confirmation": context.requires_confirmation,
214
+ },
215
+ )
216
+
213
217
  return context
214
-
218
+
215
219
  def display_dry_run_banner(self, context: DryRunContext) -> None:
216
220
  """
217
221
  Display appropriate dry-run banner based on operation type.
218
-
222
+
219
223
  Args:
220
224
  context: Dry-run context with operation details
221
225
  """
222
226
  if context.enabled:
223
227
  # Dry-run mode banner
224
228
  title = f"{STATUS_INDICATORS['info']} DRY-RUN MODE ENABLED"
225
-
229
+
226
230
  if context.operation_type in [OperationType.DISCOVERY, OperationType.ANALYSIS, OperationType.ASSESSMENT]:
227
231
  message = f"[cyan]Simulation mode: No AWS API calls will be made[/cyan]\n"
228
232
  message += f"[dim]Operation: {context.module_name} {context.operation_name}[/dim]"
@@ -231,262 +235,255 @@ class DryRunSafetyFramework:
231
235
  message += f"[dim]Operation: {context.module_name} {context.operation_name}[/dim]\n"
232
236
  if context.target_resources:
233
237
  message += f"[dim]Target resources: {len(context.target_resources)} items[/dim]"
234
-
235
- panel = Panel(
236
- message,
237
- title=title,
238
- border_style="cyan",
239
- title_align="left"
240
- )
241
-
238
+
239
+ panel = Panel(message, title=title, border_style="cyan", title_align="left")
240
+
242
241
  else:
243
242
  # Live mode banner with warnings
244
243
  config = self.safety_configs.get(context.operation_type)
245
244
  if config and config.get("warning_message"):
246
245
  title = f"{STATUS_INDICATORS['warning']} LIVE MODE - CHANGES WILL BE APPLIED"
247
-
246
+
248
247
  message = f"[red]{config['warning_message']}[/red]\n"
249
248
  message += f"[dim]Operation: {context.module_name} {context.operation_name}[/dim]"
250
249
  if context.estimated_impact:
251
250
  message += f"\n[yellow]Estimated impact: {context.estimated_impact}[/yellow]"
252
-
253
- panel = Panel(
254
- message,
255
- title=title,
256
- border_style="red",
257
- title_align="left"
258
- )
251
+
252
+ panel = Panel(message, title=title, border_style="red", title_align="left")
259
253
  else:
260
254
  # Standard live mode for read-only operations
261
255
  title = f"{STATUS_INDICATORS['success']} LIVE MODE - REAL DATA ANALYSIS"
262
256
  message = f"[green]Real AWS API calls will be made for analysis[/green]\n"
263
257
  message += f"[dim]Operation: {context.module_name} {context.operation_name}[/dim]"
264
-
265
- panel = Panel(
266
- message,
267
- title=title,
268
- border_style="green",
269
- title_align="left"
270
- )
271
-
258
+
259
+ panel = Panel(message, title=title, border_style="green", title_align="left")
260
+
272
261
  self.console.print(panel)
273
262
  self.console.print() # Add spacing
274
-
263
+
275
264
  def confirm_operation(self, context: DryRunContext) -> bool:
276
265
  """
277
266
  Request confirmation for operations that require it.
278
-
267
+
279
268
  Args:
280
269
  context: Dry-run context
281
-
270
+
282
271
  Returns:
283
272
  True if user confirms, False otherwise
284
273
  """
285
274
  if not context.requires_confirmation:
286
275
  return True
287
-
276
+
288
277
  # Show operation details
289
278
  table = Table(title="Operation Confirmation Required")
290
279
  table.add_column("Property", style="cyan")
291
280
  table.add_column("Value", style="white")
292
-
281
+
293
282
  table.add_row("Module", context.module_name)
294
283
  table.add_row("Operation", context.operation_name)
295
284
  table.add_row("Safety Level", context.safety_level.upper())
296
-
285
+
297
286
  if context.target_resources:
298
287
  table.add_row("Resources Affected", str(len(context.target_resources)))
299
-
288
+
300
289
  if context.estimated_impact:
301
290
  table.add_row("Estimated Impact", context.estimated_impact)
302
-
291
+
303
292
  self.console.print(table)
304
293
  self.console.print()
305
-
294
+
306
295
  # Request confirmation
307
296
  try:
308
297
  import click
298
+
309
299
  confirmed = click.confirm(
310
- f"Are you sure you want to proceed with this {context.operation_type.value} operation?",
311
- default=False
300
+ f"Are you sure you want to proceed with this {context.operation_type.value} operation?", default=False
312
301
  )
313
302
  except ImportError:
314
303
  # Fallback for environments without click
315
- response = input(f"Are you sure you want to proceed with this {context.operation_type.value} operation? [y/N]: ")
316
- confirmed = response.lower().startswith('y')
317
-
304
+ response = input(
305
+ f"Are you sure you want to proceed with this {context.operation_type.value} operation? [y/N]: "
306
+ )
307
+ confirmed = response.lower().startswith("y")
308
+
318
309
  # Log confirmation
319
- self._add_audit_entry(context, "confirmation_requested", {
320
- "user_confirmed": confirmed,
321
- "safety_level": context.safety_level
322
- })
323
-
310
+ self._add_audit_entry(
311
+ context, "confirmation_requested", {"user_confirmed": confirmed, "safety_level": context.safety_level}
312
+ )
313
+
324
314
  if not confirmed:
325
315
  print_warning("Operation cancelled by user")
326
-
316
+
327
317
  return confirmed
328
-
318
+
329
319
  def log_operation_start(self, context: DryRunContext, details: Optional[Dict[str, Any]] = None) -> None:
330
320
  """Log the start of an operation with full context."""
331
321
  mode = "DRY-RUN" if context.enabled else "LIVE"
332
-
322
+
333
323
  log_entry = {
334
324
  "mode": mode,
335
325
  "operation_type": context.operation_type.value,
336
326
  "module": context.module_name,
337
327
  "operation": context.operation_name,
338
328
  "target_count": len(context.target_resources),
339
- "safety_level": context.safety_level
329
+ "safety_level": context.safety_level,
340
330
  }
341
-
331
+
342
332
  if details:
343
333
  log_entry.update(details)
344
-
334
+
345
335
  self._add_audit_entry(context, "operation_started", log_entry)
346
-
336
+
347
337
  # Console output
348
338
  status = STATUS_INDICATORS.get("running", "🔄")
349
339
  self.console.print(f"{status} Starting {mode} operation: {context.operation_name}")
350
-
340
+
351
341
  def log_operation_complete(
352
342
  self,
353
343
  context: DryRunContext,
354
344
  success: bool = True,
355
345
  results: Optional[Dict[str, Any]] = None,
356
- error: Optional[str] = None
346
+ error: Optional[str] = None,
357
347
  ) -> None:
358
348
  """Log the completion of an operation."""
359
349
  mode = "DRY-RUN" if context.enabled else "LIVE"
360
-
350
+
361
351
  log_entry = {
362
352
  "mode": mode,
363
353
  "success": success,
364
354
  "duration": self._calculate_duration(context),
365
355
  }
366
-
356
+
367
357
  if results:
368
358
  log_entry["results"] = results
369
-
359
+
370
360
  if error:
371
361
  log_entry["error"] = error
372
-
362
+
373
363
  self._add_audit_entry(context, "operation_completed", log_entry)
374
-
364
+
375
365
  # Console output
376
366
  if success:
377
367
  status = STATUS_INDICATORS.get("success", "✅")
378
368
  print_success(f"Operation completed successfully in {mode} mode")
379
-
380
- if context.enabled and context.operation_type not in [OperationType.DISCOVERY, OperationType.ANALYSIS, OperationType.ASSESSMENT]:
369
+
370
+ if context.enabled and context.operation_type not in [
371
+ OperationType.DISCOVERY,
372
+ OperationType.ANALYSIS,
373
+ OperationType.ASSESSMENT,
374
+ ]:
381
375
  self.console.print(f"[dim]💡 To execute changes, run the same command with --no-dry-run[/dim]")
382
376
  else:
383
377
  status = STATUS_INDICATORS.get("error", "❌")
384
378
  print_error(f"Operation failed in {mode} mode: {error}")
385
-
379
+
386
380
  def _add_audit_entry(self, context: DryRunContext, event: str, data: Dict[str, Any]) -> None:
387
381
  """Add an entry to the audit trail."""
388
- entry = {
389
- "timestamp": datetime.utcnow().isoformat(),
390
- "event": event,
391
- "data": data
392
- }
382
+ entry = {"timestamp": datetime.utcnow().isoformat(), "event": event, "data": data}
393
383
  context.audit_trail.append(entry)
394
-
384
+
395
385
  # Log to system logger
396
- self.logger.info(f"DryRun {event}", extra={
397
- "module": context.module_name,
398
- "operation": context.operation_name,
399
- "dry_run": context.enabled,
400
- **data
401
- })
402
-
386
+ self.logger.info(
387
+ f"DryRun {event}",
388
+ extra={
389
+ "module": context.module_name,
390
+ "operation": context.operation_name,
391
+ "dry_run": context.enabled,
392
+ **data,
393
+ },
394
+ )
395
+
403
396
  def _calculate_duration(self, context: DryRunContext) -> Optional[str]:
404
397
  """Calculate operation duration from audit trail."""
405
398
  start_time = None
406
399
  end_time = datetime.utcnow()
407
-
400
+
408
401
  for entry in context.audit_trail:
409
402
  if entry["event"] == "operation_started":
410
403
  start_time = datetime.fromisoformat(entry["timestamp"])
411
404
  break
412
-
405
+
413
406
  if start_time:
414
407
  duration = end_time - start_time
415
408
  return f"{duration.total_seconds():.2f}s"
416
-
409
+
417
410
  return None
418
411
 
419
412
 
420
413
  def dry_run_operation(
421
- operation_type: OperationType,
422
- requires_confirmation: Optional[bool] = None,
423
- estimated_impact: Optional[str] = None
414
+ operation_type: OperationType, requires_confirmation: Optional[bool] = None, estimated_impact: Optional[str] = None
424
415
  ):
425
416
  """
426
417
  Decorator for operations that support dry-run mode.
427
-
418
+
428
419
  Args:
429
420
  operation_type: Type of operation for appropriate safety controls
430
421
  requires_confirmation: Override default confirmation requirement
431
422
  estimated_impact: Description of operation impact
432
-
423
+
433
424
  Usage:
434
425
  @dry_run_operation(OperationType.RESOURCE_DELETE, estimated_impact="Delete 5 VPCs")
435
426
  def delete_vpcs(dry_run: bool = True, **kwargs):
436
427
  # Function receives dry_run_context as first argument
437
428
  pass
438
429
  """
430
+
439
431
  def decorator(func: Callable) -> Callable:
440
432
  @functools.wraps(func)
441
433
  def wrapper(*args, **kwargs):
442
434
  # Extract dry_run parameter
443
- dry_run = kwargs.pop('dry_run', None)
444
-
435
+ dry_run = kwargs.pop("dry_run", None)
436
+
445
437
  # Get module and operation names
446
- module_name = getattr(func, '__module__', 'unknown').split('.')[-2] if '.' in getattr(func, '__module__', '') else 'unknown'
438
+ module_name = (
439
+ getattr(func, "__module__", "unknown").split(".")[-2]
440
+ if "." in getattr(func, "__module__", "")
441
+ else "unknown"
442
+ )
447
443
  operation_name = func.__name__
448
-
444
+
449
445
  # Create dry-run framework instance
450
446
  framework = DryRunSafetyFramework()
451
-
447
+
452
448
  # Create context
453
449
  context = framework.create_context(
454
450
  dry_run=dry_run,
455
451
  operation_type=operation_type,
456
452
  module_name=module_name,
457
453
  operation_name=operation_name,
458
- estimated_impact=estimated_impact
454
+ estimated_impact=estimated_impact,
459
455
  )
460
-
456
+
461
457
  # Override confirmation requirement if specified
462
458
  if requires_confirmation is not None:
463
459
  context.requires_confirmation = requires_confirmation and not context.enabled
464
-
460
+
465
461
  # Display banner
466
462
  framework.display_dry_run_banner(context)
467
-
463
+
468
464
  # Request confirmation if required
469
465
  if not framework.confirm_operation(context):
470
466
  return None
471
-
467
+
472
468
  # Log operation start
473
469
  framework.log_operation_start(context)
474
-
470
+
475
471
  try:
476
472
  # Call the original function with context as first argument
477
473
  result = func(context, *args, **kwargs)
478
-
474
+
479
475
  # Log success
480
476
  framework.log_operation_complete(context, success=True, results={"completed": True})
481
-
477
+
482
478
  return result
483
-
479
+
484
480
  except Exception as e:
485
481
  # Log failure
486
482
  framework.log_operation_complete(context, success=False, error=str(e))
487
483
  raise
488
-
484
+
489
485
  return wrapper
486
+
490
487
  return decorator
491
488
 
492
489
 
@@ -495,26 +492,31 @@ def discovery_operation(func: Callable) -> Callable:
495
492
  """Decorator for discovery operations (inventory, scan)."""
496
493
  return dry_run_operation(OperationType.DISCOVERY)(func)
497
494
 
495
+
498
496
  def analysis_operation(func: Callable) -> Callable:
499
497
  """Decorator for analysis operations (finops, security assess, vpc analyze)."""
500
498
  return dry_run_operation(OperationType.ANALYSIS)(func)
501
499
 
500
+
502
501
  def assessment_operation(func: Callable) -> Callable:
503
502
  """Decorator for assessment operations (cfat assess)."""
504
503
  return dry_run_operation(OperationType.ASSESSMENT)(func)
505
504
 
505
+
506
506
  def resource_creation_operation(estimated_impact: str = None):
507
507
  """Decorator for resource creation operations."""
508
508
  return dry_run_operation(OperationType.RESOURCE_CREATE, estimated_impact=estimated_impact)
509
509
 
510
+
510
511
  def resource_deletion_operation(estimated_impact: str = None):
511
512
  """Decorator for resource deletion operations."""
512
513
  return dry_run_operation(OperationType.RESOURCE_DELETE, estimated_impact=estimated_impact)
513
514
 
515
+
514
516
  def remediation_operation(estimated_impact: str = None):
515
517
  """Decorator for security remediation operations."""
516
518
  return dry_run_operation(OperationType.REMEDIATION, estimated_impact=estimated_impact)
517
519
 
518
520
 
519
521
  # Global framework instance for direct use
520
- framework = DryRunSafetyFramework()
522
+ framework = DryRunSafetyFramework()