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
@@ -39,13 +39,16 @@ import hashlib
39
39
  # For PDF support
40
40
  try:
41
41
  import PyPDF2
42
+
42
43
  PDF_SUPPORT = True
43
44
  except ImportError:
44
45
  PDF_SUPPORT = False
45
46
 
47
+
46
48
  @dataclass
47
49
  class TerraformFact:
48
50
  """A fact extracted from terraform state with citation metadata."""
51
+
49
52
  resource_type: str
50
53
  resource_id: str
51
54
  attribute: str
@@ -53,62 +56,63 @@ class TerraformFact:
53
56
  terraform_file: str
54
57
  line_number: int
55
58
  citation_id: str
56
-
59
+
57
60
  def to_citation(self) -> Dict[str, Any]:
58
61
  """Convert to Claude Citations API format."""
59
62
  return {
60
63
  "id": self.citation_id,
61
64
  "source": f"terraform-aws/{self.terraform_file}:{self.line_number}",
62
65
  "text": f"{self.resource_type}.{self.resource_id}.{self.attribute} = {self.value}",
63
- "type": "terraform_state"
66
+ "type": "terraform_state",
64
67
  }
65
68
 
69
+
66
70
  class TerraformCitationsValidator:
67
71
  """Validates runbooks outputs with terraform facts using Citations API pattern."""
68
-
72
+
69
73
  def __init__(self, terraform_dir: str = "/Volumes/Working/1xOps/CloudOps-Runbooks/terraform-aws"):
70
74
  """Initialize with terraform-aws directory path."""
71
75
  self.terraform_dir = Path(terraform_dir)
72
76
  self.facts_db: Dict[str, TerraformFact] = {}
73
77
  self.citations: List[Dict[str, Any]] = []
74
78
  self.external_knowledge_dir = Path("/Volumes/Working/1xOps/CloudOps-Runbooks/knowledge-external")
75
-
79
+
76
80
  def extract_terraform_facts(self) -> Dict[str, TerraformFact]:
77
81
  """Extract facts from terraform source files (.tf) for citation."""
78
82
  facts = {}
79
-
83
+
80
84
  # Find all terraform source files (.tf) as requested by user
81
85
  tf_files = list(self.terraform_dir.rglob("*.tf"))
82
-
86
+
83
87
  for tf_file in tf_files:
84
88
  try:
85
- with open(tf_file, 'r') as f:
89
+ with open(tf_file, "r") as f:
86
90
  tf_content = f.read()
87
-
91
+
88
92
  # Parse terraform source for resource definitions
89
93
  tf_facts = self._parse_terraform_source(tf_content, tf_file)
90
94
  facts.update(tf_facts)
91
-
95
+
92
96
  except Exception as e:
93
97
  print(f"Error parsing {tf_file}: {e}")
94
-
98
+
95
99
  self.facts_db = facts
96
100
  return facts
97
-
101
+
98
102
  def _parse_terraform_source(self, tf_content: str, tf_file: Path) -> Dict[str, TerraformFact]:
99
103
  """Parse terraform source file for resource definitions and citations."""
100
104
  facts = {}
101
- lines = tf_content.split('\n')
102
-
105
+ lines = tf_content.split("\n")
106
+
103
107
  current_resource = None
104
108
  current_resource_name = None
105
109
  brace_count = 0
106
-
110
+
107
111
  for line_num, line in enumerate(lines, 1):
108
112
  line = line.strip()
109
-
113
+
110
114
  # Detect resource blocks
111
- if line.startswith('resource '):
115
+ if line.startswith("resource "):
112
116
  # Extract resource type and name: resource "aws_nat_gateway" "example" {
113
117
  parts = line.split()
114
118
  if len(parts) >= 3:
@@ -117,98 +121,93 @@ class TerraformCitationsValidator:
117
121
  current_resource = resource_type
118
122
  current_resource_name = resource_name
119
123
  brace_count = 0
120
-
124
+
121
125
  # Track braces to know when we're inside a resource block
122
- if '{' in line:
123
- brace_count += line.count('{')
124
- if '}' in line:
125
- brace_count -= line.count('}')
126
+ if "{" in line:
127
+ brace_count += line.count("{")
128
+ if "}" in line:
129
+ brace_count -= line.count("}")
126
130
  if brace_count == 0:
127
131
  current_resource = None
128
132
  current_resource_name = None
