runbooks 0.7.7__py3-none-any.whl → 0.9.0__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 (157) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/base.py +2 -2
  3. runbooks/cfat/README.md +12 -1
  4. runbooks/cfat/__init__.py +8 -4
  5. runbooks/cfat/assessment/collectors.py +171 -14
  6. runbooks/cfat/assessment/compliance.py +546 -522
  7. runbooks/cfat/assessment/runner.py +129 -10
  8. runbooks/cfat/models.py +6 -2
  9. runbooks/common/__init__.py +152 -0
  10. runbooks/common/accuracy_validator.py +1039 -0
  11. runbooks/common/context_logger.py +440 -0
  12. runbooks/common/cross_module_integration.py +594 -0
  13. runbooks/common/enhanced_exception_handler.py +1108 -0
  14. runbooks/common/enterprise_audit_integration.py +634 -0
  15. runbooks/common/logger.py +14 -0
  16. runbooks/common/mcp_integration.py +539 -0
  17. runbooks/common/performance_monitor.py +387 -0
  18. runbooks/common/profile_utils.py +216 -0
  19. runbooks/common/rich_utils.py +622 -0
  20. runbooks/enterprise/__init__.py +68 -0
  21. runbooks/enterprise/error_handling.py +411 -0
  22. runbooks/enterprise/logging.py +439 -0
  23. runbooks/enterprise/multi_tenant.py +583 -0
  24. runbooks/feedback/user_feedback_collector.py +440 -0
  25. runbooks/finops/README.md +129 -14
  26. runbooks/finops/__init__.py +22 -3
  27. runbooks/finops/account_resolver.py +279 -0
  28. runbooks/finops/accuracy_cross_validator.py +638 -0
  29. runbooks/finops/aws_client.py +721 -36
  30. runbooks/finops/budget_integration.py +313 -0
  31. runbooks/finops/cli.py +90 -33
  32. runbooks/finops/cost_processor.py +211 -37
  33. runbooks/finops/dashboard_router.py +900 -0
  34. runbooks/finops/dashboard_runner.py +1334 -399
  35. runbooks/finops/embedded_mcp_validator.py +288 -0
  36. runbooks/finops/enhanced_dashboard_runner.py +526 -0
  37. runbooks/finops/enhanced_progress.py +327 -0
  38. runbooks/finops/enhanced_trend_visualization.py +423 -0
  39. runbooks/finops/finops_dashboard.py +41 -0
  40. runbooks/finops/helpers.py +639 -323
  41. runbooks/finops/iam_guidance.py +400 -0
  42. runbooks/finops/markdown_exporter.py +466 -0
  43. runbooks/finops/multi_dashboard.py +1502 -0
  44. runbooks/finops/optimizer.py +396 -395
  45. runbooks/finops/profile_processor.py +2 -2
  46. runbooks/finops/runbooks.inventory.organizations_discovery.log +0 -0
  47. runbooks/finops/runbooks.security.report_generator.log +0 -0
  48. runbooks/finops/runbooks.security.run_script.log +0 -0
  49. runbooks/finops/runbooks.security.security_export.log +0 -0
  50. runbooks/finops/service_mapping.py +195 -0
  51. runbooks/finops/single_dashboard.py +710 -0
  52. runbooks/finops/tests/__init__.py +19 -0
  53. runbooks/finops/tests/results_test_finops_dashboard.xml +1 -0
  54. runbooks/finops/tests/run_comprehensive_tests.py +421 -0
  55. runbooks/finops/tests/run_tests.py +305 -0
  56. runbooks/finops/tests/test_finops_dashboard.py +705 -0
  57. runbooks/finops/tests/test_integration.py +477 -0
  58. runbooks/finops/tests/test_performance.py +380 -0
  59. runbooks/finops/tests/test_performance_benchmarks.py +500 -0
  60. runbooks/finops/tests/test_reference_images_validation.py +867 -0
  61. runbooks/finops/tests/test_single_account_features.py +715 -0
  62. runbooks/finops/tests/validate_test_suite.py +220 -0
  63. runbooks/finops/types.py +1 -1
  64. runbooks/hitl/enhanced_workflow_engine.py +725 -0
  65. runbooks/inventory/README.md +12 -1
  66. runbooks/inventory/artifacts/scale-optimize-status.txt +12 -0
  67. runbooks/inventory/collectors/aws_comprehensive.py +192 -185
  68. runbooks/inventory/collectors/enterprise_scale.py +281 -0
  69. runbooks/inventory/core/collector.py +299 -12
  70. runbooks/inventory/list_ec2_instances.py +21 -20
  71. runbooks/inventory/list_ssm_parameters.py +31 -3
  72. runbooks/inventory/organizations_discovery.py +1315 -0
  73. runbooks/inventory/rich_inventory_display.py +360 -0
  74. runbooks/inventory/run_on_multi_accounts.py +32 -16
  75. runbooks/inventory/runbooks.security.report_generator.log +0 -0
  76. runbooks/inventory/runbooks.security.run_script.log +0 -0
  77. runbooks/inventory/vpc_flow_analyzer.py +1030 -0
  78. runbooks/main.py +4171 -1615
  79. runbooks/metrics/dora_metrics_engine.py +1293 -0
  80. runbooks/monitoring/performance_monitor.py +433 -0
  81. runbooks/operate/README.md +394 -0
  82. runbooks/operate/__init__.py +2 -2
  83. runbooks/operate/base.py +291 -11
  84. runbooks/operate/deployment_framework.py +1032 -0
  85. runbooks/operate/deployment_validator.py +853 -0
  86. runbooks/operate/dynamodb_operations.py +10 -6
  87. runbooks/operate/ec2_operations.py +321 -11
  88. runbooks/operate/executive_dashboard.py +779 -0
  89. runbooks/operate/mcp_integration.py +750 -0
  90. runbooks/operate/nat_gateway_operations.py +1120 -0
  91. runbooks/operate/networking_cost_heatmap.py +685 -0
  92. runbooks/operate/privatelink_operations.py +940 -0
  93. runbooks/operate/s3_operations.py +10 -6
  94. runbooks/operate/vpc_endpoints.py +644 -0
  95. runbooks/operate/vpc_operations.py +1038 -0
  96. runbooks/remediation/README.md +489 -13
  97. runbooks/remediation/__init__.py +2 -2
  98. runbooks/remediation/acm_remediation.py +1 -1
  99. runbooks/remediation/base.py +1 -1
  100. runbooks/remediation/cloudtrail_remediation.py +1 -1
  101. runbooks/remediation/cognito_remediation.py +1 -1
  102. runbooks/remediation/commons.py +8 -4
  103. runbooks/remediation/dynamodb_remediation.py +1 -1
  104. runbooks/remediation/ec2_remediation.py +1 -1
  105. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -1
  106. runbooks/remediation/kms_enable_key_rotation.py +1 -1
  107. runbooks/remediation/kms_remediation.py +1 -1
  108. runbooks/remediation/lambda_remediation.py +1 -1
  109. runbooks/remediation/multi_account.py +1 -1
  110. runbooks/remediation/rds_remediation.py +1 -1
  111. runbooks/remediation/s3_block_public_access.py +1 -1
  112. runbooks/remediation/s3_enable_access_logging.py +1 -1
  113. runbooks/remediation/s3_encryption.py +1 -1
  114. runbooks/remediation/s3_remediation.py +1 -1
  115. runbooks/remediation/vpc_remediation.py +475 -0
  116. runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
  117. runbooks/security/README.md +12 -1
  118. runbooks/security/__init__.py +166 -33
  119. runbooks/security/compliance_automation.py +634 -0
  120. runbooks/security/compliance_automation_engine.py +1021 -0
  121. runbooks/security/enterprise_security_framework.py +931 -0
  122. runbooks/security/enterprise_security_policies.json +293 -0
  123. runbooks/security/integration_test_enterprise_security.py +879 -0
  124. runbooks/security/module_security_integrator.py +641 -0
  125. runbooks/security/report_generator.py +10 -0
  126. runbooks/security/run_script.py +27 -5
  127. runbooks/security/security_baseline_tester.py +153 -27
  128. runbooks/security/security_export.py +456 -0
  129. runbooks/sre/README.md +472 -0
  130. runbooks/sre/__init__.py +33 -0
  131. runbooks/sre/mcp_reliability_engine.py +1049 -0
  132. runbooks/sre/performance_optimization_engine.py +1032 -0
  133. runbooks/sre/reliability_monitoring_framework.py +1011 -0
  134. runbooks/validation/__init__.py +10 -0
  135. runbooks/validation/benchmark.py +489 -0
  136. runbooks/validation/cli.py +368 -0
  137. runbooks/validation/mcp_validator.py +797 -0
  138. runbooks/vpc/README.md +478 -0
  139. runbooks/vpc/__init__.py +38 -0
  140. runbooks/vpc/config.py +212 -0
  141. runbooks/vpc/cost_engine.py +347 -0
  142. runbooks/vpc/heatmap_engine.py +605 -0
  143. runbooks/vpc/manager_interface.py +649 -0
  144. runbooks/vpc/networking_wrapper.py +1289 -0
  145. runbooks/vpc/rich_formatters.py +693 -0
  146. runbooks/vpc/tests/__init__.py +5 -0
  147. runbooks/vpc/tests/conftest.py +356 -0
  148. runbooks/vpc/tests/test_cli_integration.py +530 -0
  149. runbooks/vpc/tests/test_config.py +458 -0
  150. runbooks/vpc/tests/test_cost_engine.py +479 -0
  151. runbooks/vpc/tests/test_networking_wrapper.py +512 -0
  152. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/METADATA +175 -65
  153. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/RECORD +157 -60
  154. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/entry_points.txt +1 -1
  155. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/WHEEL +0 -0
  156. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/licenses/LICENSE +0 -0
  157. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,622 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Rich Library Utilities for CloudOps Runbooks Platform
