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
@@ -24,8 +24,9 @@ logger = logging.getLogger(__name__)
24
24
  @dataclass
25
25
  class AccountSession:
26
26
  """Represents a cross-account session with metadata"""
27
+
27
28
  account_id: str
28
- account_name: Optional[str]
29
+ account_name: Optional[str]
29
30
  session: boto3.Session
30
31
  status: str
31
32
  error_message: Optional[str] = None
@@ -34,68 +35,67 @@ class AccountSession:
34
35
  def create_multi_profile_sessions(profiles: List[str]) -> List[AccountSession]:
35
36
  """
36
37
  Create sessions using direct profile access for organizations without cross-account roles.
37
-
38
+
38
39
  This is an alternative approach when OrganizationAccountAccessRole is not available.
39
40
  Uses environment variables like CENTRALISED_OPS_PROFILE, BILLING_PROFILE, etc.
40
-
41
+
41
42
  Args:
42
43
  profiles: List of AWS profile names to use
43
-
44
+
44
45
  Returns:
45
46
  List of AccountSession objects with successful and failed sessions
46
47
  """
47
48
  import os
48
-
49
+
49
50
  print_info(f"🌐 Creating sessions for {len(profiles)} profiles")
50
51
  account_sessions = []
51
-
52
+
52
53
  for profile_name in profiles:
53
54
  try:
54
55
  # Validate profile exists and is accessible
55
56
  session = boto3.Session(profile_name=profile_name)
56
- sts_client = session.client('sts')
57
+ sts_client = session.client("sts")
57
58
  identity = sts_client.get_caller_identity()
58
-
59
- account_id = identity['Account']
60
-
59
+
60
+ account_id = identity["Account"]
61
+
61
62
  # Try to get account name from Organizations if possible
62
63
  account_name = profile_name # Default to profile name
63
64
  try:
64
- orgs_client = session.client('organizations')
65
+ orgs_client = session.client("organizations")
65
66
  account_info = orgs_client.describe_account(AccountId=account_id)
66
- account_name = account_info['Account']['Name']
67
+ account_name = account_info["Account"]["Name"]
67
68
  except:
68
69
  pass # Use profile name as fallback
69
-
70
- account_sessions.append(AccountSession(
71
- account_id=account_id,
72
- account_name=account_name,
73
- session=session,
74
- status="success"
75
- ))
76
-
70
+
71
+ account_sessions.append(
72
+ AccountSession(account_id=account_id, account_name=account_name, session=session, status="success")
73
+ )
74
+
77
75
  print_success(f"✅ Session created for {account_id} using profile {profile_name}")
78
-
76
+
79
77
  except Exception as e:
80
78
  print_warning(f"⚠️ Failed to create session for profile {profile_name}: {e}")
81
- account_sessions.append(AccountSession(
82
- account_id=profile_name, # Use profile name as ID when we can't get real ID
83
- account_name=profile_name,
84
- session=None,
85
- status="failed",
86
- error_message=str(e)
87
- ))
88
-
79
+ account_sessions.append(
80
+ AccountSession(
81
+ account_id=profile_name, # Use profile name as ID when we can't get real ID
82
+ account_name=profile_name,
83
+ session=None,
84
+ status="failed",
85
+ error_message=str(e),
86
+ )
87
+ )
88
+
89
89
  return account_sessions
90
90
 
91
91
 
92
92
  class CrossAccountSessionManager:
93
93
  """
94
94
  Enterprise cross-account session manager using STS AssumeRole pattern.
95
-
95
+
96
96
  This replaces the broken profile@accountId format with proper STS AssumeRole
97
97
  for multi-account VPC discovery across Landing Zone accounts.
98
-
98
+
99
99
  Key Features:
100
100
  - Uses CENTRALISED_OPS_PROFILE as base session for assuming roles
101
101
  - Standard OrganizationAccountAccessRole assumption
@@ -103,91 +103,94 @@ class CrossAccountSessionManager:
103
103
  - Comprehensive error handling and graceful degradation
104
104
  - Compatible with existing VPC module architecture
105
105
  """
106
-
106
+
107
107
  def __init__(self, base_profile: str, role_name: str = "OrganizationAccountAccessRole"):
108
108
  """
109
109
  Initialize cross-account session manager.
110
-
110
+
111
111
  Args:
112
112
  base_profile: Base profile (e.g., CENTRALISED_OPS_PROFILE) for assuming roles
113
113
  role_name: IAM role name to assume in target accounts
114
114
  """
115
115
  self.base_profile = base_profile
116
116
  self.role_name = role_name
117
-
117
+
118
118
  # Use management session for cross-account role assumptions
119
119
  # Management account has the trust relationships for OrganizationAccountAccessRole
120
- self.session = create_management_session(profile=base_profile)
121
-
120
+ self.session = create_management_session(profile_name=base_profile)
121
+
122
122
  print_info(f"🔐 Cross-account session manager initialized with {base_profile}")
