runbooks 1.1.3__py3-none-any.whl → 1.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) 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/WEIGHT_CONFIG_README.md +1 -1
  8. runbooks/cfat/assessment/compliance.py +8 -8
  9. runbooks/cfat/assessment/runner.py +1 -0
  10. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  11. runbooks/cfat/models.py +6 -2
  12. runbooks/cfat/tests/__init__.py +6 -1
  13. runbooks/cli/__init__.py +13 -0
  14. runbooks/cli/commands/cfat.py +274 -0
  15. runbooks/cli/commands/finops.py +1164 -0
  16. runbooks/cli/commands/inventory.py +379 -0
  17. runbooks/cli/commands/operate.py +239 -0
  18. runbooks/cli/commands/security.py +248 -0
  19. runbooks/cli/commands/validation.py +825 -0
  20. runbooks/cli/commands/vpc.py +310 -0
  21. runbooks/cli/registry.py +107 -0
  22. runbooks/cloudops/__init__.py +23 -30
  23. runbooks/cloudops/base.py +96 -107
  24. runbooks/cloudops/cost_optimizer.py +549 -547
  25. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  26. runbooks/cloudops/interfaces.py +226 -227
  27. runbooks/cloudops/lifecycle_manager.py +5 -4
  28. runbooks/cloudops/mcp_cost_validation.py +252 -235
  29. runbooks/cloudops/models.py +78 -53
  30. runbooks/cloudops/monitoring_automation.py +5 -4
  31. runbooks/cloudops/notebook_framework.py +179 -215
  32. runbooks/cloudops/security_enforcer.py +125 -159
  33. runbooks/common/accuracy_validator.py +11 -0
  34. runbooks/common/aws_pricing.py +349 -326
  35. runbooks/common/aws_pricing_api.py +211 -212
  36. runbooks/common/aws_profile_manager.py +341 -0
  37. runbooks/common/aws_utils.py +75 -80
  38. runbooks/common/business_logic.py +127 -105
  39. runbooks/common/cli_decorators.py +36 -60
  40. runbooks/common/comprehensive_cost_explorer_integration.py +456 -464
  41. runbooks/common/cross_account_manager.py +198 -205
  42. runbooks/common/date_utils.py +27 -39
  43. runbooks/common/decorators.py +235 -0
  44. runbooks/common/dry_run_examples.py +173 -208
  45. runbooks/common/dry_run_framework.py +157 -155
  46. runbooks/common/enhanced_exception_handler.py +15 -4
  47. runbooks/common/enhanced_logging_example.py +50 -64
  48. runbooks/common/enhanced_logging_integration_example.py +65 -37
  49. runbooks/common/env_utils.py +16 -16
  50. runbooks/common/error_handling.py +40 -38
  51. runbooks/common/lazy_loader.py +41 -23
  52. runbooks/common/logging_integration_helper.py +79 -86
  53. runbooks/common/mcp_cost_explorer_integration.py +478 -495
  54. runbooks/common/mcp_integration.py +63 -74
  55. runbooks/common/memory_optimization.py +140 -118
  56. runbooks/common/module_cli_base.py +37 -58
  57. runbooks/common/organizations_client.py +176 -194
  58. runbooks/common/patterns.py +204 -0
  59. runbooks/common/performance_monitoring.py +67 -71
  60. runbooks/common/performance_optimization_engine.py +283 -274
  61. runbooks/common/profile_utils.py +248 -39
  62. runbooks/common/rich_utils.py +643 -92
  63. runbooks/common/sre_performance_suite.py +177 -186
  64. runbooks/enterprise/__init__.py +1 -1
  65. runbooks/enterprise/logging.py +144 -106
  66. runbooks/enterprise/security.py +187 -204
  67. runbooks/enterprise/validation.py +43 -56
  68. runbooks/finops/__init__.py +29 -33
  69. runbooks/finops/account_resolver.py +1 -1
  70. runbooks/finops/advanced_optimization_engine.py +980 -0
  71. runbooks/finops/automation_core.py +268 -231
  72. runbooks/finops/business_case_config.py +184 -179
  73. runbooks/finops/cli.py +660 -139
  74. runbooks/finops/commvault_ec2_analysis.py +157 -164
  75. runbooks/finops/compute_cost_optimizer.py +336 -320
  76. runbooks/finops/config.py +20 -20
  77. runbooks/finops/cost_optimizer.py +488 -622
  78. runbooks/finops/cost_processor.py +332 -214
  79. runbooks/finops/dashboard_runner.py +1006 -172
  80. runbooks/finops/ebs_cost_optimizer.py +991 -657
  81. runbooks/finops/elastic_ip_optimizer.py +317 -257
  82. runbooks/finops/enhanced_mcp_integration.py +340 -0
  83. runbooks/finops/enhanced_progress.py +40 -37
  84. runbooks/finops/enhanced_trend_visualization.py +3 -2
  85. runbooks/finops/enterprise_wrappers.py +230 -292
  86. runbooks/finops/executive_export.py +203 -160
  87. runbooks/finops/helpers.py +130 -288
  88. runbooks/finops/iam_guidance.py +1 -1
  89. runbooks/finops/infrastructure/__init__.py +80 -0
  90. runbooks/finops/infrastructure/commands.py +506 -0
  91. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  92. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  93. runbooks/finops/markdown_exporter.py +338 -175
  94. runbooks/finops/mcp_validator.py +1952 -0
  95. runbooks/finops/nat_gateway_optimizer.py +1513 -482
  96. runbooks/finops/network_cost_optimizer.py +657 -587
  97. runbooks/finops/notebook_utils.py +226 -188
  98. runbooks/finops/optimization_engine.py +1136 -0
  99. runbooks/finops/optimizer.py +25 -29
  100. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  101. runbooks/finops/reservation_optimizer.py +427 -363
  102. runbooks/finops/scenario_cli_integration.py +77 -78
  103. runbooks/finops/scenarios.py +1278 -439
  104. runbooks/finops/schemas.py +218 -182
  105. runbooks/finops/snapshot_manager.py +2289 -0
  106. runbooks/finops/tests/test_finops_dashboard.py +3 -3
  107. runbooks/finops/tests/test_reference_images_validation.py +2 -2
  108. runbooks/finops/tests/test_single_account_features.py +17 -17
  109. runbooks/finops/tests/validate_test_suite.py +1 -1
  110. runbooks/finops/types.py +3 -3
  111. runbooks/finops/validation_framework.py +263 -269
  112. runbooks/finops/vpc_cleanup_exporter.py +191 -146
  113. runbooks/finops/vpc_cleanup_optimizer.py +593 -575
  114. runbooks/finops/workspaces_analyzer.py +171 -182
  115. runbooks/hitl/enhanced_workflow_engine.py +1 -1
  116. runbooks/integration/__init__.py +89 -0
  117. runbooks/integration/mcp_integration.py +1920 -0
  118. runbooks/inventory/CLAUDE.md +816 -0
  119. runbooks/inventory/README.md +3 -3
  120. runbooks/inventory/Tests/common_test_data.py +30 -30
  121. runbooks/inventory/__init__.py +2 -2
  122. runbooks/inventory/cloud_foundations_integration.py +144 -149
  123. runbooks/inventory/collectors/aws_comprehensive.py +28 -11
  124. runbooks/inventory/collectors/aws_networking.py +111 -101
  125. runbooks/inventory/collectors/base.py +4 -0
  126. runbooks/inventory/core/collector.py +495 -313
  127. runbooks/inventory/discovery.md +2 -2
  128. runbooks/inventory/drift_detection_cli.py +69 -96
  129. runbooks/inventory/find_ec2_security_groups.py +1 -1
  130. runbooks/inventory/inventory_mcp_cli.py +48 -46
  131. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  132. runbooks/inventory/mcp_inventory_validator.py +549 -465
  133. runbooks/inventory/mcp_vpc_validator.py +359 -442
  134. runbooks/inventory/organizations_discovery.py +56 -52
  135. runbooks/inventory/rich_inventory_display.py +33 -32
  136. runbooks/inventory/unified_validation_engine.py +278 -251
  137. runbooks/inventory/vpc_analyzer.py +733 -696
  138. runbooks/inventory/vpc_architecture_validator.py +293 -348
  139. runbooks/inventory/vpc_dependency_analyzer.py +382 -378
  140. runbooks/inventory/vpc_flow_analyzer.py +3 -3
  141. runbooks/main.py +152 -9147
  142. runbooks/main_final.py +91 -60
  143. runbooks/main_minimal.py +22 -10
  144. runbooks/main_optimized.py +131 -100
  145. runbooks/main_ultra_minimal.py +7 -2
  146. runbooks/mcp/__init__.py +36 -0
  147. runbooks/mcp/integration.py +679 -0
  148. runbooks/metrics/dora_metrics_engine.py +2 -2
  149. runbooks/monitoring/performance_monitor.py +9 -4
  150. runbooks/operate/dynamodb_operations.py +3 -1
  151. runbooks/operate/ec2_operations.py +145 -137
  152. runbooks/operate/iam_operations.py +146 -152
  153. runbooks/operate/mcp_integration.py +1 -1
  154. runbooks/operate/networking_cost_heatmap.py +33 -10
  155. runbooks/operate/privatelink_operations.py +1 -1
  156. runbooks/operate/rds_operations.py +223 -254
  157. runbooks/operate/s3_operations.py +107 -118
  158. runbooks/operate/vpc_endpoints.py +1 -1
  159. runbooks/operate/vpc_operations.py +648 -618
  160. runbooks/remediation/base.py +1 -1
  161. runbooks/remediation/commons.py +10 -7
  162. runbooks/remediation/commvault_ec2_analysis.py +71 -67
  163. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  164. runbooks/remediation/multi_account.py +24 -21
  165. runbooks/remediation/rds_snapshot_list.py +91 -65
  166. runbooks/remediation/remediation_cli.py +92 -146
  167. runbooks/remediation/universal_account_discovery.py +83 -79
  168. runbooks/remediation/workspaces_list.py +49 -44
  169. runbooks/security/__init__.py +19 -0
  170. runbooks/security/assessment_runner.py +1150 -0
  171. runbooks/security/baseline_checker.py +812 -0
  172. runbooks/security/cloudops_automation_security_validator.py +509 -535
  173. runbooks/security/compliance_automation_engine.py +17 -17
  174. runbooks/security/config/__init__.py +2 -2
  175. runbooks/security/config/compliance_config.py +50 -50
  176. runbooks/security/config_template_generator.py +63 -76
  177. runbooks/security/enterprise_security_framework.py +1 -1
  178. runbooks/security/executive_security_dashboard.py +519 -508
  179. runbooks/security/integration_test_enterprise_security.py +5 -3
  180. runbooks/security/multi_account_security_controls.py +959 -1210
  181. runbooks/security/real_time_security_monitor.py +422 -444
  182. runbooks/security/run_script.py +1 -1
  183. runbooks/security/security_baseline_tester.py +1 -1
  184. runbooks/security/security_cli.py +143 -112
  185. runbooks/security/test_2way_validation.py +439 -0
  186. runbooks/security/two_way_validation_framework.py +852 -0
  187. runbooks/sre/mcp_reliability_engine.py +6 -6
  188. runbooks/sre/production_monitoring_framework.py +167 -177
  189. runbooks/tdd/__init__.py +15 -0
  190. runbooks/tdd/cli.py +1071 -0
  191. runbooks/utils/__init__.py +14 -17
  192. runbooks/utils/logger.py +7 -2
  193. runbooks/utils/version_validator.py +51 -48
  194. runbooks/validation/__init__.py +6 -6
  195. runbooks/validation/cli.py +9 -3
  196. runbooks/validation/comprehensive_2way_validator.py +754 -708
  197. runbooks/validation/mcp_validator.py +906 -228
  198. runbooks/validation/terraform_citations_validator.py +104 -115
  199. runbooks/validation/terraform_drift_detector.py +447 -451
  200. runbooks/vpc/README.md +617 -0
  201. runbooks/vpc/__init__.py +8 -1
  202. runbooks/vpc/analyzer.py +577 -0
  203. runbooks/vpc/cleanup_wrapper.py +476 -413
  204. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  205. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  206. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  207. runbooks/vpc/config.py +92 -97
  208. runbooks/vpc/cost_engine.py +411 -148
  209. runbooks/vpc/cost_explorer_integration.py +553 -0
  210. runbooks/vpc/cross_account_session.py +101 -106
  211. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  212. runbooks/vpc/eni_gate_validator.py +961 -0
  213. runbooks/vpc/heatmap_engine.py +190 -162
  214. runbooks/vpc/mcp_no_eni_validator.py +681 -640
  215. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  216. runbooks/vpc/networking_wrapper.py +15 -8
  217. runbooks/vpc/pdca_remediation_planner.py +528 -0
  218. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  219. runbooks/vpc/runbooks_adapter.py +1167 -241
  220. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  221. runbooks/vpc/test_data_loader.py +358 -0
  222. runbooks/vpc/tests/conftest.py +314 -4
  223. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  224. runbooks/vpc/tests/test_cost_engine.py +0 -2
  225. runbooks/vpc/topology_generator.py +326 -0
  226. runbooks/vpc/unified_scenarios.py +1302 -1129
  227. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  228. runbooks-1.1.5.dist-info/METADATA +328 -0
  229. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/RECORD +233 -200
  230. runbooks/finops/README.md +0 -414
  231. runbooks/finops/accuracy_cross_validator.py +0 -647
  232. runbooks/finops/business_cases.py +0 -950
  233. runbooks/finops/dashboard_router.py +0 -922
  234. runbooks/finops/ebs_optimizer.py +0 -956
  235. runbooks/finops/embedded_mcp_validator.py +0 -1629
  236. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  237. runbooks/finops/finops_dashboard.py +0 -584
  238. runbooks/finops/finops_scenarios.py +0 -1218
  239. runbooks/finops/legacy_migration.py +0 -730
  240. runbooks/finops/multi_dashboard.py +0 -1519
  241. runbooks/finops/single_dashboard.py +0 -1113
  242. runbooks/finops/unlimited_scenarios.py +0 -393
  243. runbooks-1.1.3.dist-info/METADATA +0 -799
  244. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
  245. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
  246. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
  247. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -2,18 +2,18 @@