4
+
5
+ This module provides centralized Rich components and styling for consistent,
6
+ beautiful terminal output across all CloudOps Runbooks modules.
7
+
8
+ Features:
9
+ - Custom CloudOps theme and color schemes
10
+ - Reusable UI components (headers, footers, panels)
11
+ - Standard progress bars and spinners
12
+ - Consistent table styles
13
+ - Error/warning/success message formatting
14
+ - Tree displays for hierarchical data
15
+ - Layout templates for complex displays
16
+
17
+ Author: CloudOps Runbooks Team
18
+ Version: 0.7.8
19
+ """
20
+
21
+ from datetime import datetime
22
+ from typing import Any, Dict, List, Optional, Union
23
+
24
+ from rich import box
25
+ from rich.columns import Columns
26
+ from rich.console import Console
27
+ from rich.layout import Layout
28
+ from rich.markdown import Markdown
29
+ from rich.panel import Panel
30
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn, TimeElapsedColumn
31
+ from rich.rule import Rule
32
+ from rich.style import Style
33
+ from rich.syntax import Syntax
34
+ from rich.table import Table
35
+ from rich.text import Text
36
+ from rich.theme import Theme
37
+ from rich.tree import Tree
38
+
39
+ # CloudOps Custom Theme
40
+ CLOUDOPS_THEME = Theme(
41
+ {
42
+ "info": "cyan",
43
+ "success": "green bold",
44
+ "warning": "yellow bold",
45
+ "error": "red bold",
46
+ "critical": "red bold reverse",
47
+ "highlight": "bright_blue bold",
48
+ "header": "bright_cyan bold",
49
+ "subheader": "cyan",
50
+ "dim": "dim white",
51
+ "resource": "bright_magenta",
52
+ "cost": "bright_green",
53
+ "security": "bright_red",
54
+ "compliance": "bright_yellow",
55
+ }
56
+ )
57
+
58
+ # Initialize console with custom theme
59
+ console = Console(theme=CLOUDOPS_THEME)
60
+
61
+ # Status indicators
62
+ STATUS_INDICATORS = {
63
+ "success": "🟢",
64
+ "warning": "🟡",
65
+ "error": "🔴",
66
+ "info": "🔵",
67
+ "pending": "⚪",
68
+ "running": "🔄",
69
+ "stopped": "⏹️",
70
+ "critical": "🚨",
71
+ }
72
+
73
+
74
+ def get_console() -> Console:
75
+ """Get the themed console instance."""
76
+ return console
77
+
78
+
79
+ def get_context_aware_console():
80
+ """
81
+ Get a context-aware console that adapts to CLI vs Jupyter environments.
82
+
83
+ This function is a bridge to the context_logger module to maintain
84
+ backward compatibility while enabling context awareness.
85
+
86
+ Returns:
87
+ Context-aware console instance
88
+ """
89
+ try:
90
+ from runbooks.common.context_logger import get_context_console
91
+
92
+ return get_context_console()
93
+ except ImportError:
94
+ # Fallback to regular console if context_logger not available
95
+ return console
96
+
97
+
98
+ def print_header(title: str, version: str = "0.7.8") -> None:
99
+ """
100
+ Print a consistent header for all modules.
101
+
102
+ Args:
103
+ title: Module title
104
+ version: Module version
105
+ """
106
+ header_text = Text()
107
+ header_text.append("CloudOps Runbooks ", style="header")
108
+ header_text.append(f"| {title} ", style="subheader")
109
+ header_text.append(f"v{version}", style="dim")
110
+
111
+ console.print()
112
+ console.print(Panel(header_text, box=box.DOUBLE, style="header"))
113
+ console.print()
114
+
115
+
116
+ def print_banner() -> None:
117
+ """Print the CloudOps Runbooks ASCII banner."""
118
+ banner = r"""
119
+ ╔═══════════════════════════════════════════════════════════════╗
120
+ ║ _____ _ _ ____ ____ ║
121
+ ║ / ____| | | |/ __ \ | _ \ ║
122
+ ║ | | | | ___ _ _ __| | | | |_ __ ___ | |_) |_ _ __ ║
123
+ ║ | | | |/ _ \| | | |/ _` | | | | '_ \/ __| | _ <| | | '_ \ ║
124
+ ║ | |____| | (_) | |_| | (_| | |__| | |_) \__ \ | |_) | |_| | | |║
125
+ ║ \_____|_|\___/ \__,_|\__,_|\____/| .__/|___/ |____/ \__,_|_| |║
126
+ ║ | | ║
127
+ ║ Enterprise AWS Automation |_| Platform v0.7.8 ║
128
+ ╚═══════════════════════════════════════════════════════════════╝
129
+ """
130
+ console.print(banner, style="header")
131
+
132
+
133
+ def create_table(
134
+ title: Optional[str] = None,
135
+ columns: List[Dict[str, Any]] = None,
136
+ show_header: bool = True,
137
+ show_footer: bool = False,
138
+ box_style: Any = box.ROUNDED,
139
+ title_style: str = "header",
140
+ ) -> Table:
141
+ """
142
+ Create a consistent styled table.
143
+
144
+ Args:
145
+ title: Table title
146
+ columns: List of column definitions [{"name": "Col1", "style": "cyan", "justify": "left"}]
147
+ show_header: Show header row
148
+ show_footer: Show footer row
149
+ box_style: Rich box style
150
+ title_style: Style for title
151
+
152
+ Returns:
153
+ Configured Table object
154
+ """
155
+ table = Table(
156
+ title=title,
157
+ show_header=show_header,
158
+ show_footer=show_footer,
159
+ box=box_style,
160
+ title_style=title_style,
161
+ header_style="bold",
162
+ row_styles=["none", "dim"], # Alternating row colors
163
+ )
164
+
165
+ if columns:
166
+ for col in columns:
167
+ table.add_column(
168
+ col.get("name", ""),
169
+ style=col.get("style", ""),
170
+ justify=col.get("justify", "left"),
171
+ no_wrap=col.get("no_wrap", False),
172
+ )
173
+
174
+ return table
175
+
176
+
177
+ def create_progress_bar(description: str = "Processing") -> Progress:
178
+ """
179
+ Create a consistent progress bar.
180
+
181
+ Args:
182
+ description: Progress bar description
183
+
184
+ Returns:
185
+ Configured Progress object
186
+ """
187
+ return Progress(
188
+ SpinnerColumn(spinner_name="dots", style="cyan"),
189
+ TextColumn("[progress.description]{task.description}"),
190
+ BarColumn(bar_width=40, style="cyan", complete_style="green"),
191
+ TaskProgressColumn(),
192
+ TimeElapsedColumn(),
193
+ console=console,
194
+ transient=True,
195
+ )
196
+
197
+
198
+ def print_status(message: str, status: str = "info") -> None:
199
+ """
200
+ Print a status message with appropriate styling and indicator.
201
+
202
+ Args:
203
+ message: Status message
204
+ status: Status type (success, warning, error, info, critical)
205
+ """
206
+ indicator = STATUS_INDICATORS.get(status, "")
207
+ style = status if status in ["success", "warning", "error", "critical", "info"] else "info"
208
+ console.print(f"{indicator} {message}", style=style)
209
+
210
+
211
+ def print_error(message: str, exception: Optional[Exception] = None) -> None:
212
+ """
213
+ Print an error message with optional exception details.
214
+
215
+ Args:
216
+ message: Error message
217
+ exception: Optional exception object
218
+ """
219
+ console.print(f"{STATUS_INDICATORS['error']} {message}", style="error")
220
+ if exception:
221
+ console.print(f" Details: {str(exception)}", style="dim")
222
+
223
+
224
+ def print_success(message: str) -> None:
225
+ """
226
+ Print a success message.
227
+
228
+ Args:
229
+ message: Success message
230
+ """
231
+ console.print(f"{STATUS_INDICATORS['success']} {message}", style="success")
232
+
233
+
234
+ def print_warning(message: str) -> None:
235
+ """
236
+ Print a warning message.
237
+
238
+ Args:
239
+ message: Warning message
240
+ """
241
+ console.print(f"{STATUS_INDICATORS['warning']} {message}", style="warning")
242
+
243
+
244
+ def print_info(message: str) -> None:
245
+ """
246
+ Print an info message.
247
+
248
+ Args:
249
+ message: Info message
250
+ """
251
+ console.print(f"{STATUS_INDICATORS['info']} {message}", style="info")
252
+
253
+
254
+ def create_tree(label: str, style: str = "cyan") -> Tree:
255
+ """
256
+ Create a tree for hierarchical display.
257
+
258
+ Args:
259
+ label: Root label
260
+ style: Tree style
261
+
262
+ Returns:
263
+ Tree object
264
+ """
265
+ return Tree(label, style=style, guide_style="dim")
266
+
267
+
268
+ def print_separator(label: Optional[str] = None, style: str = "dim") -> None:
269
+ """
270
+ Print a separator line.
271
+
272
+ Args:
273
+ label: Optional label for separator
274
+ style: Separator style
275
+ """
276
+ if label:
277
+ console.print(Rule(label, style=style))
278
+ else:
279
+ console.print(Rule(style=style))
280
+
281
+
282
+ def create_panel(
283
+ content: Any,
284
+ title: Optional[str] = None,
285
+ subtitle: Optional[str] = None,
286
+ border_style: str = "cyan",
287
+ padding: int = 1,
288
+ ) -> Panel:
289
+ """
290
+ Create a panel for highlighting content.
291
+
292
+ Args:
293
+ content: Panel content
294
+ title: Panel title
295
+ subtitle: Panel subtitle
296
+ border_style: Border color/style
297
+ padding: Internal padding
298
+
299
+ Returns:
300
+ Panel object
301
+ """
302
+ return Panel(
303
+ content, title=title, subtitle=subtitle, border_style=border_style, padding=(padding, padding), expand=False
304
+ )
305
+
306
+
307
+ def format_cost(amount: float, currency: str = "USD") -> Text:
308
+ """
309
+ Format a cost value with appropriate styling.
310
+
311
+ Args:
312
+ amount: Cost amount
313
+ currency: Currency code
314
+
315
+ Returns:
316
+ Formatted Text object
317
+ """
318
+ text = Text()
319
+ symbol = "$" if currency == "USD" else currency
320
+ if amount >= 10000:
321
+ text.append(f"{symbol}{amount:,.2f}", style="cost bold")
322
+ elif amount >= 1000:
323
+ text.append(f"{symbol}{amount:,.2f}", style="cost")
324
+ else:
325
+ text.append(f"{symbol}{amount:,.2f}", style="dim")
326
+ return text
327
+
328
+
329
+ def format_resource_count(count: int, resource_type: str) -> Text:
330
+ """
331
+ Format a resource count with appropriate styling.
332
+
333
+ Args:
334
+ count: Resource count
335
+ resource_type: Type of resource
336
+
337
+ Returns:
338
+ Formatted Text object
339
+ """
340
+ text = Text()
341
+ if count == 0:
342
+ text.append(f"{count} {resource_type}", style="dim")
343
+ elif count > 100:
344
+ text.append(f"{count} {resource_type}", style="warning")
345
+ else:
346
+ text.append(f"{count} {resource_type}", style="resource")
347
+ return text
348
+
349
+
350
+ def create_display_profile_name(profile_name: str, max_length: int = 25, context_aware: bool = True) -> str:
351
+ """
352
+ Create user-friendly display version of AWS profile names for better readability.
353
+
354
+ This function intelligently truncates long enterprise profile names while preserving
355
+ meaningful information for identification. Full names remain available for AWS API calls.
356
+
357
+ Examples:
358
+ 'ams-admin-Billing-ReadOnlyAccess-909135376185' → 'ams-admin-Billing-9091...'
359
+ 'ams-centralised-ops-ReadOnlyAccess-335083429030' → 'ams-centralised-ops-3350...'
360
+ 'short-profile' → 'short-profile' (no truncation needed)
361
+
362
+ Args:
363
+ profile_name: Full AWS profile name
364
+ max_length: Maximum display length (default 25 for table formatting)
365
+ context_aware: Whether to adapt truncation based on execution context
366
+
367
+ Returns:
368
+ User-friendly display name for console output
369
+ """
370
+ if not profile_name or len(profile_name) <= max_length:
371
+ return profile_name
372
+
373
+ # Context-aware length adjustment
374
+ if context_aware:
375
+ try:
376
+ from runbooks.common.context_logger import ExecutionContext, get_context_config
377
+
378
+ config = get_context_config()
379
+
380
+ if config.context == ExecutionContext.JUPYTER:
381
+ # Shorter names for notebook tables
382
+ max_length = min(max_length, 20)
383
+ elif config.context == ExecutionContext.CLI:
384
+ # Slightly longer for CLI terminals
385
+ max_length = min(max_length + 5, 30)
386
+ except ImportError:
387
+ # Fallback if context_logger not available
388
+ pass
389
+
390
+ # Smart truncation strategy for AWS profile patterns
391
+ # Common patterns: ams-{type}-{service}-{permissions}-{account_id}
392
+
393
+ if "-" in profile_name:
394
+ parts = profile_name.split("-")
395
+
396
+ # Strategy 1: Keep meaningful prefix + account ID suffix
397
+ if len(parts) >= 4 and parts[-1].isdigit():
398
+ # Enterprise pattern: ams-admin-Billing-ReadOnlyAccess-909135376185
399
+ account_id = parts[-1]
400
+ prefix_parts = parts[:-2] # Skip permissions part for brevity
401
+
402
+ prefix = "-".join(prefix_parts)
403
+ account_short = account_id[:4] # First 4 digits of account ID
404
+
405
+ truncated = f"{prefix}-{account_short}..."
406
+
407
+ if len(truncated) <= max_length:
408
+ return truncated
409
+
410
+ # Strategy 2: Keep first few meaningful parts
411
+ meaningful_parts = []
412
+ current_length = 0
413
+
414
+ for part in parts:
415
+ # Skip common noise words but keep meaningful ones
416
+ if part.lower() in ["readonlyaccess", "fullaccess", "access"]:
417
+ continue
418
+
419
+ part_with_sep = f"{part}-" if meaningful_parts else part
420
+ if current_length + len(part_with_sep) + 3 <= max_length: # +3 for "..."
421
+ meaningful_parts.append(part)
422
+ current_length += len(part_with_sep)
423
+ else:
424
+ break
425
+
426
+ if len(meaningful_parts) >= 2:
427
+ return f"{'-'.join(meaningful_parts)}..."
428
+
429
+ # Strategy 3: Simple prefix truncation with ellipsis
430
+ return f"{profile_name[: max_length - 3]}..."
431
+
432
+
433
+ def format_profile_name(profile_name: str, style: str = "cyan", display_max_length: int = 25) -> Text:
434
+ """
435
+ Format profile name with consistent styling and intelligent truncation.
436
+
437
+ This function creates a Rich Text object with:
438
+ - Smart truncation for display readability
439
+ - Consistent styling across all modules
440
+ - Hover-friendly formatting (full name in tooltip would be future enhancement)
441
+
442
+ Args:
443
+ profile_name: AWS profile name
444
+ style: Rich style for the profile name
445
+ display_max_length: Maximum length for display
446
+
447
+ Returns:
448
+ Rich Text object with formatted profile name
449
+ """
450
+ display_name = create_display_profile_name(profile_name, display_max_length)
451
+
452
+ text = Text()
453
+
454
+ # Add visual indicators for truncated names
455
+ if display_name.endswith("..."):
456
+ # Truncated name - use slightly different style
457
+ text.append(display_name, style=f"{style} italic")
458
+ else:
459
+ # Full name - normal style
460
+ text.append(display_name, style=style)
461
+
462
+ return text
463
+
464
+
465
+ def format_account_name(
466
+ account_name: str, account_id: str, style: str = "bold bright_white", max_length: int = 35
467
+ ) -> str:
468
+ """
469
+ Format account name with ID for consistent enterprise display in tables.
470
+
471
+ This function provides consistent account display formatting across all FinOps dashboards:
472
+ - Account name with intelligent truncation
473
+ - Account ID as secondary line for identification
474
+ - Rich markup for professional presentation
475
+
476
+ Args:
477
+ account_name: Resolved account name from Organizations API
478
+ account_id: AWS account ID
479
+ style: Rich style for the account name
480
+ max_length: Maximum display length for account name
481
+
482
+ Returns:
483
+ Formatted display string with Rich markup
484
+
485
+ Example:
486
+ "Data Management"
487
+ "123456789012"
488
+ """
489
+ if account_name and account_name != account_id and len(account_name.strip()) > 0:
490
+ # We have a resolved account name - format with both name and ID
491
+ display_name = account_name if len(account_name) <= max_length else account_name[: max_length - 3] + "..."
492
+ return f"[{style}]{display_name}[/]\n[dim]{account_id}[/]"
493
+ else:
494
+ # No resolved name available - show account ID prominently
495
+ return f"[{style}]{account_id}[/]"
496
+
497
+
498
+ def create_layout(sections: Dict[str, Any]) -> Layout:
499
+ """
500
+ Create a layout for complex displays.
501
+
502
+ Args:
503
+ sections: Dictionary of layout sections
504
+
505
+ Returns:
506
+ Layout object
507
+ """
508
+ layout = Layout()
509
+
510
+ # Example layout structure
511
+ if "header" in sections:
512
+ layout.split_column(Layout(name="header", size=3), Layout(name="body"), Layout(name="footer", size=3))
513
+ layout["header"].update(sections["header"])
514
+
515
+ if "body" in sections:
516
+ if isinstance(sections["body"], dict):
517
+ layout["body"].split_row(*[Layout(name=k) for k in sections["body"].keys()])
518
+ for key, content in sections["body"].items():
519
+ layout["body"][key].update(content)
520
+ else:
521
+ layout["body"].update(sections["body"])
522
+
523
+ if "footer" in sections:
524
+ layout["footer"].update(sections["footer"])
525
+
526
+ return layout
527
+
528
+
529
+ def print_json(data: Dict[str, Any], title: Optional[str] = None) -> None:
530
+ """
531
+ Print JSON data with syntax highlighting.
532
+
533
+ Args:
534
+ data: JSON data to display
535
+ title: Optional title
536
+ """
537
+ import json
538
+
539
+ json_str = json.dumps(data, indent=2)
540
+ syntax = Syntax(json_str, "json", theme="monokai", line_numbers=False)
541
+ if title:
542
+ console.print(Panel(syntax, title=title, border_style="cyan"))
543
+ else:
544
+ console.print(syntax)
545
+
546
+
547
+ def print_markdown(text: str) -> None:
548
+ """
549
+ Print markdown formatted text.
550
+
551
+ Args:
552
+ text: Markdown text
553
+ """
554
+ md = Markdown(text)
555
+ console.print(md)
556
+
557
+
558
+ def confirm_action(prompt: str, default: bool = False) -> bool:
559
+ """
560
+ Get user confirmation with styled prompt.
561
+
562
+ Args:
563
+ prompt: Confirmation prompt
564
+ default: Default value if user just presses enter
565
+
566
+ Returns:
567
+ User's confirmation choice
568
+ """
569
+ default_text = "[Y/n]" if default else "[y/N]"
570
+ console.print(f"\n{STATUS_INDICATORS['info']} {prompt} {default_text}: ", style="info", end="")
571
+
572
+ response = input().strip().lower()
573
+ if not response:
574
+ return default
575
+ return response in ["y", "yes"]
576
+
577
+
578
+ def create_columns(items: List[Any], equal: bool = True, expand: bool = True) -> Columns:
579
+ """
580
+ Create columns for side-by-side display.
581
+
582
+ Args:
583
+ items: List of items to display in columns
584
+ equal: Equal width columns
585
+ expand: Expand to full width
586
+
587
+ Returns:
588
+ Columns object
589
+ """
590
+ return Columns(items, equal=equal, expand=expand, padding=(0, 2))
591
+
592
+
593
+ # Export all public functions and constants
594
+ __all__ = [
595
+ "CLOUDOPS_THEME",
596
+ "STATUS_INDICATORS",
597
+ "console",
598
+ "get_console",
599
+ "get_context_aware_console",
600
+ "print_header",
601
+ "print_banner",
602
+ "create_table",
603
+ "create_progress_bar",
604
+ "print_status",
605
+ "print_error",
606
+ "print_success",
607
+ "print_warning",
608
+ "print_info",
609
+ "create_tree",
610
+ "print_separator",
611
+ "create_panel",
612
+ "format_cost",
613
+ "format_resource_count",
614
+ "create_display_profile_name",
615
+ "format_profile_name",
616
+ "format_account_name",
617
+ "create_layout",
618
+ "print_json",
619
+ "print_markdown",
620
+ "confirm_action",
621
+ "create_columns",
622
+ ]
@@ -0,0 +1,68 @@
1
+ """
2
+ Enterprise enhancements for CloudOps-Runbooks.
3
+
4
+ This module provides enterprise-grade enhancements including:
5
+ - Advanced error handling with actionable guidance
6
+ - Structured logging for enterprise monitoring
7
+ - Security hardening and compliance validation
8
+ - Enhanced configuration management
9
+ - Professional documentation standards
10
+ """
11
+
12
+ from .error_handling import (
13
+ AWSServiceError,
14
+ ConfigurationError,
15
+ EnterpriseErrorHandler,
16
+ RunbooksException,
17
+ SecurityError,
18
+ ValidationError,
19
+ create_user_friendly_error,
20
+ )
21
+ from .logging import (
22
+ AuditLogger,
23
+ EnterpriseLogger,
24
+ PerformanceLogger,
25
+ configure_enterprise_logging,
26
+ )
27
+ from .security import (
28
+ ComplianceChecker,
29
+ SecurityValidator,
30
+ ZeroTrustValidator,
31
+ sanitize_input,
32
+ validate_aws_permissions,
33
+ )
34
+ from .validation import (
35
+ ConfigValidator,
36
+ InputValidator,
37
+ TypeValidator,
38
+ validate_configuration,
39
+ validate_user_input,
40
+ )
41
+
42
+ __all__ = [
43
+ # Error handling
44
+ "EnterpriseErrorHandler",
45
+ "RunbooksException",
46
+ "ConfigurationError",
47
+ "ValidationError",
48
+ "SecurityError",
49
+ "AWSServiceError",
50
+ "create_user_friendly_error",
51
+ # Logging
52
+ "EnterpriseLogger",
53
+ "AuditLogger",
54
+ "PerformanceLogger",
55
+ "configure_enterprise_logging",
56
+ # Security
57
+ "SecurityValidator",
58
+ "ComplianceChecker",
59
+ "ZeroTrustValidator",
60
+ "sanitize_input",
61
+ "validate_aws_permissions",
62
+ # Validation
63
+ "ConfigValidator",
64
+ "InputValidator",
65
+ "TypeValidator",
66
+ "validate_configuration",
67
+ "validate_user_input",
68
+ ]