129
-
133
+
130
134
  # Extract cost-relevant attributes from within resource blocks
131
- if current_resource and current_resource_name and '=' in line:
135
+ if current_resource and current_resource_name and "=" in line:
132
136
  # Parse attribute assignments
133
- if 'instance_type' in line:
137
+ if "instance_type" in line:
134
138
  value = self._extract_tf_value(line)
135
139
  fact = TerraformFact(
136
140
  resource_type=current_resource,
137
141
  resource_id=current_resource_name,
138
- attribute='instance_type',
142
+ attribute="instance_type",
139
143
  value=value,
140
144
  terraform_file=str(tf_file.relative_to(self.terraform_dir)),
141
145
  line_number=line_num,
142
146
  citation_id=hashlib.md5(
143
147
  f"{current_resource}.{current_resource_name}.instance_type".encode()
144
- ).hexdigest()[:8]
148
+ ).hexdigest()[:8],
145
149
  )
146
150
  facts[fact.citation_id] = fact
147
-
148
- elif 'size' in line and current_resource == 'aws_ebs_volume':
151
+
152
+ elif "size" in line and current_resource == "aws_ebs_volume":
149
153
  value = self._extract_tf_value(line)
150
154
  fact = TerraformFact(
151
155
  resource_type=current_resource,
152
156
  resource_id=current_resource_name,
153
- attribute='size',
157
+ attribute="size",
154
158
  value=value,
155
159
  terraform_file=str(tf_file.relative_to(self.terraform_dir)),
156
160
  line_number=line_num,
157
161
  citation_id=hashlib.md5(
158
162
  f"{current_resource}.{current_resource_name}.size".encode()
159
- ).hexdigest()[:8]
163
+ ).hexdigest()[:8],
160
164
  )
161
165
  facts[fact.citation_id] = fact
162
-
166
+
163
167
  return facts
164
-
168
+
165
169
  def _extract_tf_value(self, line: str) -> str:
166
170
  """Extract value from terraform assignment line."""
167
- if '=' in line:
168
- value_part = line.split('=', 1)[1].strip()
171
+ if "=" in line:
172
+ value_part = line.split("=", 1)[1].strip()
169
173
  # Remove quotes and trailing characters
170
- value_part = value_part.strip('"').strip("'").rstrip(',').strip()
174
+ value_part = value_part.strip('"').strip("'").rstrip(",").strip()
171
175
  return value_part
172
176
  return ""
173
-
174
- def _create_fact_from_resource(self, resource: Dict, instance: Dict,
175
- state_file: Path) -> Optional[TerraformFact]:
177
+
178
+ def _create_fact_from_resource(self, resource: Dict, instance: Dict, state_file: Path) -> Optional[TerraformFact]:
176
179
  """Create a citeable fact from terraform resource."""
177
180
  try:
178
181
  # Extract cost-relevant attributes
179
- if resource['type'] == 'aws_nat_gateway':
182
+ if resource["type"] == "aws_nat_gateway":
180
183
  return TerraformFact(
181
- resource_type=resource['type'],
182
- resource_id=resource['name'],
183
- attribute='monthly_cost',
184
+ resource_type=resource["type"],
185
+ resource_id=resource["name"],
186
+ attribute="monthly_cost",
184
187
  value=32.4, # Would be calculated from terraform state
185
188
  terraform_file=str(state_file.relative_to(self.terraform_dir)),
186
189
  line_number=1, # Would parse actual line
187
- citation_id=hashlib.md5(
188
- f"{resource['type']}.{resource['name']}".encode()
189
- ).hexdigest()[:8]
190
+ citation_id=hashlib.md5(f"{resource['type']}.{resource['name']}".encode()).hexdigest()[:8],
190
191
  )
191
- elif resource['type'] == 'aws_ebs_volume':
192
- size = instance['attributes'].get('size', 0)
193
- volume_type = instance['attributes'].get('type', 'gp2')
192
+ elif resource["type"] == "aws_ebs_volume":
193
+ size = instance["attributes"].get("size", 0)
194
+ volume_type = instance["attributes"].get("type", "gp2")
194
195
  return TerraformFact(
195
- resource_type=resource['type'],
196
- resource_id=resource['name'],
197
- attribute='size_gb',
196
+ resource_type=resource["type"],
197
+ resource_id=resource["name"],
198
+ attribute="size_gb",
198
199
  value=size,
199
200
  terraform_file=str(state_file.relative_to(self.terraform_dir)),
200
201
  line_number=1,
201
- citation_id=hashlib.md5(
202
- f"{resource['type']}.{resource['name']}".encode()
203
- ).hexdigest()[:8]
202
+ citation_id=hashlib.md5(f"{resource['type']}.{resource['name']}".encode()).hexdigest()[:8],
204
203
  )