2
2
  """
3
3
  CloudOps Notebook Framework - Enterprise Consolidation Infrastructure
4
4
 
5
- Provides reusable components for consolidating 64 individual notebooks into
5
+ Provides reusable components for consolidating 64 individual notebooks into
6
6
  12-15 production scenarios with enterprise-grade functionality.
7
7
 
8
8
  Strategic Alignment:
9
- - Follows Rich CLI standards from rich_utils.py
9
+ - Follows Rich CLI standards from rich_utils.py
10
10
  - Handles authentication failures gracefully (no hardcoding/assumptions)
11
11
  - Dual-purpose interface: executive summary + technical details
12
12
  - Type-safe validation with Pydantic v2
13
13
 
14
14
  Key Features:
15
15
  - Authentication flow management with comprehensive error handling
16
- - Executive and technical reporting modes
16
+ - Executive and technical reporting modes
17
17
  - Multi-scenario consolidation support
18
18
  - MCP integration readiness
19
19
  - Performance monitoring and benchmarking
@@ -31,36 +31,60 @@ from enum import Enum
31
31
  import boto3
32
32
  import pandas as pd
33
33
  from botocore.exceptions import (
34
- ClientError, NoCredentialsError, ProfileNotFound,
35
- TokenRetrievalError, UnauthorizedSSOTokenError
34
+ ClientError,
35
+ NoCredentialsError,
36
+ ProfileNotFound,
37
+ TokenRetrievalError,
38
+ UnauthorizedSSOTokenError,
36
39
  )
37
40
  from pydantic import BaseModel, Field, ValidationError
38
41
 
39
42
  from runbooks.common.rich_utils import (
40
- console, print_header, print_success, print_error, print_warning, print_info,
41
- create_table, create_progress_bar, format_cost, create_panel, STATUS_INDICATORS,
42
- print_json, create_columns, confirm_action
43
+ console,
44
+ print_header,
45
+ print_success,
46
+ print_error,
47
+ print_warning,
48
+ print_info,
49
+ create_table,
50
+ create_progress_bar,
51
+ format_cost,
52
+ create_panel,
53
+ STATUS_INDICATORS,
54
+ print_json,
55
+ create_columns,
56
+ confirm_action,
43
57
  )
44
58
  from runbooks.common.profile_utils import (
45
- get_profile_for_operation, create_cost_session, create_management_session,
46
- create_operational_session
59
+ get_profile_for_operation,
60
+ create_cost_session,
61
+ create_management_session,
62
+ create_operational_session,
47
63
  )
48
64
  from .models import (
49
- BusinessScenario, ExecutionMode, RiskLevel, ProfileConfiguration,
50
- CloudOpsExecutionResult, BusinessMetrics, ResourceImpact, CostOptimizationResult
65
+ BusinessScenario,
66
+ ExecutionMode,
67
+ RiskLevel,
68
+ ProfileConfiguration,
69
+ CloudOpsExecutionResult,
70
+ BusinessMetrics,
71
+ ResourceImpact,
72
+ CostOptimizationResult,
51
73
  )
52
74
  from .base import CloudOpsBase, PerformanceBenchmark
53
75
 
54
76
 
55
77
  class NotebookMode(str, Enum):
56
78
  """Execution modes for notebook interface."""
79
+
57
80
  EXECUTIVE = "executive" # Executive summary for business stakeholders
58
- TECHNICAL = "technical" # Technical details for engineering teams
81
+ TECHNICAL = "technical" # Technical details for engineering teams
59
82
  COMPREHENSIVE = "comprehensive" # Both executive and technical views
60
83
 
61
84
 
62
85
  class AuthenticationStatus(str, Enum):
63
86
  """AWS authentication status tracking."""
87
+
64
88
  SUCCESS = "success"
65
89
  EXPIRED_TOKEN = "expired_token"
66
90
  INVALID_PROFILE = "invalid_profile"
@@ -72,12 +96,13 @@ class AuthenticationStatus(str, Enum):
72
96
  @dataclass
73
97
  class AuthenticationResult:
74
98
  """Results of AWS authentication validation."""
99
+
75
100
  status: AuthenticationStatus
76
101
  profile_name: str
77
102
  account_id: Optional[str] = None
78
103
  error_message: Optional[str] = None
79
104
  remediation_steps: List[str] = None
80
-
105
+
81
106
  def __post_init__(self):
82
107
  if self.remediation_steps is None:
83
108
  self.remediation_steps = []
@@ -85,17 +110,18 @@ class AuthenticationResult:
85
110
 
86
111
  class ScenarioMetadata(BaseModel):
87
112
  """Metadata for consolidated notebook scenarios."""
113
+
88
114
  scenario_id: str = Field(description="Unique scenario identifier")
89
115
  scenario_name: str = Field(description="Human-readable scenario name")
90
116
  scenario_type: BusinessScenario = Field(description="Business scenario category")
91
117
  consolidated_notebooks: List[str] = Field(description="List of individual notebooks consolidated")
92
-
118
+
93
119
  # Executive Information
94
120
  business_objective: str = Field(description="High-level business objective")
95
121
  expected_outcomes: List[str] = Field(description="Expected business outcomes")
96
122
  stakeholders: List[str] = Field(description="Key stakeholders", default=[])
97
-
98
- # Technical Information
123
+
124
+ # Technical Information
99
125
  aws_services: List[str] = Field(description="AWS services utilized")
100
126
  estimated_execution_time: int = Field(description="Estimated execution time in minutes")
101
127
  prerequisites: List[str] = Field(description="Technical prerequisites", default=[])
@@ -104,21 +130,21 @@ class ScenarioMetadata(BaseModel):
104
130
  class NotebookFramework(CloudOpsBase):
105
131
  """
