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,360 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Rich Inventory Display - Enhanced inventory presentation with Rich library
4
+
5
+ This module provides enterprise-grade inventory display functionality using
6
+ the Rich library for beautiful, consistent CLI output that works in both
7
+ terminal and Jupyter environments.
8
+
9
+ Features:
10
+ - Rich progress bars for long-running operations
11
+ - Professional table formatting for results
12
+ - Status indicators and color coding
13
+ - Performance timing with visual feedback
14
+ - Consistent branding with CloudOps theme
15
+
16
+ Author: CloudOps Runbooks Team
17
+ Version: 0.7.8
18
+ """
19
+
20
+ from datetime import datetime
21
+ from typing import Any, Dict, List, Optional
22
+
23
+ from rich import box
24
+ from rich.console import Console
25
+ from rich.panel import Panel
26
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn
27
+ from rich.table import Table
28
+ from rich.text import Text
29
+ from rich.tree import Tree
30
+
31
+ from runbooks.common.rich_utils import (
32
+ STATUS_INDICATORS,
33
+ console,
34
+ create_panel,
35
+ create_progress_bar,
36
+ create_table,
37
+ print_info,
38
+ print_status,
39
+ print_success,
40
+ )
41
+
42
+
43
+ def display_inventory_header(operation: str, profile: str, accounts: int, regions: int) -> None:
44
+ """
45
+ Display inventory operation header with operation context.
46
+
47
+ Args:
48
+ operation: Type of inventory operation (EC2, RDS, S3, etc.)
49
+ profile: AWS profile being used
50
+ accounts: Number of accounts to scan
51
+ regions: Number of regions to scan
52
+ """
53
+ header_text = f"""
54
+ [bold cyan]🔍 AWS {operation} Inventory Discovery[/bold cyan]
55
+
56
+ [yellow]Profile:[/yellow] {profile}
57
+ [yellow]Scope:[/yellow] {accounts} accounts × {regions} regions = {accounts * regions} total operations
58
+ [yellow]Started:[/yellow] {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
59
+ """
60
+
61
+ console.print(create_panel(header_text.strip(), title="📊 Inventory Operation", border_style="cyan"))
62
+
63
+
64
+ def create_inventory_progress(total_operations: int, operation_name: str = "Scanning Resources") -> Progress:
65
+ """
66
+ Create a Rich progress bar for inventory operations.
67
+
68
+ Args:
69
+ total_operations: Total number of operations to perform
70
+ operation_name: Name of the operation being performed
71
+
72
+ Returns:
73
+ Progress instance for tracking
74
+ """
75
+ return Progress(
76
+ SpinnerColumn(spinner_name="dots", style="cyan"),
77
+ TextColumn("[progress.description]{task.description}"),
78
+ BarColumn(bar_width=40, style="cyan", complete_style="green"),
79
+ TaskProgressColumn(),
80
+ TextColumn("•"),
81
+ TextColumn("[blue]{task.completed}/{task.total} operations"),
82
+ console=console,
83
+ transient=False,
84
+ )
85
+
86
+
87
+ def display_ec2_inventory_results(
88
+ instances: List[Dict[str, Any]], accounts: int, regions: int, timing_info: Optional[Dict] = None
89
+ ) -> None:
90
+ """
91
+ Display EC2 inventory results in a professional Rich table format.
92
+
93
+ Args:
94
+ instances: List of EC2 instance data
95
+ accounts: Number of accounts scanned
96
+ regions: Number of regions scanned
97
+ timing_info: Optional timing information
98
+ """
99
+ # Summary panel first
100
+ total_instances = len(instances)
101
+
102
+ # Count by state
103
+ state_counts = {}
104
+ for instance in instances:
105
+ state = instance.get("State", {}).get("Name", "unknown")
106
+ state_counts[state] = state_counts.get(state, 0) + 1
107
+
108
+ # Create status breakdown
109
+ status_text = ""
110
+ for state, count in sorted(state_counts.items()):
111
+ status_indicator = {
112
+ "running": "🟢",
113
+ "stopped": "🔴",
114
+ "stopping": "🟡",
115
+ "starting": "🟡",
116
+ "terminated": "⚫",
117
+ "terminating": "🟡",
118
+ }.get(state, "⚪")
119
+
120
+ status_text += f"{status_indicator} {state.title()}: {count}\n"
121
+
122
+ summary_content = f"""
123
+ [bold cyan]EC2 Inventory Summary[/bold cyan]
124
+
125
+ [green]Total Instances Found:[/green] {total_instances}
126
+ [green]Accounts Scanned:[/green] {accounts}
127
+ [green]Regions Scanned:[/green] {regions}
128
+
129
+ [bold yellow]Instance States:[/bold yellow]
130
+ {status_text.strip()}
131
+ """
132
+
133
+ console.print(create_panel(summary_content.strip(), title="📊 Discovery Results", border_style="green"))
134
+
135
+ # Detailed results table if instances found
136
+ if instances:
137
+ # Group instances by account for better organization
138
+ instances_by_account = {}
139
+ for instance in instances:
140
+ account_id = instance.get("AccountId", "Unknown")
141
+ if account_id not in instances_by_account:
142
+ instances_by_account[account_id] = []
143
+ instances_by_account[account_id].append(instance)
144
+
145
+ # Create detailed table
146
+ table = create_table(
147
+ title="🖥️ EC2 Instance Details",
148
+ columns=[
149
+ {"name": "Account", "style": "cyan"},
150
+ {"name": "Region", "style": "yellow"},
151
+ {"name": "Instance ID", "style": "magenta"},
152
+ {"name": "Type", "style": "blue"},
153
+ {"name": "State", "style": "green"},
154
+ {"name": "Name", "style": "white"},
155
+ ],
156
+ box_style=box.ROUNDED,
157
+ )
158
+
159
+ # Add rows (show first 50 instances to avoid overwhelming output)
160
+ displayed_count = 0
161
+ for account_id in sorted(instances_by_account.keys()):
162
+ account_instances = instances_by_account[account_id][:10] # Max 10 per account
163
+
164
+ for instance in account_instances:
165
+ if displayed_count >= 50: # Overall limit
166
+ break
167
+
168
+ # Extract instance information
169
+ instance_id = instance.get("InstanceId", "N/A")
170
+ instance_type = instance.get("InstanceType", "N/A")
171
+ state = instance.get("State", {}).get("Name", "unknown")
172
+ region = instance.get("Region", "N/A")
173
+
174
+ # Get instance name from tags
175
+ instance_name = "N/A"
176
+ tags = instance.get("Tags", [])
177
+ for tag in tags:
178
+ if tag.get("Key") == "Name":
179
+ instance_name = tag.get("Value", "N/A")
180
+ break
181
+
182
+ # Style state with appropriate color
183
+ state_styled = {
184
+ "running": "[green]🟢 Running[/green]",
185
+ "stopped": "[red]🔴 Stopped[/red]",
186
+ "stopping": "[yellow]🟡 Stopping[/yellow]",
187
+ "starting": "[yellow]🟡 Starting[/yellow]",
188
+ "terminated": "[dim]⚫ Terminated[/dim]",
189
+ "terminating": "[yellow]🟡 Terminating[/yellow]",
190
+ }.get(state, f"[white]⚪ {state.title()}[/white]")
191
+
192
+ table.add_row(
193
+ account_id[:12], # Truncate account ID
194
+ region,
195
+ instance_id,
196
+ instance_type,
197
+ state_styled,
198
+ instance_name[:20] if instance_name != "N/A" else "N/A", # Truncate long names
199
+ )
200
+
201
+ displayed_count += 1
202
+
203
+ console.print(table)
204
+
205
+ # Show truncation message if needed
206
+ if total_instances > 50:
207
+ console.print(f"\n[dim]Showing first 50 instances. Total found: {total_instances}[/dim]")
208
+
209
+ # Timing information
210
+ if timing_info:
211
+ execution_time = timing_info.get("total_time", 0)
212
+ print_success(f"✅ Inventory scan completed in {execution_time:.2f} seconds")
213
+
214
+ print_info("💡 Use --output json or --output csv to export complete results")
215
+
216
+
217
+ def display_generic_inventory_results(
218
+ resource_type: str, resources: List[Dict[str, Any]], accounts: int, regions: int
219
+ ) -> None:
220
+ """
221
+ Display generic inventory results for any resource type.
222
+
223
+ Args:
224
+ resource_type: Type of AWS resource (RDS, S3, Lambda, etc.)
225
+ resources: List of resource data
226
+ accounts: Number of accounts scanned
227
+ regions: Number of regions scanned
228
+ """
229
+ total_resources = len(resources)
230
+
231
+ # Resource type icons
232
+ resource_icons = {
233
+ "rds": "🗄️",
234
+ "s3": "🪣",
235
+ "lambda": "⚡",
236
+ "vpc": "🌐",
237
+ "iam": "👤",
238
+ "cloudformation": "📚",
239
+ "ssm": "🔑",
240
+ "route53": "🌍",
241
+ }
242
+
243
+ icon = resource_icons.get(resource_type.lower(), "📦")
244
+
245
+ summary_content = f"""
246
+ [bold cyan]{resource_type.upper()} Inventory Summary[/bold cyan]
247
+
248
+ [green]Total Resources Found:[/green] {total_resources}
249
+ [green]Accounts Scanned:[/green] {accounts}
250
+ [green]Regions Scanned:[/green] {regions}
251
+ """
252
+
253
+ console.print(create_panel(summary_content.strip(), title=f"{icon} Discovery Results", border_style="green"))
254
+
255
+ if total_resources > 0:
256
+ print_success(f"✅ Found {total_resources} {resource_type} resources across {accounts} accounts")
257
+ else:
258
+ print_info(f"ℹ️ No {resource_type} resources found in the specified scope")
259
+
260
+
261
+ def display_inventory_error(error_message: str, suggestions: Optional[List[str]] = None) -> None:
262
+ """
263
+ Display inventory operation error with helpful suggestions.
264
+
265
+ Args:
266
+ error_message: Error message to display
267
+ suggestions: Optional list of suggestions for resolution
268
+ """
269
+ error_content = f"[bold red]❌ Inventory Operation Failed[/bold red]\n\n{error_message}"
270
+
271
+ if suggestions:
272
+ error_content += "\n\n[yellow]💡 Suggestions:[/yellow]\n"
273
+ for suggestion in suggestions:
274
+ error_content += f" • {suggestion}\n"
275
+
276
+ console.print(create_panel(error_content.strip(), title="🚨 Error", border_style="red", padding=1))
277
+
278
+
279
+ def display_multi_resource_summary(
280
+ resource_counts: Dict[str, int], accounts: int, regions: int, execution_time: float
281
+ ) -> None:
282
+ """
283
+ Display summary for multi-resource inventory operations.
284
+
285
+ Args:
286
+ resource_counts: Dictionary of resource type to count
287
+ accounts: Number of accounts scanned
288
+ regions: Number of regions scanned
289
+ execution_time: Total execution time in seconds
290
+ """
291
+ # Create summary table
292
+ table = create_table(
293
+ title="📊 Multi-Resource Inventory Summary",
294
+ columns=[
295
+ {"name": "Resource Type", "style": "cyan"},
296
+ {"name": "Count", "style": "green", "justify": "right"},
297
+ {"name": "Status", "style": "yellow"},
298
+ ],
299
+ )
300
+
301
+ total_resources = 0
302
+ for resource_type, count in sorted(resource_counts.items()):
303
+ status = "✅ Found" if count > 0 else "⚪ None"
304
+ table.add_row(resource_type.title(), str(count), status)
305
+ total_resources += count
306
+
307
+ console.print(table)
308
+
309
+ # Overall summary
310
+ summary_text = f"""
311
+ [bold green]Overall Summary[/bold green]
312
+
313
+ [cyan]Total Resources:[/cyan] {total_resources}
314
+ [cyan]Accounts Scanned:[/cyan] {accounts}
315
+ [cyan]Regions Scanned:[/cyan] {regions}
316
+ [cyan]Execution Time:[/cyan] {execution_time:.2f} seconds
317
+ [cyan]Performance:[/cyan] {(accounts * regions) / execution_time:.1f} operations/second
318
+ """
319
+
320
+ console.print(create_panel(summary_text.strip(), title="🎯 Inventory Complete", border_style="bright_blue"))
321
+
322
+
323
+ def display_account_tree(accounts_data: Dict[str, Dict]) -> None:
324
+ """
325
+ Display account and resource hierarchy as a Rich tree.
326
+
327
+ Args:
328
+ accounts_data: Nested dictionary of account -> resource data
329
+ """
330
+ tree = Tree("🏢 [bold cyan]AWS Organization Structure[/bold cyan]")
331
+
332
+ for account_id, account_data in accounts_data.items():
333
+ account_name = account_data.get("account_name", "Unknown")
334
+ account_branch = tree.add(f"📊 [yellow]Account: {account_id}[/yellow] ({account_name})")
335
+
336
+ # Add regions
337
+ regions = account_data.get("regions", {})
338
+ for region, region_data in regions.items():
339
+ region_branch = account_branch.add(f"🌍 [green]Region: {region}[/green]")
340
+
341
+ # Add resource counts
342
+ for resource_type, count in region_data.get("resource_counts", {}).items():
343
+ if count > 0:
344
+ icon = {"ec2": "🖥️", "rds": "🗄️", "s3": "🪣", "lambda": "⚡"}.get(resource_type, "📦")
345
+
346
+ region_branch.add(f"{icon} {resource_type.upper()}: [bold]{count}[/bold] resources")
347
+
348
+ console.print(tree)
349
+
350
+
351
+ # Export public functions
352
+ __all__ = [
353
+ "display_inventory_header",
354
+ "create_inventory_progress",
355
+ "display_ec2_inventory_results",
356
+ "display_generic_inventory_results",
357
+ "display_inventory_error",
358
+ "display_multi_resource_summary",
359
+ "display_account_tree",
360
+ ]
@@ -8,6 +8,11 @@ from account_class import aws_acct_access
8
8
  from ArgumentsClass import CommonArguments
9
9
  from botocore.exceptions import ClientError
10
10
  from colorama import Fore, init
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+
14
+ # Initialize Rich console
15
+ console = Console()
11
16
 
12
17
  init()
13
18
  __version__ = "2023.05.04"
@@ -57,23 +62,23 @@ def check_account_access(faws_acct, faccount_num, fAccessRole=None):
57
62
  return_response = {"Credentials": credentials, "Success": True, "ErrorMessage": ""}
58
63
  return return_response
59
64
  except ClientError as my_Error:
60
- print(f"Client Error: {my_Error}")
65
+ console.print(f"[red]❌ Client Error: {my_Error}[/red]")
61
66
  return_response = {"Success": False, "ErrorMessage": "Client Error"}
62
67
  return return_response
63
68
  except sts_client.exceptions.MalformedPolicyDocumentException as my_Error:
64
- print(f"MalformedPolicy: {my_Error}")
69
+ console.print(f"[red]❌ MalformedPolicy: {my_Error}[/red]")
65
70
  return_response = {"Success": False, "ErrorMessage": "Malformed Policy"}
66
71
  return return_response
67
72
  except sts_client.exceptions.PackedPolicyTooLargeException as my_Error:
68
- print(f"Policy is too large: {my_Error}")
73
+ console.print(f"[red]❌ Policy is too large: {my_Error}[/red]")
69
74
  return_response = {"Success": False, "ErrorMessage": "Policy is too large"}
70
75
  return return_response
71
76
  except sts_client.exceptions.RegionDisabledException as my_Error:
72
- print(f"Region is disabled: {my_Error}")
77
+ console.print(f"[red]❌ Region is disabled: {my_Error}[/red]")
73
78
  return_response = {"Success": False, "ErrorMessage": "Region Disabled"}
74
79
  return return_response
75
80
  except sts_client.exceptions.ExpiredTokenException as my_Error:
76
- print(f"Expired Token: {my_Error}")
81
+ console.print(f"[red]❌ Expired Token: {my_Error}[/red]")
77
82
  return_response = {"Success": False, "ErrorMessage": "Expired Token"}
78
83
  return return_response
79
84
 
@@ -187,7 +192,9 @@ for account_num in Accounts:
187
192
  )
188
193
  response = check_account_access(aws_acct, account_num, pAccessRole)
189
194
  if response["Success"]:
190
- print(f"Account {account_num} was successfully connected via role {pAccessRole} from {aws_acct.acct_number}")
195
+ console.print(
196
+ f"[green]✅ Account {account_num} was successfully connected via role {pAccessRole} from {aws_acct.acct_number}[/green]"
197
+ )
191
198
  """
192
199
  Put more commands here... Or you can write functions that represent your commands and call them from here.
193
200
  """
@@ -196,16 +203,25 @@ for account_num in Accounts:
196
203
  username = "Paul"
197
204
  user_response = participant_user(tgt_aws_access, username=username)
198
205
  else:
199
- print(
200
- f"Access Role {pAccessRole} failed to connect to {account_num} from {aws_acct.acct_number} with error: {response['ErrorMessage']}"
206
+ console.print(
207
+ Panel(
208
+ f"Access Role {pAccessRole} failed to connect to {account_num} from {aws_acct.acct_number}",
209
+ title=f"[red]❌ Connection Error: {response['ErrorMessage']}[/red]",
210
+ border_style="red",
211
+ )
201
212
  )
202
213
 
203
- # Display access keys
204
- print(f"Credentials for account {tgt_aws_access.acct_number}")
205
- print(f"User {username} has been created (or confirmed) in account {user_response['AccountId']}")
206
- print(f"Password for {user_response['User']} is {user_response['Password']}")
207
- print(f"Access Keys are:\n{user_response['AccessKeyId']}\n{user_response['SecretAccessKey']}")
214
+ # Display access keys with Rich formatting
215
+ credentials_info = [
216
+ f"[cyan]Account:[/cyan] {tgt_aws_access.acct_number}",
217
+ f"[cyan]User:[/cyan] {user_response['User']} (created/confirmed in account {user_response['AccountId']})",
218
+ f"[cyan]Password:[/cyan] {user_response['Password']}",
219
+ f"[cyan]Access Key ID:[/cyan] {user_response['AccessKeyId']}",
220
+ f"[cyan]Secret Access Key:[/cyan] {user_response['SecretAccessKey']}",
221
+ ]
222
+
223
+ console.print(Panel("\n".join(credentials_info), title="[blue]🔑 Account Credentials[/blue]", border_style="blue"))
208
224
 
209
- print()
210
- print("Thanks for using this script...")
211
- print()
225
+ console.print("")
226
+ console.print("[green]✅ Thanks for using this script...[/green]")
227
+ console.print("")
File without changes