205
204
  except Exception:
206
205
  return None
207
-
206
+
208
207
  def validate_with_citations(self, runbook_output: Dict[str, Any]) -> Dict[str, Any]:
209
208
  """
210
209
  Validate runbook output with terraform facts and provide citations.
211
-
210
+
212
211
  This demonstrates how Citations API would work:
213
212
  1. Runbook produces cost calculation
214
213
  2. Validator finds relevant terraform facts
@@ -220,56 +219,53 @@ class TerraformCitationsValidator:
220
219
  "validated": True,
221
220
  "accuracy": 0.0,
222
221
  "citations": [],
223
- "drift_detected": []
222
+ "drift_detected": [],
224
223
  }
225
-
224
+
226
225
  # Example: Validate NAT Gateway cost calculation
227
- if 'nat_gateway_cost' in runbook_output:
228
- cited_fact = self._find_citation_for_cost(
229
- 'aws_nat_gateway',
230
- runbook_output['nat_gateway_cost']
231
- )
226
+ if "nat_gateway_cost" in runbook_output:
227
+ cited_fact = self._find_citation_for_cost("aws_nat_gateway", runbook_output["nat_gateway_cost"])
232
228
  if cited_fact:
233
- validation_result['citations'].append(cited_fact.to_citation())
234
-
229
+ validation_result["citations"].append(cited_fact.to_citation())
230
+
235
231
  # Example: Validate EBS volume costs
236
- if 'ebs_costs' in runbook_output:
237
- for volume_id, cost in runbook_output['ebs_costs'].items():
232
+ if "ebs_costs" in runbook_output:
233
+ for volume_id, cost in runbook_output["ebs_costs"].items():
238
234
  cited_fact = self._find_citation_for_volume(volume_id)
239
235
  if cited_fact:
240
- validation_result['citations'].append(cited_fact.to_citation())
241
-
236
+ validation_result["citations"].append(cited_fact.to_citation())
237
+
242
238
  # Calculate accuracy based on citations
243
- if validation_result['citations']:
244
- validation_result['accuracy'] = len(validation_result['citations']) / len(runbook_output) * 100
245
-
239
+ if validation_result["citations"]:
240
+ validation_result["accuracy"] = len(validation_result["citations"]) / len(runbook_output) * 100
241
+
246
242
  return validation_result
247
-
243
+
248
244
  def _find_citation_for_cost(self, resource_type: str, cost: float) -> Optional[TerraformFact]:
249
245
  """Find terraform fact to cite for a cost calculation."""
250
246
  for fact_id, fact in self.facts_db.items():
251
247
  if fact.resource_type == resource_type:
252
248
  return fact
253
249
  return None
254
-
250
+
255
251
  def _find_citation_for_volume(self, volume_id: str) -> Optional[TerraformFact]:
256
252
  """Find terraform fact for an EBS volume."""
257
253
  for fact_id, fact in self.facts_db.items():
258
- if fact.resource_type == 'aws_ebs_volume' and volume_id in fact.resource_id:
254
+ if fact.resource_type == "aws_ebs_volume" and volume_id in fact.resource_id:
259
255
  return fact
260
256
  return None
261
-
257
+
262
258
  def validate_with_pdf_knowledge(self, pdf_path: str) -> Dict[str, Any]:
263
259
  """
264
260
  Validate using PDF documents from knowledge-external directory.
265
-
261
+
266
262
  PDF SUPPORT FEASIBILITY:
267
263
  YES - PDF support is highly valuable for this runbooks project:
268
264
  1. AWS pricing documentation in PDF format
269
265
  2. Compliance reports and audit documents
270
266
  3. Architecture diagrams and cost models
271
267
  4. External knowledge validation sources
272
-
268
+
273
269
  USE CASES:
274
270
  - Validate pricing against AWS official PDFs
275
271
  - Cross-reference compliance requirements