106
132
  Enterprise notebook framework for consolidated CloudOps scenarios.
107
-
133
+
108
134
  Provides comprehensive infrastructure for transforming individual notebooks
109
135
  into enterprise-grade consolidated scenarios with dual executive/technical interfaces.
110
136
  """
111
-
137
+
112
138
  def __init__(
113
- self,
139
+ self,
114
140
  profile: str = "default",
115
141
  mode: NotebookMode = NotebookMode.COMPREHENSIVE,
116
142
  dry_run: bool = True,
117
- validate_auth: bool = True
143
+ validate_auth: bool = True,
118
144
  ):
119
145
  """
120
146
  Initialize notebook framework.
121
-
147
+
122
148
  Args:
123
149
  profile: AWS profile for authentication
124
150
  mode: Notebook execution mode (executive/technical/comprehensive)
@@ -128,7 +154,7 @@ class NotebookFramework(CloudOpsBase):
128
154
  self.mode = mode
129
155
  self.validate_auth = validate_auth
130
156
  self.auth_status: Optional[AuthenticationResult] = None
131
-
157
+
132
158
  # Initialize base class (handles AWS session setup)
133
159
  # Note: This may raise exceptions for authentication issues
134
160
  try:
@@ -141,14 +167,14 @@ class NotebookFramework(CloudOpsBase):
141
167
  status=AuthenticationStatus.UNKNOWN_ERROR,
