runbooks 0.7.6__py3-none-any.whl → 0.7.9__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 (111) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/base.py +5 -1
  3. runbooks/cfat/__init__.py +8 -4
  4. runbooks/cfat/assessment/collectors.py +171 -14
  5. runbooks/cfat/assessment/compliance.py +871 -0
  6. runbooks/cfat/assessment/runner.py +122 -11
  7. runbooks/cfat/models.py +6 -2
  8. runbooks/common/logger.py +14 -0
  9. runbooks/common/rich_utils.py +451 -0
  10. runbooks/enterprise/__init__.py +68 -0
  11. runbooks/enterprise/error_handling.py +411 -0
  12. runbooks/enterprise/logging.py +439 -0
  13. runbooks/enterprise/multi_tenant.py +583 -0
  14. runbooks/finops/README.md +468 -241
  15. runbooks/finops/__init__.py +39 -3
  16. runbooks/finops/cli.py +83 -18
  17. runbooks/finops/cross_validation.py +375 -0
  18. runbooks/finops/dashboard_runner.py +812 -164
  19. runbooks/finops/enhanced_dashboard_runner.py +525 -0
  20. runbooks/finops/finops_dashboard.py +1892 -0
  21. runbooks/finops/helpers.py +485 -51
  22. runbooks/finops/optimizer.py +823 -0
  23. runbooks/finops/tests/__init__.py +19 -0
  24. runbooks/finops/tests/results_test_finops_dashboard.xml +1 -0
  25. runbooks/finops/tests/run_comprehensive_tests.py +421 -0
  26. runbooks/finops/tests/run_tests.py +305 -0
  27. runbooks/finops/tests/test_finops_dashboard.py +705 -0
  28. runbooks/finops/tests/test_integration.py +477 -0
  29. runbooks/finops/tests/test_performance.py +380 -0
  30. runbooks/finops/tests/test_performance_benchmarks.py +500 -0
  31. runbooks/finops/tests/test_reference_images_validation.py +867 -0
  32. runbooks/finops/tests/test_single_account_features.py +715 -0
  33. runbooks/finops/tests/validate_test_suite.py +220 -0
  34. runbooks/finops/types.py +1 -1
  35. runbooks/hitl/enhanced_workflow_engine.py +725 -0
  36. runbooks/inventory/artifacts/scale-optimize-status.txt +12 -0
  37. runbooks/inventory/collectors/aws_comprehensive.py +442 -0
  38. runbooks/inventory/collectors/enterprise_scale.py +281 -0
  39. runbooks/inventory/core/collector.py +172 -13
  40. runbooks/inventory/discovery.md +1 -1
  41. runbooks/inventory/list_ec2_instances.py +18 -20
  42. runbooks/inventory/list_ssm_parameters.py +31 -3
  43. runbooks/inventory/organizations_discovery.py +1269 -0
  44. runbooks/inventory/rich_inventory_display.py +393 -0
  45. runbooks/inventory/run_on_multi_accounts.py +35 -19
  46. runbooks/inventory/runbooks.security.report_generator.log +0 -0
  47. runbooks/inventory/runbooks.security.run_script.log +0 -0
  48. runbooks/inventory/vpc_flow_analyzer.py +1030 -0
  49. runbooks/main.py +2215 -119
  50. runbooks/metrics/dora_metrics_engine.py +599 -0
  51. runbooks/operate/__init__.py +2 -2
  52. runbooks/operate/base.py +122 -10
  53. runbooks/operate/deployment_framework.py +1032 -0
  54. runbooks/operate/deployment_validator.py +853 -0
  55. runbooks/operate/dynamodb_operations.py +10 -6
  56. runbooks/operate/ec2_operations.py +319 -11
  57. runbooks/operate/executive_dashboard.py +779 -0
  58. runbooks/operate/mcp_integration.py +750 -0
  59. runbooks/operate/nat_gateway_operations.py +1120 -0
  60. runbooks/operate/networking_cost_heatmap.py +685 -0
  61. runbooks/operate/privatelink_operations.py +940 -0
  62. runbooks/operate/s3_operations.py +10 -6
  63. runbooks/operate/vpc_endpoints.py +644 -0
  64. runbooks/operate/vpc_operations.py +1038 -0
  65. runbooks/remediation/__init__.py +2 -2
  66. runbooks/remediation/acm_remediation.py +1 -1
  67. runbooks/remediation/base.py +1 -1
  68. runbooks/remediation/cloudtrail_remediation.py +1 -1
  69. runbooks/remediation/cognito_remediation.py +1 -1
  70. runbooks/remediation/dynamodb_remediation.py +1 -1
  71. runbooks/remediation/ec2_remediation.py +1 -1
  72. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -1
  73. runbooks/remediation/kms_enable_key_rotation.py +1 -1
  74. runbooks/remediation/kms_remediation.py +1 -1
  75. runbooks/remediation/lambda_remediation.py +1 -1
  76. runbooks/remediation/multi_account.py +1 -1
  77. runbooks/remediation/rds_remediation.py +1 -1
  78. runbooks/remediation/s3_block_public_access.py +1 -1
  79. runbooks/remediation/s3_enable_access_logging.py +1 -1
  80. runbooks/remediation/s3_encryption.py +1 -1
  81. runbooks/remediation/s3_remediation.py +1 -1
  82. runbooks/remediation/vpc_remediation.py +475 -0
  83. runbooks/security/__init__.py +3 -1
  84. runbooks/security/compliance_automation.py +632 -0
  85. runbooks/security/report_generator.py +10 -0
  86. runbooks/security/run_script.py +31 -5
  87. runbooks/security/security_baseline_tester.py +169 -30
  88. runbooks/security/security_export.py +477 -0
  89. runbooks/validation/__init__.py +10 -0
  90. runbooks/validation/benchmark.py +484 -0
  91. runbooks/validation/cli.py +356 -0
  92. runbooks/validation/mcp_validator.py +768 -0
  93. runbooks/vpc/__init__.py +38 -0
  94. runbooks/vpc/config.py +212 -0
  95. runbooks/vpc/cost_engine.py +347 -0
  96. runbooks/vpc/heatmap_engine.py +605 -0
  97. runbooks/vpc/manager_interface.py +634 -0
  98. runbooks/vpc/networking_wrapper.py +1260 -0
  99. runbooks/vpc/rich_formatters.py +679 -0
  100. runbooks/vpc/tests/__init__.py +5 -0
  101. runbooks/vpc/tests/conftest.py +356 -0
  102. runbooks/vpc/tests/test_cli_integration.py +530 -0
  103. runbooks/vpc/tests/test_config.py +458 -0
  104. runbooks/vpc/tests/test_cost_engine.py +479 -0
  105. runbooks/vpc/tests/test_networking_wrapper.py +512 -0
  106. {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/METADATA +40 -12
  107. {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/RECORD +111 -50
  108. {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/WHEEL +0 -0
  109. {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/entry_points.txt +0 -0
  110. {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/licenses/LICENSE +0 -0
  111. {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/top_level.txt +0 -0
runbooks/__init__.py CHANGED
@@ -67,7 +67,7 @@ try:
67
67
  __version__ = _pkg_version("runbooks")
68
68
  except Exception:
69
69
  # Fallback if metadata is unavailable during editable installs
70
- __version__ = "0.7.6"
70
+ __version__ = "0.7.8"
71
71
 
72
72
  # Core module exports
73
73
  from runbooks.config import RunbooksConfig, load_config, save_config
runbooks/base.py CHANGED
@@ -5,6 +5,7 @@ This module provides common base classes and utilities used across
5
5
  all Cloud Foundations components including CFAT, inventory, and organizations.
6
6
  """
7
7
 
8
+ import os
8
9
  from abc import ABC, abstractmethod
9
10
  from datetime import datetime
10
11
  from pathlib import Path
@@ -86,7 +87,10 @@ class CloudFoundationsBase(ABC):
86
87
 
87
88
  def _create_session(self) -> boto3.Session:
88
89
  """Create boto3 session with appropriate configuration."""
89
- session_kwargs = {"profile_name": self.profile}
90
+ # Use environment variable first, then profile parameter, then default
91
+ profile = os.environ.get("AWS_PROFILE") or self.profile
92
+
93
+ session_kwargs = {"profile_name": profile}
90
94
  if self.region:
91
95
  session_kwargs["region_name"] = self.region
92
96
 
runbooks/cfat/__init__.py CHANGED
@@ -30,11 +30,15 @@ Example:
30
30
  report.to_html("assessment_report.html")
31
31
  report.to_json("findings.json")
32
32
 
33
- print(f"Compliance Score: {report.summary.compliance_score}/100")
34
- print(f"Critical Issues: {report.summary.critical_issues}")
33
+ # Rich console output for better formatting
34
+ from rich.console import Console
35
+ console = Console()
36
+
37
+ console.print(f"[green]Compliance Score: {report.summary.compliance_score}/100[/green]")
38
+ console.print(f"[red]Critical Issues: {report.summary.critical_issues}[/red]")
35
39
  ```
36
40
 
37
- Version: 0.7.6 (Latest with enhanced CLI integration, rust tooling, and modern dependency stack)
41
+ Version: 0.7.8 (Latest with enhanced CLI integration, rust tooling, and modern dependency stack)
38
42
  """
39
43
 
40
44
  # Core assessment engine
@@ -53,7 +57,7 @@ from runbooks.cfat.models import (
53
57
  from runbooks.cfat.runner import AssessmentRunner
54
58
 
55
59
  # Version info
56
- __version__ = "0.7.6"
60
+ __version__ = "0.7.8"
57
61
  __author__ = "CloudOps Runbooks Team"
58
62
 
59
63
  # Public API exports
@@ -66,7 +66,7 @@ class IAMCollector(BaseCollector):
66
66
 
67
67
 
68
68
  class VPCCollector(BaseCollector):
69
- """Virtual Private Cloud resource collector."""
69
+ """Virtual Private Cloud resource collector with NAT Gateway cost optimization integration."""
70
70
 
71
71
  def get_service_name(self) -> str:
72
72
  """Get service name."""
@@ -74,23 +74,180 @@ class VPCCollector(BaseCollector):
74
74
 
75
75
  def collect(self) -> Dict[str, Any]:
76
76
  """
77
- Collect VPC resources for assessment.
77
+ Collect VPC resources for assessment with NAT Gateway cost analysis.
78
78
 
79
79
  Returns:
80
- Dictionary containing VPC resource data
80
+ Dictionary containing VPC resource data including cost optimization insights
81
81
  """
82
- logger.info("Collecting VPC resources...")
82
+ logger.info("Collecting VPC resources with cost optimization analysis...")
83
+
84
+ try:
85
+ ec2_client = self.session.client("ec2", region_name=self.region)
86
+
87
+ # Collect VPCs
88
+ vpcs_response = ec2_client.describe_vpcs()
89
+ vpcs = vpcs_response.get("Vpcs", [])
90
+
91
+ # Collect Subnets
92
+ subnets_response = ec2_client.describe_subnets()
93
+ subnets = subnets_response.get("Subnets", [])
94
+
95
+ # Collect NAT Gateways with cost analysis (GitHub Issue #96)
96
+ nat_gateways_response = ec2_client.describe_nat_gateways()
97
+ nat_gateways = nat_gateways_response.get("NatGateways", [])
98
+
99
+ # Calculate NAT Gateway costs ($45/month per gateway)
100
+ active_nat_gateways = [ng for ng in nat_gateways if ng.get("State") == "available"]
101
+ nat_cost_analysis = {
102
+ "total_nat_gateways": len(active_nat_gateways),
103
+ "estimated_monthly_cost": len(active_nat_gateways) * 45.0,
104
+ "optimization_opportunities": self._analyze_nat_optimization(active_nat_gateways, subnets),
105
+ "cost_alerts": [],
106
+ }
107
+
108
+ if len(active_nat_gateways) > 3:
109
+ nat_cost_analysis["cost_alerts"].append(
110
+ f"HIGH COST: {len(active_nat_gateways)} NAT Gateways detected. "
111
+ f"Monthly cost: ${nat_cost_analysis['estimated_monthly_cost']:,.2f}"
112
+ )
113
+
114
+ # Collect Security Groups
115
+ sg_response = ec2_client.describe_security_groups()
116
+ security_groups = sg_response.get("SecurityGroups", [])
117
+
118
+ # Collect Network ACLs
119
+ nacls_response = ec2_client.describe_network_acls()
120
+ nacls = nacls_response.get("NetworkAcls", [])
121
+
122
+ # Collect Internet Gateways
123
+ igw_response = ec2_client.describe_internet_gateways()
124
+ internet_gateways = igw_response.get("InternetGateways", [])
125
+
126
+ # Collect VPC Flow Logs
127
+ flow_logs_response = ec2_client.describe_flow_logs()
128
+ flow_logs = flow_logs_response.get("FlowLogs", [])
129
+
130
+ # Collect Route Tables for routing analysis
131
+ route_tables_response = ec2_client.describe_route_tables()
132
+ route_tables = route_tables_response.get("RouteTables", [])
133
+
134
+ logger.info(
135
+ f"Collected {len(vpcs)} VPCs, {len(nat_gateways)} NAT Gateways, "
136
+ f"estimated monthly NAT cost: ${nat_cost_analysis['estimated_monthly_cost']:,.2f}"
137
+ )
138
+
139
+ return {
140
+ "vpcs": vpcs,
141
+ "subnets": subnets,
142
+ "nat_gateways": nat_gateways,
143
+ "nat_cost_analysis": nat_cost_analysis, # New: Cost optimization data
144
+ "security_groups": security_groups,
145
+ "nacls": nacls,
146
+ "flow_logs": flow_logs,
147
+ "internet_gateways": internet_gateways,
148
+ "route_tables": route_tables,
149
+ "assessment_metadata": {
150
+ "collector_version": "v0.7.8-vpc-enhanced",
151
+ "github_issue": "#96",
152
+ "cost_optimization_enabled": True,
153
+ },
154
+ }
155
+
156
+ except Exception as e:
157
+ logger.error(f"Failed to collect VPC resources: {e}")
158
+ return {
159
+ "vpcs": [],
160
+ "subnets": [],
161
+ "nat_gateways": [],
162
+ "nat_cost_analysis": {"error": str(e)},
163
+ "security_groups": [],
164
+ "nacls": [],
165
+ "flow_logs": [],
166
+ "internet_gateways": [],
167
+ "route_tables": [],
168
+ "assessment_metadata": {"collector_version": "v0.7.8-vpc-enhanced", "error": str(e)},
169
+ }
170
+
171
+ def _analyze_nat_optimization(self, nat_gateways: List[Dict], subnets: List[Dict]) -> int:
172
+ """
173
+ Analyze NAT Gateway placement for cost optimization opportunities.
83
174
 
84
- # Placeholder implementation
85
- # TODO: Implement actual VPC resource collection
86
- return {
87
- "vpcs": [],
88
- "subnets": [],
89
- "security_groups": [],
90
- "nacls": [],
91
- "flow_logs": [],
92
- "internet_gateways": [],
93
- }
175
+ Args:
176
+ nat_gateways: List of NAT Gateway configurations
177
+ subnets: List of subnet configurations
178
+
179
+ Returns:
180
+ Number of optimization opportunities found
181
+ """
182
+ opportunities = 0
183
+
184
+ # Group NAT Gateways by Availability Zone
185
+ az_nat_count = {}
186
+ for nat in nat_gateways:
187
+ if nat.get("State") == "available":
188
+ subnet_id = nat.get("SubnetId")
189
+ # Find AZ for this subnet
190
+ subnet_az = None
191
+ for subnet in subnets:
192
+ if subnet.get("SubnetId") == subnet_id:
193
+ subnet_az = subnet.get("AvailabilityZone")
194
+ break
195
+
196
+ if subnet_az:
197
+ az_nat_count[subnet_az] = az_nat_count.get(subnet_az, 0) + 1
198
+
199
+ # Check for potential consolidation opportunities
200
+ for az, count in az_nat_count.items():
201
+ if count > 1:
202
+ opportunities += count - 1 # Could potentially consolidate to 1 per AZ
203
+
204
+ return opportunities
205
+
206
+ def run(self) -> "CloudFoundationsResult":
207
+ """
208
+ Run VPC resource collection and return standardized result.
209
+
210
+ Returns:
211
+ CloudFoundationsResult with VPC assessment data including NAT Gateway cost analysis
212
+ """
213
+ try:
214
+ # Collect VPC resources with cost optimization analysis
215
+ vpc_data = self.collect()
216
+
217
+ # Determine success based on data collection
218
+ success = bool(vpc_data) and not vpc_data.get("assessment_metadata", {}).get("error")
219
+
220
+ # Create message with cost insights
221
+ nat_cost_analysis = vpc_data.get("nat_cost_analysis", {})
222
+ total_cost = nat_cost_analysis.get("estimated_monthly_cost", 0)
223
+ total_nats = nat_cost_analysis.get("total_nat_gateways", 0)
224
+
225
+ if success:
226
+ message = (
227
+ f"VPC assessment completed: {len(vpc_data.get('vpcs', []))} VPCs, "
228
+ f"{total_nats} NAT Gateways, estimated monthly NAT cost: ${total_cost:,.2f}"
229
+ )
230
+
231
+ # Add cost alerts to message if present
232
+ cost_alerts = nat_cost_analysis.get("cost_alerts", [])
233
+ if cost_alerts:
234
+ message += f". {len(cost_alerts)} cost optimization opportunities identified"
235
+ else:
236
+ error = vpc_data.get("assessment_metadata", {}).get("error", "Unknown error")
237
+ message = f"VPC assessment failed: {error}"
238
+
239
+ return self.create_result(
240
+ success=success,
241
+ message=message,
242
+ data=vpc_data,
243
+ errors=[vpc_data.get("assessment_metadata", {}).get("error")] if not success else [],
244
+ )
245
+
246
+ except Exception as e:
247
+ logger.error(f"VPC collector run failed: {e}")
248
+ return self.create_result(
249
+ success=False, message=f"VPC assessment failed: {str(e)}", data={}, errors=[str(e)]
250
+ )
94
251
 
95
252
 
96
253
  class CloudTrailCollector(BaseCollector):