runbooks 1.1.4__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.
- runbooks/__init__.py +31 -2
- runbooks/__init___optimized.py +18 -4
- runbooks/_platform/__init__.py +1 -5
- runbooks/_platform/core/runbooks_wrapper.py +141 -138
- runbooks/aws2/accuracy_validator.py +812 -0
- runbooks/base.py +7 -0
- runbooks/cfat/assessment/compliance.py +1 -1
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cli/__init__.py +1 -1
- runbooks/cli/commands/cfat.py +64 -23
- runbooks/cli/commands/finops.py +1005 -54
- runbooks/cli/commands/inventory.py +138 -35
- runbooks/cli/commands/operate.py +9 -36
- runbooks/cli/commands/security.py +42 -18
- runbooks/cli/commands/validation.py +432 -18
- runbooks/cli/commands/vpc.py +81 -17
- runbooks/cli/registry.py +22 -10
- runbooks/cloudops/__init__.py +20 -27
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +544 -542
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +224 -225
- runbooks/cloudops/lifecycle_manager.py +5 -4
- runbooks/cloudops/mcp_cost_validation.py +252 -235
- runbooks/cloudops/models.py +78 -53
- runbooks/cloudops/monitoring_automation.py +5 -4
- runbooks/cloudops/notebook_framework.py +177 -213
- runbooks/cloudops/security_enforcer.py +125 -159
- runbooks/common/accuracy_validator.py +11 -0
- runbooks/common/aws_pricing.py +349 -326
- runbooks/common/aws_pricing_api.py +211 -212
- runbooks/common/aws_profile_manager.py +40 -36
- runbooks/common/aws_utils.py +74 -79
- runbooks/common/business_logic.py +126 -104
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
- runbooks/common/cross_account_manager.py +197 -204
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +29 -19
- runbooks/common/dry_run_examples.py +173 -208
- runbooks/common/dry_run_framework.py +157 -155
- runbooks/common/enhanced_exception_handler.py +15 -4
- runbooks/common/enhanced_logging_example.py +50 -64
- runbooks/common/enhanced_logging_integration_example.py +65 -37
- runbooks/common/env_utils.py +16 -16
- runbooks/common/error_handling.py +40 -38
- runbooks/common/lazy_loader.py +41 -23
- runbooks/common/logging_integration_helper.py +79 -86
- runbooks/common/mcp_cost_explorer_integration.py +476 -493
- runbooks/common/mcp_integration.py +63 -74
- runbooks/common/memory_optimization.py +140 -118
- runbooks/common/module_cli_base.py +37 -58
- runbooks/common/organizations_client.py +175 -193
- runbooks/common/patterns.py +23 -25
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +111 -37
- runbooks/common/rich_utils.py +201 -141
- runbooks/common/sre_performance_suite.py +177 -186
- runbooks/enterprise/__init__.py +1 -1
- runbooks/enterprise/logging.py +144 -106
- runbooks/enterprise/security.py +187 -204
- runbooks/enterprise/validation.py +43 -56
- runbooks/finops/__init__.py +26 -30
- runbooks/finops/account_resolver.py +1 -1
- runbooks/finops/advanced_optimization_engine.py +980 -0
- runbooks/finops/automation_core.py +268 -231
- runbooks/finops/business_case_config.py +184 -179
- runbooks/finops/cli.py +660 -139
- runbooks/finops/commvault_ec2_analysis.py +157 -164
- runbooks/finops/compute_cost_optimizer.py +336 -320
- runbooks/finops/config.py +20 -20
- runbooks/finops/cost_optimizer.py +484 -618
- runbooks/finops/cost_processor.py +332 -214
- runbooks/finops/dashboard_runner.py +1006 -172
- runbooks/finops/ebs_cost_optimizer.py +991 -657
- runbooks/finops/elastic_ip_optimizer.py +317 -257
- runbooks/finops/enhanced_mcp_integration.py +340 -0
- runbooks/finops/enhanced_progress.py +32 -29
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +223 -285
- runbooks/finops/executive_export.py +203 -160
- runbooks/finops/helpers.py +130 -288
- runbooks/finops/iam_guidance.py +1 -1
- runbooks/finops/infrastructure/__init__.py +80 -0
- runbooks/finops/infrastructure/commands.py +506 -0
- runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
- runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
- runbooks/finops/markdown_exporter.py +337 -174
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1512 -481
- runbooks/finops/network_cost_optimizer.py +657 -587
- runbooks/finops/notebook_utils.py +226 -188
- runbooks/finops/optimization_engine.py +1136 -0
- runbooks/finops/optimizer.py +19 -23
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +64 -65
- runbooks/finops/scenarios.py +1277 -438
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +259 -265
- runbooks/finops/vpc_cleanup_exporter.py +189 -144
- runbooks/finops/vpc_cleanup_optimizer.py +591 -573
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +1 -1
- runbooks/inventory/collectors/aws_networking.py +109 -99
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/inventory_mcp_cli.py +48 -46
- runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
- runbooks/inventory/mcp_inventory_validator.py +549 -465
- runbooks/inventory/mcp_vpc_validator.py +359 -442
- runbooks/inventory/organizations_discovery.py +55 -51
- runbooks/inventory/rich_inventory_display.py +33 -32
- runbooks/inventory/unified_validation_engine.py +278 -251
- runbooks/inventory/vpc_analyzer.py +732 -695
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +382 -378
- runbooks/inventory/vpc_flow_analyzer.py +1 -1
- runbooks/main.py +49 -34
- runbooks/main_final.py +91 -60
- runbooks/main_minimal.py +22 -10
- runbooks/main_optimized.py +131 -100
- runbooks/main_ultra_minimal.py +7 -2
- runbooks/mcp/__init__.py +36 -0
- runbooks/mcp/integration.py +679 -0
- runbooks/monitoring/performance_monitor.py +9 -4
- runbooks/operate/dynamodb_operations.py +3 -1
- runbooks/operate/ec2_operations.py +145 -137
- runbooks/operate/iam_operations.py +146 -152
- runbooks/operate/networking_cost_heatmap.py +29 -8
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_operations.py +646 -616
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +70 -66
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +86 -60
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +46 -41
- runbooks/security/__init__.py +19 -0
- runbooks/security/assessment_runner.py +1150 -0
- runbooks/security/baseline_checker.py +812 -0
- runbooks/security/cloudops_automation_security_validator.py +509 -535
- runbooks/security/compliance_automation_engine.py +17 -17
- runbooks/security/config/__init__.py +2 -2
- runbooks/security/config/compliance_config.py +50 -50
- runbooks/security/config_template_generator.py +63 -76
- runbooks/security/enterprise_security_framework.py +1 -1
- runbooks/security/executive_security_dashboard.py +519 -508
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/security_baseline_tester.py +1 -1
- runbooks/security/security_cli.py +143 -112
- runbooks/security/test_2way_validation.py +439 -0
- runbooks/security/two_way_validation_framework.py +852 -0
- runbooks/sre/production_monitoring_framework.py +167 -177
- runbooks/tdd/__init__.py +15 -0
- runbooks/tdd/cli.py +1071 -0
- runbooks/utils/__init__.py +14 -17
- runbooks/utils/logger.py +7 -2
- runbooks/utils/version_validator.py +50 -47
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +745 -704
- runbooks/validation/mcp_validator.py +906 -228
- runbooks/validation/terraform_citations_validator.py +104 -115
- runbooks/validation/terraform_drift_detector.py +447 -451
- runbooks/vpc/README.md +617 -0
- runbooks/vpc/__init__.py +8 -1
- runbooks/vpc/analyzer.py +577 -0
- runbooks/vpc/cleanup_wrapper.py +476 -413
- runbooks/vpc/cli_cloudtrail_commands.py +339 -0
- runbooks/vpc/cli_mcp_validation_commands.py +480 -0
- runbooks/vpc/cloudtrail_audit_integration.py +717 -0
- runbooks/vpc/config.py +92 -97
- runbooks/vpc/cost_engine.py +411 -148
- runbooks/vpc/cost_explorer_integration.py +553 -0
- runbooks/vpc/cross_account_session.py +101 -106
- runbooks/vpc/enhanced_mcp_validation.py +917 -0
- runbooks/vpc/eni_gate_validator.py +961 -0
- runbooks/vpc/heatmap_engine.py +185 -160
- runbooks/vpc/mcp_no_eni_validator.py +680 -639
- runbooks/vpc/nat_gateway_optimizer.py +358 -0
- runbooks/vpc/networking_wrapper.py +15 -8
- runbooks/vpc/pdca_remediation_planner.py +528 -0
- runbooks/vpc/performance_optimized_analyzer.py +219 -231
- runbooks/vpc/runbooks_adapter.py +1167 -241
- runbooks/vpc/tdd_red_phase_stubs.py +601 -0
- runbooks/vpc/test_data_loader.py +358 -0
- runbooks/vpc/tests/conftest.py +314 -4
- runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
- runbooks/vpc/tests/test_cost_engine.py +0 -2
- runbooks/vpc/topology_generator.py +326 -0
- runbooks/vpc/unified_scenarios.py +1297 -1124
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.5.dist-info/METADATA +328 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/RECORD +214 -193
- runbooks/finops/README.md +0 -414
- runbooks/finops/accuracy_cross_validator.py +0 -647
- runbooks/finops/business_cases.py +0 -950
- runbooks/finops/dashboard_router.py +0 -922
- runbooks/finops/ebs_optimizer.py +0 -973
- runbooks/finops/embedded_mcp_validator.py +0 -1629
- runbooks/finops/enhanced_dashboard_runner.py +0 -527
- runbooks/finops/finops_dashboard.py +0 -584
- runbooks/finops/finops_scenarios.py +0 -1218
- runbooks/finops/legacy_migration.py +0 -730
- runbooks/finops/multi_dashboard.py +0 -1519
- runbooks/finops/single_dashboard.py +0 -1113
- runbooks/finops/unlimited_scenarios.py +0 -393
- runbooks-1.1.4.dist-info/METADATA +0 -800
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.4.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,
|
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(
|
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(
|
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
|
123
|
-
brace_count += line.count(
|
124
|
-
if
|
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
|
135
|
+
if current_resource and current_resource_name and "=" in line:
|
132
136
|
# Parse attribute assignments
|
133
|
-
if
|
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=
|
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
|
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=
|
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
|
168
|
-
value_part = line.split(
|
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(
|
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[
|
182
|
+
if resource["type"] == "aws_nat_gateway":
|
180
183
|
return TerraformFact(
|
181
|
-
resource_type=resource[
|
182
|
-
resource_id=resource[
|
183
|
-
attribute=
|
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[
|
192
|
-
size = instance[
|
193
|
-
volume_type = instance[
|
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[
|
196
|
-
resource_id=resource[
|
197
|
-
attribute=
|
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
|
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[
|
234
|
-
|
229
|
+
validation_result["citations"].append(cited_fact.to_citation())
|
230
|
+
|
235
231
|
# Example: Validate EBS volume costs
|
236
|
-
if
|
237
|
-
for volume_id, cost in runbook_output[
|
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[
|
241
|
-
|
236
|
+
validation_result["citations"].append(cited_fact.to_citation())
|
237
|
+
|
242
238
|
# Calculate accuracy based on citations
|
243
|
-
if validation_result[
|
244
|
-
validation_result[
|
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 ==
|
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
|
-
|
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,
|
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
|
300
|
-
validation_result[
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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[
|
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
|
-
|
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)
|