142
168
  profile_name=profile,
143
169
  error_message=str(e),
144
- remediation_steps=self._get_generic_remediation_steps()
170
+ remediation_steps=self._get_generic_remediation_steps(),
145
171
  )
146
172
  self.session = None # Ensure session is None on failure
147
-
173
+
148
174
  def _validate_authentication(self) -> AuthenticationResult:
149
175
  """
150
176
  Comprehensive AWS authentication validation with detailed error handling.
151
-
177
+
152
178
  Returns:
153
179
  AuthenticationResult with status and remediation guidance
154
180
  """
@@ -158,25 +184,23 @@ class NotebookFramework(CloudOpsBase):
158
184
  status=AuthenticationStatus.NO_CREDENTIALS,
159
185
  profile_name=self.profile,
160
186
  error_message="No AWS session available",
161
- remediation_steps=self._get_generic_remediation_steps()
187
+ remediation_steps=self._get_generic_remediation_steps(),
162
188
  )
163
-
189
+
164
190
  # Test authentication by calling STS
165
- sts_client = self.session.client('sts')
191
+ sts_client = self.session.client("sts")
166
192
  identity = sts_client.get_caller_identity()
167
-
168
- account_id = identity.get('Account')
169
- user_arn = identity.get('Arn')
170
-
193
+
194
+ account_id = identity.get("Account")
195
+ user_arn = identity.get("Arn")
196
+
171
197
  print_success(f"Authentication successful for profile: {self.profile}")
172
198
  print_info(f"Account: {account_id}, Identity: {user_arn}")
173
-
199
+
174
200
  return AuthenticationResult(
175
- status=AuthenticationStatus.SUCCESS,
176
- profile_name=self.profile,
177
- account_id=account_id
201
+ status=AuthenticationStatus.SUCCESS, profile_name=self.profile, account_id=account_id
178
202
  )
179
-
203
+
180
204
  except UnauthorizedSSOTokenError:
181
205
  return AuthenticationResult(
182
206
  status=AuthenticationStatus.EXPIRED_TOKEN,
@@ -185,10 +209,10 @@ class NotebookFramework(CloudOpsBase):
185
209
  remediation_steps=[
186
210
  "Run: aws sso login",
187
211
  "Ensure your AWS SSO session is active",
188
- f"Verify profile '{self.profile}' is configured for SSO"
189
- ]
212
+ f"Verify profile '{self.profile}' is configured for SSO",
213
+ ],
190
214
  )
191
-
215
+
192
216
  except TokenRetrievalError as e:
193
217
  return AuthenticationResult(
194
218
  status=AuthenticationStatus.EXPIRED_TOKEN,
@@ -197,10 +221,10 @@ class NotebookFramework(CloudOpsBase):
197
221
  remediation_steps=[
198
222
  "Run: aws sso login",
199
223
  "Check your internet connection",
200
- "Verify AWS SSO configuration"
201
- ]
224
+ "Verify AWS SSO configuration",
225
+ ],
202
226
  )
203
-
227
+
204
228
  except ProfileNotFound:
205
229
  return AuthenticationResult(
206
230
  status=AuthenticationStatus.INVALID_PROFILE,
@@ -209,10 +233,10 @@ class NotebookFramework(CloudOpsBase):
209
233
  remediation_steps=[
210
234
  f"Check if profile '{self.profile}' exists in ~/.aws/config",
211
235
  "Run: aws configure list-profiles",
212
- "Configure the profile using: aws configure sso"
213
- ]
236
+ "Configure the profile using: aws configure sso",
237
+ ],
214
238
  )
215
-
239
+
216
240
  except NoCredentialsError:
217
241
  return AuthenticationResult(
218
242
  status=AuthenticationStatus.NO_CREDENTIALS,
@@ -221,14 +245,14 @@ class NotebookFramework(CloudOpsBase):
221
245
  remediation_steps=[
222
246
  "Configure AWS credentials using: aws configure",
223
247
  "Or set up SSO using: aws configure sso",
224
- "Verify AWS credentials are properly configured"
225
- ]
248
+ "Verify AWS credentials are properly configured",
249
+ ],
226
250
  )
227
-
251
+
228
252
  except ClientError as e:
229
- error_code = e.response.get('Error', {}).get('Code', 'Unknown')
230
-
231
- if error_code in ['AccessDenied', 'UnauthorizedOperation']:
253
+ error_code = e.response.get("Error", {}).get("Code", "Unknown")
254
+
255
+ if error_code in ["AccessDenied", "UnauthorizedOperation"]:
232
256
  return AuthenticationResult(
233
257
  status=AuthenticationStatus.PERMISSION_DENIED,
234
258
  profile_name=self.profile,
@@ -236,113 +260,97 @@ class NotebookFramework(CloudOpsBase):
236
260
  remediation_steps=[
237
261
  "Verify your AWS profile has sufficient permissions",
238
262
  "Contact your AWS administrator for access",
239
- "Check IAM policies attached to your role/user"
240
- ]
263
+ "Check IAM policies attached to your role/user",
264
+ ],
241
265
  )
242
266
  else:
243
267
  return AuthenticationResult(
244
268
  status=AuthenticationStatus.UNKNOWN_ERROR,
245
269
  profile_name=self.profile,
246
270
  error_message=f"AWS API error: {str(e)}",
247
- remediation_steps=self._get_generic_remediation_steps()
271
+ remediation_steps=self._get_generic_remediation_steps(),
248
272
  )
249
-
273
+
250
274
  except Exception as e:
251
275
  return AuthenticationResult(
252
276
  status=AuthenticationStatus.UNKNOWN_ERROR,
253
277
  profile_name=self.profile,
254
278
  error_message=f"Unexpected error: {str(e)}",
255
- remediation_steps=self._get_generic_remediation_steps()
279
+ remediation_steps=self._get_generic_remediation_steps(),
256
280
  )
257
-
281
+
258
282
  def _get_generic_remediation_steps(self) -> List[str]:
259
283
  """Get generic remediation steps for authentication issues."""
260
284
  return [
261
285
  "Check AWS profile configuration: aws configure list-profiles",
262
286
  "Verify credentials: aws sts get-caller-identity",
263
- "For SSO profiles, login again: aws sso login",
264
- "Contact your AWS administrator if issues persist"
287
+ "For SSO profiles, login again: aws sso login",
288
+ "Contact your AWS administrator if issues persist",
265
289
  ]
266
-
290
+
267
291
  def display_authentication_status(self) -> None:
268
292
  """Display authentication status with Rich CLI formatting."""
269
293
  if not self.auth_status:
270
294
  print_warning("Authentication status not available")
271
295
  return
272
-
296
+
273
297
  status_colors = {
274
298
  AuthenticationStatus.SUCCESS: "green",
275
299
  AuthenticationStatus.EXPIRED_TOKEN: "yellow",
276
300
  AuthenticationStatus.INVALID_PROFILE: "red",
277
- AuthenticationStatus.NO_CREDENTIALS: "red",
301
+ AuthenticationStatus.NO_CREDENTIALS: "red",
278
302
  AuthenticationStatus.PERMISSION_DENIED: "red",
279
- AuthenticationStatus.UNKNOWN_ERROR: "red"
303
+ AuthenticationStatus.UNKNOWN_ERROR: "red",
280
304
  }
281
-
305
+
282
306
  status_icons = {
283
307
  AuthenticationStatus.SUCCESS: "✅",
284
308
  AuthenticationStatus.EXPIRED_TOKEN: "⚠️",
285
309
  AuthenticationStatus.INVALID_PROFILE: "❌",
286
310
  AuthenticationStatus.NO_CREDENTIALS: "❌",
287
311
  AuthenticationStatus.PERMISSION_DENIED: "🔒",
288
- AuthenticationStatus.UNKNOWN_ERROR: "❓"
312
+ AuthenticationStatus.UNKNOWN_ERROR: "❓",
289
313
  }
290
-
314
+
291
315
  status_color = status_colors.get(self.auth_status.status, "white")
