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
@@ -15,6 +15,14 @@ Compatible with both local (via pip or Docker) and AWS Lambda environments.
15
15
  import argparse
16
16
  import sys
17
17
 
18
+ from runbooks.common.rich_utils import (
19
+ console,
20
+ create_panel,
21
+ print_error,
22
+ print_info,
23
+ print_success,
24
+ print_warning,
25
+ )
18
26
  from runbooks.utils.logger import configure_logger
19
27
 
20
28
  from .security_baseline_tester import SecurityBaselineTester
@@ -65,17 +73,31 @@ def main():
65
73
  try:
66
74
  args = parse_arguments()
67
75
 
68
- logger.info("Starting AWS Security Baseline Tester...")
69
- logger.info(f"Using AWS profile: {args.profile}")
70
- logger.info(f"Report language: {args.language}")
71
- logger.info(f"Output directory: {args.output}")
76
+ # Display startup information with Rich formatting
77
+ startup_info = f"""[bold cyan]AWS Security Baseline Tester[/bold cyan]
78
+
79
+ [green]Configuration:[/green]
80
+ [cyan]AWS Profile:[/cyan] {args.profile}
81
+ [cyan]Language:[/cyan] {args.language}
82
+ [cyan]Output Directory:[/cyan] {args.output or "./results"}
83
+
84
+ [dim]Starting comprehensive security assessment...[/dim]"""
85
+
86
+ console.print(create_panel(startup_info, title="🔒 Security Baseline Tester", border_style="cyan"))
87
+
88
+ print_info("Initializing AWS Security Baseline Tester...")
89
+ print_info(f"Using AWS profile: {args.profile}")
90
+ print_info(f"Report language: {args.language}")
91
+ print_info(f"Output directory: {args.output or './results'}")
72
92
 
73
93
  ## Instantiate and run the Security Baseline Tester
74
94
  tester = SecurityBaselineTester(args.profile, args.language, args.output)
75
95
  tester.run()
76
96
 
77
- logger.info("AWS Security Baseline testing completed successfully.")
97
+ print_success("AWS Security Baseline testing completed successfully!")
98
+
78
99
  except Exception as e:
100
+ print_error(f"An unexpected error occurred: {e}", exception=e)
79
101
  logger.error(f"An unexpected error occurred: {e}", exc_info=True)
80
102
  sys.exit(1)
81
103
 
@@ -5,26 +5,43 @@ import logging
5
5
  import os
6
6
  from concurrent.futures import ThreadPoolExecutor, as_completed
7
7
  from pathlib import Path
8
+ from typing import Any, Dict, List, Optional
8
9
 
9
10
  import boto3
10
11
  import botocore
11
12
 
13
+ from runbooks.common.rich_utils import (
14
+ STATUS_INDICATORS,
15
+ console,
16
+ create_panel,
17
+ create_progress_bar,
18
+ create_table,
19
+ print_error,
20
+ print_info,
21
+ print_status,
22
+ print_success,
23
+ print_warning,
24
+ )
25
+
12
26
  from . import (
13
27
  checklist, # noqa: F403
14
28
  report_generator,
15
29
  )
30
+ from .security_export import SecurityExporter
16
31
  from .utils import common, language, level_const
17
32
 
18
33
  # from .utils.language import get_translator
19
34
 
20
35
 
21
36
  class SecurityBaselineTester:
22
- def __init__(self, profile, lang_code, output_dir):
37
+ def __init__(self, profile, lang_code, output_dir, export_formats: List[str] = None):
23
38
  self.profile = profile
24
39
  self.language = lang_code
25
40
  self.output = output_dir
41
+ self.export_formats = export_formats or ["json", "csv"]
26
42
  self.session = self._create_session()
27
43
  self.config = self._load_config()
44
+ self.exporter = SecurityExporter(output_dir)
28
45
  ## Call module 'language' and pass the string 'lang_code'
29
46
  self.translator = language.get_translator("main", lang_code)
30
47
 
@@ -50,22 +67,40 @@ class SecurityBaselineTester:
50
67
  raise
51
68
 
52
69
  def run(self):
70
+ """Execute the security baseline assessment with Rich CLI output."""
53
71
  try:
72
+ # Print security assessment header
73
+ console.print(
74
+ create_panel(
75
+ "[bold cyan]AWS Security Baseline Assessment[/bold cyan]\n\n"
76
+ f"[dim]Profile: {self.profile} | Language: {self.language}[/dim]",
77
+ title="🛡️ Starting Security Assessment",
78
+ border_style="cyan",
79
+ )
80
+ )
81
+
54
82
  self._validate_session()
55
83
  caller_identity = self._get_caller_identity()
56
84
  self._print_auditor_info(caller_identity)
57
85
 
58
- logging.info(self.translator.translate("start_test"))
86
+ print_info("Initiating comprehensive security baseline tests...")
59
87
 
60
88
  account_id, results = self._execute_tests()
61
89
  self._generate_report(account_id, results)
62
90
 
63
- logging.info(self.translator.translate("test_completed"))
91
+ # Export results in multiple formats
92
+ if self.export_formats:
93
+ print_info("Exporting security assessment results...")
94
+ self.exporter.export_security_results(
95
+ account_id=account_id, results=results, language=self.language, formats=self.export_formats
96
+ )
97
+
98
+ print_success("Security baseline assessment completed successfully!")
99
+
64
100
  except Exception as e:
65
- logging.error(
66
- f"An error occurred during the security baseline test: {str(e)}",
67
- exc_info=True,
68
- )
101
+ print_error(f"Security baseline test failed: {str(e)}", exception=e)
102
+ logging.error(f"An error occurred during the security baseline test: {str(e)}", exc_info=True)
103
+ raise
69
104
 
70
105
  def _validate_session(self):
71
106
  if self.session.region_name is None:
@@ -79,35 +114,114 @@ class SecurityBaselineTester:
79
114
  raise
80
115
 
81
116
  def _print_auditor_info(self, caller_identity):
82
- logging.info("==================== AUDITOR INFO ====================")
83
- logging.info(f"USER ID : {caller_identity['UserId']}")
84
- logging.info(f"ACCOUNT : {caller_identity['Account']}")
85
- logging.info(f"ARN : {caller_identity['Arn']}")
86
- logging.info("=====================================================")
117
+ """Display auditor information with Rich formatting."""
118
+ auditor_info = f"""[bold cyan]User ID:[/bold cyan] {caller_identity["UserId"]}
119
+ [bold cyan]Account:[/bold cyan] {caller_identity["Account"]}
120
+ [bold cyan]ARN:[/bold cyan] {caller_identity["Arn"]}"""
121
+
122
+ console.print(
123
+ create_panel(auditor_info, title="🔐 Security Assessment Context", border_style="cyan", padding=1)
124
+ )
87
125
 
88
126
  def _execute_tests(self):
89
127
  iam_client = self.session.client("iam")
90
128
  sts_client = self.session.client("sts")
91
129
 
92
130
  account_id = common.get_account_id(sts_client)
93
- logging.info(self.translator.translate("request_credential_report"))
131
+ print_info(f"Generating credential report for account {account_id}")
94
132
  credential_report = common.generate_credential_report(iam_client)
95
133
 
96
- with ThreadPoolExecutor(max_workers=self.config.get("max_workers", 5)) as executor:
97
- futures = {
98
- executor.submit(self._run_check, check_name, credential_report): check_name
99
- for check_name in self.config.get("checks", [])
100
- }
134
+ # Create progress bar for security checks
135
+ checks = self.config.get("checks", [])
136
+ total_checks = len(checks)
101
137
 
102
- results = {
103
- level: [] for level in ["Success", "Warning", "Danger", "Error", "Info"] if isinstance(level, str)
104
- }
105
- for future in as_completed(futures):
106
- result = future.result()
107
- results[result.level].append(result)
138
+ with create_progress_bar(description="Security Assessment") as progress:
139
+ task = progress.add_task("Running security checks...", total=total_checks)
108
140
 
141
+ with ThreadPoolExecutor(max_workers=self.config.get("max_workers", 5)) as executor:
142
+ futures = {
143
+ executor.submit(self._run_check, check_name, credential_report): check_name for check_name in checks
144
+ }
145
+
146
+ results = {
147
+ level: [] for level in ["Success", "Warning", "Danger", "Error", "Info"] if isinstance(level, str)
148
+ }
149
+ completed_checks = 0
150
+
151
+ for future in as_completed(futures):
152
+ result = future.result()
153
+ results[result.level].append(result)
154
+ completed_checks += 1
155
+ progress.update(task, completed=completed_checks)
156
+
157
+ # Display security assessment summary
158
+ self._display_security_summary(results, total_checks)
109
159
  return account_id, results