@@ -278,38 +274,36 @@ class TerraformCitationsValidator:
278
274
  """
279
275
  if not PDF_SUPPORT:
280
276
  return {"error": "PyPDF2 not installed for PDF support"}
281
-
282
- validation_result = {
283
- "pdf_source": pdf_path,
284
- "extracted_facts": [],
285
- "validation_status": "pending"
286
- }
287
-
277
+
278
+ validation_result = {"pdf_source": pdf_path, "extracted_facts": [], "validation_status": "pending"}
279
+
288
280
  try:
289
281
  pdf_file = self.external_knowledge_dir / pdf_path
290
282
  if pdf_file.exists():
291
- with open(pdf_file, 'rb') as f:
283
+ with open(pdf_file, "rb") as f:
292
284
  pdf_reader = PyPDF2.PdfReader(f)
293
-
285
+
294
286
  # Extract text from PDF for validation
295
287
  for page_num, page in enumerate(pdf_reader.pages):
296
288
  text = page.extract_text()
297
-
289
+
298
290
  # Look for pricing information
299
- if 'NAT Gateway' in text and '$' in text:
300
- validation_result['extracted_facts'].append({
301
- "page": page_num + 1,
302
- "fact": "NAT Gateway pricing found",
303
- "citation": f"{pdf_path}:page_{page_num+1}"
304
- })
305
-
306
- validation_result['validation_status'] = 'completed'
307
-
291
+ if "NAT Gateway" in text and "$" in text:
292
+ validation_result["extracted_facts"].append(
293
+ {
294
+ "page": page_num + 1,
295
+ "fact": "NAT Gateway pricing found",
296
+ "citation": f"{pdf_path}:page_{page_num + 1}",
297
+ }
298
+ )
299
+
300
+ validation_result["validation_status"] = "completed"
301
+
308
302
  except Exception as e:
309
- validation_result['error'] = str(e)
310
-
303
+ validation_result["error"] = str(e)
304
+
311
305
  return validation_result
312
-
306
+
313
307
  def generate_citation_report(self) -> str:
314
308
  """Generate a report with all citations for audit trail."""
315
309
  report = []
@@ -318,14 +312,14 @@ class TerraformCitationsValidator:
318
312
  report.append(f"Terraform Directory: {self.terraform_dir}")
319
313
  report.append(f"Total Facts Extracted: {len(self.facts_db)}")
320
314
  report.append("")
321
-
315
+
322
316
  report.append("## Extracted Terraform Facts")
323
317
  for fact_id, fact in self.facts_db.items():
324
318
  report.append(f"- [{fact.citation_id}] {fact.resource_type}.{fact.resource_id}")
325
319
  report.append(f" Source: {fact.terraform_file}:{fact.line_number}")
326
320
  report.append(f" Value: {fact.attribute} = {fact.value}")
327
321
  report.append("")
328
-
322
+
329
323
  report.append("## Citations API Integration")
330
324
  report.append("```python")
331
325
  report.append("# Example usage with runbooks API:")
@@ -334,30 +328,25 @@ class TerraformCitationsValidator:
334
328
  report.append("result = validator.validate_with_citations(runbook_output)")
335
329
  report.append("print(f'Validation accuracy: {result[\"accuracy\"]}%')")
336
330
  report.append("```")
337
-
331
+
338
332
  return "\n".join(report)
339
333
 
334
+
340
335
  # Example usage demonstrating Citations API integration
341
336
  if __name__ == "__main__":
342
337
  validator = TerraformCitationsValidator()
343
-
338
+
344
339
  # Extract facts from terraform state
345
340
  facts = validator.extract_terraform_facts()
346
341
  print(f"Extracted {len(facts)} terraform facts for citation")
347
-
342
+
348
343
  # Example runbook output to validate
349
- example_output = {
350
- "nat_gateway_cost": 32.4,
351
- "ebs_costs": {
352
- "vol-12345": 8.0,
353
- "vol-67890": 10.0
354
- }
355
- }
356
-
344
+ example_output = {"nat_gateway_cost": 32.4, "ebs_costs": {"vol-12345": 8.0, "vol-67890": 10.0}}
345
+
357
346
  # Validate with citations
358
347
  validation = validator.validate_with_citations(example_output)
359
348
  print(f"Validation result: {validation}")
360
-
349
+
361
350
  # Generate report
362
351
  report = validator.generate_citation_report()
363
- print(report)
352
+ print(report)