292
316
  status_icon = status_icons.get(self.auth_status.status, "?")
293
-
317
+
294
318
  # Authentication Status Panel
295
319
  status_content = (
296
320
  f"Profile: {self.auth_status.profile_name}\n"
297
321
  f"Status: {status_icon} {self.auth_status.status.value.replace('_', ' ').title()}"
298
322
  )
299
-
323
+
300
324
  if self.auth_status.account_id:
301
325
  status_content += f"\nAccount ID: {self.auth_status.account_id}"
302
-
326
+
303
327
  if self.auth_status.error_message:
304
328
  status_content += f"\nError: {self.auth_status.error_message}"
305
-
306
- auth_panel = create_panel(
307
- status_content,
308
- title="AWS Authentication Status",
309
- border_style=status_color
310
- )
329
+
330
+ auth_panel = create_panel(status_content, title="AWS Authentication Status", border_style=status_color)
311
331
  console.print(auth_panel)
312
-
332
+
313
333
  # Remediation Steps (if authentication failed)
314
- if (self.auth_status.status != AuthenticationStatus.SUCCESS and
315
- self.auth_status.remediation_steps):
316
-
334
+ if self.auth_status.status != AuthenticationStatus.SUCCESS and self.auth_status.remediation_steps:
317
335
  remediation_text = "\n".join([f"• {step}" for step in self.auth_status.remediation_steps])
318
- remediation_panel = create_panel(
319
- remediation_text,
320
- title="Remediation Steps",
321
- border_style="blue"
322
- )
336
+ remediation_panel = create_panel(remediation_text, title="Remediation Steps", border_style="blue")
323
337
  console.print(remediation_panel)
324
-
338
+
325
339
  def is_authenticated(self) -> bool:
326
340
  """Check if AWS authentication is successful."""
327
- return (self.auth_status and
328
- self.auth_status.status == AuthenticationStatus.SUCCESS and
329
- self.session is not None)
330
-
331
- def create_scenario_header(
332
- self,
333
- metadata: ScenarioMetadata,
334
- show_consolidated_info: bool = True
335
- ) -> None:
341
+ return self.auth_status and self.auth_status.status == AuthenticationStatus.SUCCESS and self.session is not None
342
+
343
+ def create_scenario_header(self, metadata: ScenarioMetadata, show_consolidated_info: bool = True) -> None:
336
344
  """
337
345
  Create rich scenario header for consolidated notebooks.
338
-
346
+
339
347
  Args:
340
348
  metadata: Scenario metadata with business and technical information
341
349
  show_consolidated_info: Show information about consolidated notebooks
342
350
  """
343
351
  # Main scenario header
344
- print_header(f"CloudOps Scenario: {metadata.scenario_name}", "v0.9.1")
345
-
352
+ print_header(f"CloudOps Scenario: {metadata.scenario_name}", "latest version")
353
+
346
354
  # Executive Summary (always shown)
347
355
  if self.mode in [NotebookMode.EXECUTIVE, NotebookMode.COMPREHENSIVE]:
348
356
  exec_content = (
@@ -351,55 +359,42 @@ class NotebookFramework(CloudOpsBase):
351
359
  f"⏱️ Estimated Time: {metadata.estimated_execution_time} minutes\n"
352
360
  f"🛡️ Execution Mode: {'🔍 Analysis Only' if self.dry_run else '⚡ Live Execution'}"
353
361
  )
354
-
362
+
355
363
  if metadata.expected_outcomes:
356
364
  exec_content += f"\n\n📈 Expected Outcomes:\n"
357
365
  exec_content += "\n".join([f"• {outcome}" for outcome in metadata.expected_outcomes])
358
-
359
- exec_panel = create_panel(
360
- exec_content,
361
- title="Executive Summary",
362
- border_style="cyan"
363
- )
366
+
367
+ exec_panel = create_panel(exec_content, title="Executive Summary", border_style="cyan")
364
368
  console.print(exec_panel)
365
-
369
+
366
370
  # Technical Details (technical/comprehensive modes)
367
371
  if self.mode in [NotebookMode.TECHNICAL, NotebookMode.COMPREHENSIVE]:
368
372
  tech_content = (
369
- f"🔧 AWS Services: {', '.join(metadata.aws_services)}\n"
370
- f"📝 Scenario ID: {metadata.scenario_id}"
373
+ f"🔧 AWS Services: {', '.join(metadata.aws_services)}\n📝 Scenario ID: {metadata.scenario_id}"
371
374
  )
372
-
375
+
373
376
  if metadata.prerequisites:
374
377
  tech_content += f"\n\n✅ Prerequisites:\n"
375
378
  tech_content += "\n".join([f"• {prereq}" for prereq in metadata.prerequisites])
376
-
379
+
377
380
  if show_consolidated_info and metadata.consolidated_notebooks:
378
381
  tech_content += f"\n\n📚 Consolidated Notebooks ({len(metadata.consolidated_notebooks)}):\n"
379
382
  tech_content += "\n".join([f"• {nb}" for nb in metadata.consolidated_notebooks])
380
-
381
- tech_panel = create_panel(
382
- tech_content,
383
- title="Technical Information",
384
- border_style="blue"
385
- )
383
+
384
+ tech_panel = create_panel(tech_content, title="Technical Information", border_style="blue")
386
385
  console.print(tech_panel)
387
-
388
- def create_results_summary(
389
- self,
390
- result: CloudOpsExecutionResult,
391
- show_detailed_metrics: bool = None
392
- ) -> None:
386
+
387
+ def create_results_summary(self, result: CloudOpsExecutionResult, show_detailed_metrics: bool = None) -> None:
393
388
  """
394
389
  Create comprehensive results summary with mode-appropriate detail level.
395
-
390
+
396
391
  Args:
397
392
  result: CloudOps execution result
398
393
  show_detailed_metrics: Override detail level (None = use mode default)
399
394
  """
400
395
  if show_detailed_metrics is None:
401
396
  show_detailed_metrics = self.mode in [NotebookMode.TECHNICAL, NotebookMode.COMPREHENSIVE]
402
-
397
+
403
398
  # Executive Summary (always shown)
404
399
  exec_summary = (
405
400
  f"📊 Scenario: {result.scenario_name}\n"
@@ -409,20 +404,18 @@ class NotebookFramework(CloudOpsBase):
409
404
  f"💰 Monthly Savings: {format_cost(result.business_metrics.total_monthly_savings)}\n"
410
405
  f"⏱️ Execution Time: {result.execution_time:.1f}s"
411
406
  )
412
-
407
+
413
408
  if result.business_metrics.roi_percentage:
414
409
  exec_summary += f"\n📈 ROI: {result.business_metrics.roi_percentage:.1f}%"
415
-
410
+
416
411
  if not result.success and result.error_message:
417
412
  exec_summary += f"\n❌ Error: {result.error_message}"
418
-
413
+
419
414
  exec_panel = create_panel(
420
- exec_summary,
421
- title="Execution Results Summary",
422
- border_style="green" if result.success else "red"
415
+ exec_summary, title="Execution Results Summary", border_style="green" if result.success else "red"
423
416
  )
424
417
  console.print(exec_panel)
425
-
418
+
426
419
  # Detailed Metrics (technical/comprehensive modes)
427
420
  if show_detailed_metrics and result.business_metrics:
428
421
  metrics_table = create_table(
@@ -430,72 +423,54 @@ class NotebookFramework(CloudOpsBase):
430
423
  columns=[
431
424
  {"name": "Metric", "style": "cyan"},
432
425
  {"name": "Value", "style": "green"},
433
- {"name": "Impact", "style": "yellow"}
434
- ]
426
+ {"name": "Impact", "style": "yellow"},
427
+ ],
435
428
  )
436
-
429
+
437
430
  # Financial Metrics
438
431
  metrics_table.add_row(
439
- "Monthly Savings",
440
- f"${result.business_metrics.total_monthly_savings:,.2f}",
441
- "Cost Reduction"
432
+ "Monthly Savings", f"${result.business_metrics.total_monthly_savings:,.2f}", "Cost Reduction"
442
433
  )
443
-
434
+
444
435
  if result.business_metrics.roi_percentage:
445
436
  metrics_table.add_row(
446
- "ROI Percentage",
447
- f"{result.business_metrics.roi_percentage:.1f}%",
448
- "Investment Return"
437
+ "ROI Percentage", f"{result.business_metrics.roi_percentage:.1f}%", "Investment Return"
449
438
  )
450
-
439
+
451
440
  if result.business_metrics.payback_period_months:
452
441
  metrics_table.add_row(
453
- "Payback Period",
454
- f"{result.business_metrics.payback_period_months} months",
455
- "Investment Recovery"
442
+ "Payback Period", f"{result.business_metrics.payback_period_months} months", "Investment Recovery"
456
443
  )
457
-
444
+
458
445
  # Operational Metrics
459
446
  if result.business_metrics.operational_efficiency_gain:
460
447
  metrics_table.add_row(
461
448
  "Efficiency Gain",
462
449
  f"{result.business_metrics.operational_efficiency_gain:.1f}%",
463
- "Operational Improvement"
450
+ "Operational Improvement",
464
451
  )
465
-
452
+
466
453
  metrics_table.add_row(
467
- "Risk Level",
468
- result.business_metrics.overall_risk_level.value.title(),
469
- "Risk Assessment"
454
+ "Risk Level", result.business_metrics.overall_risk_level.value.title(), "Risk Assessment"
470
455
  )
471
-
456
+
472
457
  console.print(metrics_table)
473
-
458
+
474
459
  # Recommendations (always shown if present)
475
460
  if result.recommendations:
476
461
  rec_text = "\n".join([f"• {rec}" for rec in result.recommendations])
477
- rec_panel = create_panel(
478
- rec_text,
479
- title="Strategic Recommendations",
480
- border_style="blue"
481
- )
462
+ rec_panel = create_panel(rec_text, title="Strategic Recommendations", border_style="blue")
482
463
  console.print(rec_panel)
483
-
484
- async def execute_with_auth_handling(
485
- self,
486
- operation_name: str,
487
- operation_func: Callable,
488
- *args,
489
- **kwargs
490
- ) -> Any:
464
+
465
+ async def execute_with_auth_handling(self, operation_name: str, operation_func: Callable, *args, **kwargs) -> Any:
491
466
  """
492
467
  Execute operation with comprehensive authentication error handling.
493
-
468
+
494
469
  Args:
495
470
  operation_name: Human-readable operation name
496
471
  operation_func: Function to execute (sync or async)
497
472
  *args, **kwargs: Arguments for operation_func
498
-
473
+
499
474
  Returns:
500
475
  Operation result or None if authentication failed
501
476
  """
@@ -504,101 +479,96 @@ class NotebookFramework(CloudOpsBase):
504
479
  print_error(f"Cannot execute {operation_name}: Authentication failed")
505
480
  self.display_authentication_status()
506
481
  return None
507
-
482
+
508
483
  # Execute with monitoring (from CloudOpsBase)
509
484
  try:
510
- return await self.execute_with_monitoring(
511
- operation_name, operation_func, *args, **kwargs
512
- )
485
+ return await self.execute_with_monitoring(operation_name, operation_func, *args, **kwargs)
513
486
  except ClientError as e:
514
- error_code = e.response.get('Error', {}).get('Code', 'Unknown')
515
-
516
- if error_code in ['ExpiredToken', 'InvalidToken']:
487
+ error_code = e.response.get("Error", {}).get("Code", "Unknown")
488
+
489
+ if error_code in ["ExpiredToken", "InvalidToken"]:
517
490
  print_error(f"AWS token expired during {operation_name}")
518
491
  print_warning("Please refresh your AWS credentials and retry")