110
160
 
161
+ def _display_security_summary(self, results: Dict[str, List], total_checks: int):
162
+ """Display security assessment summary with Rich formatting."""
163
+ # Create summary table
164
+ summary_table = create_table(
165
+ title="🛡️ Security Assessment Summary",
166
+ columns=[
167
+ {"name": "Status", "style": "bold", "justify": "left"},
168
+ {"name": "Count", "style": "bold", "justify": "center"},
169
+ {"name": "Percentage", "style": "dim", "justify": "right"},
170
+ ],
171
+ )
172
+
173
+ # Calculate statistics
174
+ for level in ["Danger", "Warning", "Success", "Info", "Error"]:
175
+ count = len(results.get(level, []))
176
+ if total_checks > 0:
177
+ percentage = (count / total_checks) * 100
178
+ percentage_str = f"{percentage:.1f}%"
179
+ else:
180
+ percentage_str = "0%"
181
+
182
+ # Style based on level
183
+ if level == "Danger":
184
+ status_text = f"🔴 {level}"
185
+ style = "error"
186
+ elif level == "Warning":
187
+ status_text = f"🟡 {level}"
188
+ style = "warning"
189
+ elif level == "Success":
190
+ status_text = f"🟢 {level}"
191
+ style = "success"
192
+ elif level == "Info":
193
+ status_text = f"🔵 {level}"
194
+ style = "info"
195
+ else: # Error
196
+ status_text = f"❌ {level}"
197
+ style = "critical"
198
+
199
+ summary_table.add_row(status_text, str(count), percentage_str, style=style)
200
+
201
+ console.print(summary_table)
202
+
203
+ # Calculate overall security score
204
+ total_issues = len(results.get("Danger", [])) + len(results.get("Warning", []))
205
+ total_success = len(results.get("Success", []))
206
+
207
+ if total_checks > 0:
208
+ security_score = (total_success / total_checks) * 100
209
+ if security_score >= 90:
210
+ score_style = "success"
211
+ score_icon = "🛡️"
212
+ elif security_score >= 75:
213
+ score_style = "warning"
214
+ score_icon = "⚠️"
215
+ else:
216
+ score_style = "error"
217
+ score_icon = "🚨"
218
+
219
+ score_summary = f"""[bold {score_style}]{score_icon} Overall Security Score: {security_score:.1f}%[/bold {score_style}]
220
+
221
+ [dim]Total Checks: {total_checks} | Issues Found: {total_issues} | Successful: {total_success}[/dim]"""
222
+
223
+ console.print(create_panel(score_summary, title="Security Posture Assessment", border_style=score_style))
224
+
111
225
  def _run_check(self, check_name, credential_report):
112
226
  # check_module = __import__(f"checklist.{check_name}", fromlist=[check_name])
113
227
  check_module = importlib.import_module(f"runbooks.security.checklist.{check_name}")
@@ -164,9 +278,9 @@ class SecurityBaselineTester:
164
278
 
165
279
  if not results_dir.exists():
166
280
  results_dir.mkdir(parents=True, exist_ok=True)
167
- logging.info(self.translator.translate("results_folder_created"))
281
+ print_info(f"Created results directory: {results_dir}")
168
282
  else:
169
- logging.info(self.translator.translate("results_folder_already_exists"))
283
+ print_info(f"Using existing results directory: {results_dir}")
170
284
 
171
285
  return results_dir
172
286
 
@@ -198,4 +312,16 @@ class SecurityBaselineTester:
198
312
  with report_path.open("w", encoding="utf-8") as file:
199
313
  file.write(html_report)
200
314
 
201
- logging.info(self.translator.translate("generate_result_report"))
315
+ # Display report generation success with Rich formatting
316
+ report_success = f"""[bold green]Security Report Generated Successfully[/bold green]
317
+
318
+ [cyan]Report Location:[/cyan] {report_path}
319
+ [cyan]Account ID:[/cyan] {account_id}
320
+ [cyan]Language:[/cyan] {self.language}
321
+ [cyan]Report Time:[/cyan] {current_time}
322
+
323
+ [dim]Open the HTML report in your browser to view detailed findings.[/dim]"""
324
+
325
+ console.print(create_panel(report_success, title="📊 Report Generation Complete", border_style="green"))
326
+
327
+ print_success(f"HTML report saved to: {report_path}")