123
-
123
+
124
124
  def create_cross_account_sessions(
125
- self,
126
- accounts: List[Dict[str, str]],
127
- max_workers: int = 10
125
+ self, accounts: List[Dict[str, str]], max_workers: int = 10
128
126
  ) -> List[AccountSession]:
129
127
  """
130
128
  Create cross-account sessions using STS AssumeRole pattern.
131
-
129
+
132
130
  Args:
133
131
  accounts: List of account dictionaries from Organizations API
134
132
  max_workers: Maximum parallel workers for session creation
135
-
133
+
136
134
  Returns:
137
135
  List of AccountSession objects with successful and failed sessions
138
136
  """
139
137
  print_info(f"🌐 Creating cross-account sessions for {len(accounts)} accounts")
140
-
138
+
141
139
  account_sessions = []
142
-
140
+
143
141
  # Filter active accounts only
144
142
  active_accounts = [acc for acc in accounts if acc.get("status") == "ACTIVE"]
145
143
  print_info(f"📋 Processing {len(active_accounts)} active accounts")
146
-
144
+
147
145
  # Create sessions in parallel for performance
148
146
  with ThreadPoolExecutor(max_workers=max_workers) as executor:
149
147
  future_to_account = {
150
- executor.submit(self._create_account_session, account): account
151
- for account in active_accounts
148
+ executor.submit(self._create_account_session, account): account for account in active_accounts
152
149
  }
153
-
150
+
154
151
  for future in as_completed(future_to_account):
155
152
  account = future_to_account[future]
156
153
  try:
157
154
  account_session = future.result()
158
155
  account_sessions.append(account_session)
159
-
156
+
160
157
  if account_session.status == "success":
161
158
  print_success(f"✅ Session created for {account_session.account_id}")
162
159
  else:
163
- print_warning(f"⚠️ Session failed for {account_session.account_id}: {account_session.error_message}")
164
-
160
+ print_warning(
161
+ f"⚠️ Session failed for {account_session.account_id}: {account_session.error_message}"
162
+ )
163
+
165
164
  except Exception as e:
166
165
  print_error(f"❌ Unexpected error creating session for {account['id']}: {e}")
167
- account_sessions.append(AccountSession(
168
- account_id=account["id"],
169
- account_name=account.get("name"),
170
- session=None,
171
- status="error",
172
- error_message=str(e)
173
- ))
174
-
166
+ account_sessions.append(
167
+ AccountSession(
168
+ account_id=account["id"],
169
+ account_name=account.get("name"),
170
+ session=None,
171
+ status="error",
172
+ error_message=str(e),
173
+ )
174
+ )
175
+
175
176
  successful_sessions = [s for s in account_sessions if s.status == "success"]
176
177
  failed_sessions = [s for s in account_sessions if s.status != "success"]
177
-
178
- print_info(f"🎯 Session creation complete: {len(successful_sessions)} successful, {len(failed_sessions)} failed")
179
-
178
+
179
+ print_info(
180
+ f"🎯 Session creation complete: {len(successful_sessions)} successful, {len(failed_sessions)} failed"
181
+ )
182
+
180
183
  return account_sessions
181
-
184
+
182
185
  def _create_account_session(self, account: Dict[str, str]) -> AccountSession:
183
186
  """
184
187
  Create a session for a single account using STS AssumeRole.
185
-
188
+
186
189
  This is the core implementation of the enterprise pattern.
187
190
  """
188
191
  account_id = account["id"]
189
192
  account_name = account.get("name", f"Account-{account_id}")
190
-
193
+
191
194
  # Try multiple role patterns for different organization setups - universal compatibility
192
195
  role_patterns = [
193
196
  self.role_name, # Default: OrganizationAccountAccessRole
@@ -199,87 +202,80 @@ class CrossAccountSessionManager:
199
202
  "CrossAccountRole", # Generic cross-account role
200
203
  "AssumeRole", # Generic assume role
201
204
  ]
202
-
205
+
203
206
  for role_name in role_patterns:
204
207
  try:
205
208
  # Step 1: Assume role in target account using STS
206
- sts_client = self.session.client('sts')
209
+ sts_client = self.session.client("sts")
207
210
  assumed_role = sts_client.assume_role(
208
211
  RoleArn=f"arn:aws:iam::{account_id}:role/{role_name}",
209
- RoleSessionName=f"VPCDiscovery-{account_id[:12]}"
212
+ RoleSessionName=f"VPCDiscovery-{account_id[:12]}",
210
213
  )
211
-
214
+
212
215
  # If successful, continue with this role
213
-
216
+
214
217
  # Step 2: Create session with assumed role credentials
215
218
  assumed_session = boto3.Session(
216
- aws_access_key_id=assumed_role['Credentials']['AccessKeyId'],
217
- aws_secret_access_key=assumed_role['Credentials']['SecretAccessKey'],
218
- aws_session_token=assumed_role['Credentials']['SessionToken']
219
+ aws_access_key_id=assumed_role["Credentials"]["AccessKeyId"],
220
+ aws_secret_access_key=assumed_role["Credentials"]["SecretAccessKey"],
221
+ aws_session_token=assumed_role["Credentials"]["SessionToken"],
219
222
  )