519
492
  return None
520
- elif error_code in ['AccessDenied', 'UnauthorizedOperation']:
493
+ elif error_code in ["AccessDenied", "UnauthorizedOperation"]:
521
494
  print_error(f"Permission denied during {operation_name}")
522
495
  print_info("Contact your AWS administrator for required permissions")
523
496
  return None
524
497
  else:
525
498
  # Re-raise other AWS errors
526
499
  raise
527
-
500
+
528
501
  def export_results_to_formats(
529
- self,
530
- result: CloudOpsExecutionResult,
531
- export_dir: Path = None,
532
- formats: List[str] = None
502
+ self, result: CloudOpsExecutionResult, export_dir: Path = None, formats: List[str] = None
533
503
  ) -> Dict[str, str]:
534
504
  """
535
505
  Export results to multiple formats for enterprise reporting.
536
-
506
+
537
507
  Args:
538
508
  result: Execution result to export
539
509
  export_dir: Directory for exported files (default: ./exports)
540
510
  formats: List of formats ['json', 'csv', 'html', 'pdf'] (default: all)
541
-
511
+
542
512
  Returns:
543
513
  Dictionary mapping format to file path
544
514
  """
545
515
  if export_dir is None:
546
516
  export_dir = Path("./exports")
547
-
517
+
548
518
  if formats is None:
549
- formats = ['json', 'csv', 'html'] # PDF requires additional dependencies
550
-
519
+ formats = ["json", "csv", "html"] # PDF requires additional dependencies
520
+
551
521
  export_dir.mkdir(exist_ok=True)
552
522
  exported_files = {}
553
-
523
+
554
524
  # Base filename
555
525
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
556
526
  base_filename = f"{result.scenario.value}_{timestamp}"
557
-
527
+
558
528
  # JSON Export
559
- if 'json' in formats:
529
+ if "json" in formats:
560
530
  json_file = export_dir / f"{base_filename}.json"
561
- with open(json_file, 'w') as f:
531
+ with open(json_file, "w") as f:
562
532
  json.dump(result.dict(), f, indent=2, default=str)
563
- exported_files['json'] = str(json_file)
533
+ exported_files["json"] = str(json_file)
564
534
  print_success(f"JSON export: {json_file}")
565
-
535
+
566
536
  # CSV Export (summary metrics)
567
- if 'csv' in formats:
537
+ if "csv" in formats:
568
538
  csv_file = export_dir / f"{base_filename}_summary.csv"
569
539
  summary_df = pd.DataFrame([result.summary_metrics])
570
540
  summary_df.to_csv(csv_file, index=False)
571
- exported_files['csv'] = str(csv_file)
541
+ exported_files["csv"] = str(csv_file)
572
542
  print_success(f"CSV export: {csv_file}")
573
-
543
+
574
544
  # Resource impacts CSV
575
545
  if result.resources_impacted:
576
546
  impacts_csv = export_dir / f"{base_filename}_impacts.csv"
577
547
  impacts_data = [impact.dict() for impact in result.resources_impacted]
578
548
  impacts_df = pd.DataFrame(impacts_data)
579
549
  impacts_df.to_csv(impacts_csv, index=False)
580
- exported_files['csv_impacts'] = str(impacts_csv)
550
+ exported_files["csv_impacts"] = str(impacts_csv)
581
551
  print_info(f"Resource impacts CSV: {impacts_csv}")
582
-
552
+
583
553
  # HTML Export (Rich console output)
584
- if 'html' in formats:
554
+ if "html" in formats:
585
555
  html_file = export_dir / f"{base_filename}.html"
586
556
  # Create HTML version of the results
587
557
  html_content = self._create_html_report(result)
588
- with open(html_file, 'w') as f:
558
+ with open(html_file, "w") as f:
589
559
  f.write(html_content)
590
- exported_files['html'] = str(html_file)
560
+ exported_files["html"] = str(html_file)
591
561
  print_success(f"HTML export: {html_file}")
592
-
562
+
593
563
  return exported_files
594
-
564
+
595
565
  def _create_html_report(self, result: CloudOpsExecutionResult) -> str:
596
566
  """
597
567
  Create HTML report from execution result.
598
-
568
+
599
569
  Args:
600
570
  result: Execution result
601
-
571
+
602
572
  Returns:
603
573
  HTML content string
604
574
  """
@@ -626,8 +596,8 @@ class NotebookFramework(CloudOpsBase):
626
596
  <p><strong>Scenario:</strong> {result.scenario_name}</p>
627
597
  <p><strong>Execution Time:</strong> {result.execution_time:.1f} seconds</p>
628
598
  <p><strong>Status:</strong>
629
- <span class="{'success' if result.success else 'error'}">
630
- {'✅ Success' if result.success else '❌ Failed'}
599
+ <span class="{"success" if result.success else "error"}">
600
+ {"✅ Success" if result.success else "❌ Failed"}
631
601
  </span>
632
602
  </p>
633
603
  <p><strong>Resources Analyzed:</strong> {result.resources_analyzed:,}</p>
@@ -658,7 +628,7 @@ class NotebookFramework(CloudOpsBase):
658
628
  </div>
659
629
 
660
630
  <footer style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; color: #666;">
661
- <p>Generated by CloudOps Runbooks v0.9.1 at {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p>
631
+ <p>Generated by CloudOps Runbooks latest version at {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p>
662
632
  </footer>
663
633
  </body>
664
634
  </html>
@@ -667,10 +637,4 @@ class NotebookFramework(CloudOpsBase):
667
637
 
668
638
 
669
639
  # Export framework components
670
- __all__ = [
671
- "NotebookFramework",
672
- "NotebookMode",
673
- "AuthenticationStatus",
674
- "AuthenticationResult",
675
- "ScenarioMetadata"
676
- ]
640
+ __all__ = ["NotebookFramework", "NotebookMode", "AuthenticationStatus", "AuthenticationResult", "ScenarioMetadata"]