220
-
223
+
221
224
  # Step 3: Validate session with basic STS call
222
- assumed_sts = assumed_session.client('sts')
225
+ assumed_sts = assumed_session.client("sts")
223
226
  identity = assumed_sts.get_caller_identity()
224
-
225
- logger.debug(f"Successfully assumed role {role_name} in account {account_id}, identity: {identity['Arn']}")
226
-
227
+
228
+ logger.debug(
229
+ f"Successfully assumed role {role_name} in account {account_id}, identity: {identity['Arn']}"
230
+ )
231
+
227
232
  return AccountSession(
228
- account_id=account_id,
229
- account_name=account_name,
230
- session=assumed_session,
231
- status="success"
233
+ account_id=account_id, account_name=account_name, session=assumed_session, status="success"
232
234
  )
233
-
235
+
234
236
  except ClientError as e:
235
237
  # Continue to next role pattern
236
238
  continue
237
-
239
+
238
240
  # If no role patterns worked, return failure
239
241
  error_msg = f"Unable to assume any role pattern in {account_id} - tried: {', '.join(role_patterns)}"
240
242
  logger.warning(f"Failed to create session for {account_id}: {error_msg}")
241
-
243
+
242
244
  return AccountSession(
243
- account_id=account_id,
244
- account_name=account_name,
245
- session=None,
246
- status="failed",
247
- error_message=error_msg
245
+ account_id=account_id, account_name=account_name, session=None, status="failed", error_message=error_msg
248
246
  )
249
-
247
+
250
248
  def get_successful_sessions(self, account_sessions: List[AccountSession]) -> List[AccountSession]:
251
249
  """Get only successful account sessions for VPC discovery."""
252
250
  successful = [s for s in account_sessions if s.status == "success"]
253
251
  print_info(f"🎯 {len(successful)} accounts ready for VPC discovery")
254
252
  return successful
255
-
253
+
256
254
  def get_session_summary(self, account_sessions: List[AccountSession]) -> Dict[str, int]:
257
255
  """Get summary statistics for session creation."""
258
256
  summary = {
259
257
  "total": len(account_sessions),
260
258
  "successful": len([s for s in account_sessions if s.status == "success"]),
261
259
  "failed": len([s for s in account_sessions if s.status == "failed"]),
262
- "errors": len([s for s in account_sessions if s.status == "error"])
260
+ "errors": len([s for s in account_sessions if s.status == "error"]),
263
261
  }
264
262
  return summary
265
263
 
266
264
 
267
265
  def create_cross_account_vpc_sessions(
268
- accounts: List[Dict[str, str]],
269
- base_profile: str,
270
- role_name: str = "OrganizationAccountAccessRole"
266
+ accounts: List[Dict[str, str]], base_profile: str, role_name: str = "OrganizationAccountAccessRole"
271
267
  ) -> List[AccountSession]:
272
268
  """
273
269
  Convenience function to create cross-account VPC sessions.
274
-
270
+
275
271
  This is the main entry point for VPC modules to replace the broken
276
272
  profile@accountId pattern with proper STS AssumeRole.
277
-
273
+
278
274
  Args:
279
275
  accounts: List of organization accounts from get_organization_accounts
280
276
  base_profile: Base profile for assuming roles (CENTRALISED_OPS_PROFILE)
281
277
  role_name: IAM role name to assume
282
-
278
+
283
279
  Returns:
284
280
  List of AccountSession objects ready for VPC discovery
285
281
  """
@@ -289,24 +285,23 @@ def create_cross_account_vpc_sessions(
289
285
 
290
286
  # Compatibility functions for existing VPC module integration
291
287
  def convert_accounts_to_sessions(
292
- accounts: List[Dict[str, str]],
293
- base_profile: str
288
+ accounts: List[Dict[str, str]], base_profile: str
294
289
  ) -> Tuple[List[AccountSession], Dict[str, Dict[str, str]]]:
295
290
  """
296
291
  Convert organization accounts to cross-account sessions.
297
-
292
+
298
293
  This replaces the broken convert_accounts_to_profiles function
299
294
  with proper STS AssumeRole session creation.
300
-
295
+
301
296
  Returns:
302
297
  Tuple of (successful_sessions, account_metadata)
303
298
  """
304
299
  account_sessions = create_cross_account_vpc_sessions(accounts, base_profile)
305
300
  successful_sessions = [s for s in account_sessions if s.status == "success"]
306
-
301
+
307
302
  # Create account metadata dict for compatibility
308
303
  account_metadata = {}
309
304
  for account in accounts:
310
305
  account_metadata[account["id"]] = account
311
-
312
- return successful_sessions, account_metadata
306
+
307
+ return successful_sessions, account_metadata