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
@@ -1,647 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Accuracy Cross-Validator - Real-Time Numerical Verification Engine
|
4
|
-
================================================================
|
5
|
-
|
6
|
-
BUSINESS CRITICAL: "Are you really 100% sure about ALL of NUMBERS & figures?"
|
7
|
-
|
8
|
-
This module provides real-time cross-validation of ALL numerical data displayed
|
9
|
-
in FinOps dashboards, ensuring 100% accuracy with enterprise-grade validation.
|
10
|
-
|
11
|
-
Features:
|
12
|
-
- Real-time cross-validation between multiple data sources
|
13
|
-
- Automated discrepancy detection and alerting
|
14
|
-
- 99.99% accuracy validation with <0.01% tolerance
|
15
|
-
- Live accuracy scoring and quality gates
|
16
|
-
- Complete audit trail for compliance reporting
|
17
|
-
- Performance optimized for enterprise scale
|
18
|
-
"""
|
19
|
-
|
20
|
-
import asyncio
|
21
|
-
import json
|
22
|
-
import logging
|
23
|
-
import time
|
24
|
-
from dataclasses import dataclass, field
|
25
|
-
from datetime import datetime, timedelta
|
26
|
-
from decimal import ROUND_HALF_UP, Decimal, getcontext
|
27
|
-
from enum import Enum
|
28
|
-
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
29
|
-
|
30
|
-
# Set decimal context for financial precision
|
31
|
-
getcontext().prec = 28
|
32
|
-
|
33
|
-
import boto3
|
34
|
-
from rich.console import Console
|
35
|
-
from rich.panel import Panel
|
36
|
-
from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn
|
37
|
-
from rich.table import Table
|
38
|
-
|
39
|
-
from ..common.rich_utils import (
|
40
|
-
console as rich_console,
|
41
|
-
)
|
42
|
-
from ..common.rich_utils import (
|
43
|
-
format_cost,
|
44
|
-
print_error,
|
45
|
-
print_info,
|
46
|
-
print_success,
|
47
|
-
print_warning,
|
48
|
-
)
|
49
|
-
|
50
|
-
|
51
|
-
class ValidationStatus(Enum):
|
52
|
-
"""Validation status enumeration for clear status tracking."""
|
53
|
-
|
54
|
-
PASSED = "PASSED"
|
55
|
-
FAILED = "FAILED"
|
56
|
-
WARNING = "WARNING"
|
57
|
-
ERROR = "ERROR"
|
58
|
-
IN_PROGRESS = "IN_PROGRESS"
|
59
|
-
|
60
|
-
|
61
|
-
class AccuracyLevel(Enum):
|
62
|
-
"""Accuracy level definitions for enterprise compliance."""
|
63
|
-
|
64
|
-
ENTERPRISE = 99.99 # 99.99% - Enterprise financial reporting
|
65
|
-
BUSINESS = 99.50 # 99.50% - Business intelligence
|
66
|
-
OPERATIONAL = 95.00 # 95.00% - Operational monitoring
|
67
|
-
DEVELOPMENT = 90.00 # 90.00% - Development/testing
|
68
|
-
|
69
|
-
|
70
|
-
@dataclass
|
71
|
-
class ValidationResult:
|
72
|
-
"""Comprehensive validation result with full audit trail."""
|
73
|
-
|
74
|
-
description: str
|
75
|
-
calculated_value: Union[float, int, str]
|
76
|
-
reference_value: Union[float, int, str]
|
77
|
-
accuracy_percent: float
|
78
|
-
absolute_difference: float
|
79
|
-
tolerance_met: bool
|
80
|
-
validation_status: ValidationStatus
|
81
|
-
source: str
|
82
|
-
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
83
|
-
metadata: Dict[str, Any] = field(default_factory=dict)
|
84
|
-
|
85
|
-
|
86
|
-
@dataclass
|
87
|
-
class CrossValidationReport:
|
88
|
-
"""Comprehensive cross-validation report for enterprise audit."""
|
89
|
-
|
90
|
-
total_validations: int
|
91
|
-
passed_validations: int
|
92
|
-
failed_validations: int
|
93
|
-
overall_accuracy: float
|
94
|
-
accuracy_level_met: AccuracyLevel
|
95
|
-
validation_results: List[ValidationResult]
|
96
|
-
execution_time: float
|
97
|
-
report_timestamp: str
|
98
|
-
compliance_status: Dict[str, Any]
|
99
|
-
quality_gates: Dict[str, bool]
|
100
|
-
|
101
|
-
|
102
|
-
class AccuracyCrossValidator:
|
103
|
-
"""
|
104
|
-
Enterprise-grade accuracy cross-validation engine.
|
105
|
-
|
106
|
-
Provides real-time numerical accuracy verification with comprehensive
|
107
|
-
audit trails and quality gates for financial compliance.
|
108
|
-
"""
|
109
|
-
|
110
|
-
def __init__(
|
111
|
-
self,
|
112
|
-
accuracy_level: AccuracyLevel = AccuracyLevel.ENTERPRISE,
|
113
|
-
tolerance_percent: float = 0.01,
|
114
|
-
console: Optional[Console] = None,
|
115
|
-
):
|
116
|
-
"""
|
117
|
-
Initialize accuracy cross-validator.
|
118
|
-
|
119
|
-
Args:
|
120
|
-
accuracy_level: Required accuracy level (default: ENTERPRISE 99.99%)
|
121
|
-
tolerance_percent: Tolerance threshold (default: 0.01%)
|
122
|
-
console: Rich console for output (optional)
|
123
|
-
"""
|
124
|
-
self.accuracy_level = accuracy_level
|
125
|
-
self.tolerance_percent = tolerance_percent
|
126
|
-
self.console = console or rich_console
|
127
|
-
self.validation_results: List[ValidationResult] = []
|
128
|
-
self.logger = logging.getLogger(__name__)
|
129
|
-
|
130
|
-
# Performance tracking
|
131
|
-
self.validation_start_time = None
|
132
|
-
self.validation_counts = {
|
133
|
-
ValidationStatus.PASSED: 0,
|
134
|
-
ValidationStatus.FAILED: 0,
|
135
|
-
ValidationStatus.WARNING: 0,
|
136
|
-
ValidationStatus.ERROR: 0,
|
137
|
-
}
|
138
|
-
|
139
|
-
def validate_financial_calculation(
|
140
|
-
self, calculated_value: float, reference_value: float, description: str, source: str = "financial_calculation"
|
141
|
-
) -> ValidationResult:
|
142
|
-
"""
|
143
|
-
Validate financial calculation with enterprise precision.
|
144
|
-
|
145
|
-
Args:
|
146
|
-
calculated_value: System calculated value
|
147
|
-
reference_value: Reference/expected value
|
148
|
-
description: Description of calculation
|
149
|
-
source: Source identifier for audit trail
|
150
|
-
|
151
|
-
Returns:
|
152
|
-
Comprehensive validation result
|
153
|
-
"""
|
154
|
-
# Use Decimal for precise financial calculations
|
155
|
-
calc_decimal = Decimal(str(calculated_value)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
156
|
-
ref_decimal = Decimal(str(reference_value)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
157
|
-
|
158
|
-
# Calculate accuracy metrics
|
159
|
-
if ref_decimal != 0:
|
160
|
-
accuracy_percent = float((1 - abs(calc_decimal - ref_decimal) / abs(ref_decimal)) * 100)
|
161
|
-
else:
|
162
|
-
accuracy_percent = 100.0 if calc_decimal == 0 else 0.0
|
163
|
-
|
164
|
-
absolute_difference = float(abs(calc_decimal - ref_decimal))
|
165
|
-
|
166
|
-
# Determine validation status
|
167
|
-
tolerance_met = (absolute_difference / max(float(abs(ref_decimal)), 1)) * 100 <= self.tolerance_percent
|
168
|
-
accuracy_met = accuracy_percent >= self.accuracy_level.value
|
169
|
-
|
170
|
-
if accuracy_met and tolerance_met:
|
171
|
-
validation_status = ValidationStatus.PASSED
|
172
|
-
elif accuracy_percent >= AccuracyLevel.BUSINESS.value:
|
173
|
-
validation_status = ValidationStatus.WARNING
|
174
|
-
else:
|
175
|
-
validation_status = ValidationStatus.FAILED
|
176
|
-
|
177
|
-
# Create validation result
|
178
|
-
result = ValidationResult(
|
179
|
-
description=description,
|
180
|
-
calculated_value=float(calc_decimal),
|
181
|
-
reference_value=float(ref_decimal),
|
182
|
-
accuracy_percent=accuracy_percent,
|
183
|
-
absolute_difference=absolute_difference,
|
184
|
-
tolerance_met=tolerance_met,
|
185
|
-
validation_status=validation_status,
|
186
|
-
source=source,
|
187
|
-
metadata={
|
188
|
-
"accuracy_level_required": self.accuracy_level.value,
|
189
|
-
"tolerance_threshold": self.tolerance_percent,
|
190
|
-
"precision_used": "Decimal_2dp",
|
191
|
-
},
|
192
|
-
)
|
193
|
-
|
194
|
-
# Track result
|
195
|
-
self._track_validation_result(result)
|
196
|
-
return result
|
197
|
-
|
198
|
-
def validate_count_accuracy(
|
199
|
-
self, calculated_count: int, reference_count: int, description: str, source: str = "count_validation"
|
200
|
-
) -> ValidationResult:
|
201
|
-
"""
|
202
|
-
Validate count accuracy (must be exact for counts).
|
203
|
-
|
204
|
-
Args:
|
205
|
-
calculated_count: System calculated count
|
206
|
-
reference_count: Reference count
|
207
|
-
description: Description of count
|
208
|
-
source: Source identifier
|
209
|
-
|
210
|
-
Returns:
|
211
|
-
Validation result (exact match required for counts)
|
212
|
-
"""
|
213
|
-
# Counts must be exact integers
|
214
|
-
accuracy_percent = 100.0 if calculated_count == reference_count else 0.0
|
215
|
-
absolute_difference = abs(calculated_count - reference_count)
|
216
|
-
|
217
|
-
validation_status = ValidationStatus.PASSED if accuracy_percent == 100.0 else ValidationStatus.FAILED
|
218
|
-
|
219
|
-
result = ValidationResult(
|
220
|
-
description=description,
|
221
|
-
calculated_value=calculated_count,
|
222
|
-
reference_value=reference_count,
|
223
|
-
accuracy_percent=accuracy_percent,
|
224
|
-
absolute_difference=absolute_difference,
|
225
|
-
tolerance_met=accuracy_percent == 100.0,
|
226
|
-
validation_status=validation_status,
|
227
|
-
source=source,
|
228
|
-
metadata={"validation_type": "exact_count_match", "precision_required": "integer_exact"},
|
229
|
-
)
|
230
|
-
|
231
|
-
self._track_validation_result(result)
|
232
|
-
return result
|
233
|
-
|
234
|
-
def validate_percentage_calculation(
|
235
|
-
self,
|
236
|
-
calculated_percent: float,
|
237
|
-
numerator: float,
|
238
|
-
denominator: float,
|
239
|
-
description: str,
|
240
|
-
source: str = "percentage_calculation",
|
241
|
-
) -> ValidationResult:
|
242
|
-
"""
|
243
|
-
Validate percentage calculation with mathematical verification.
|
244
|
-
|
245
|
-
Args:
|
246
|
-
calculated_percent: System calculated percentage
|
247
|
-
numerator: Numerator value
|
248
|
-
denominator: Denominator value
|
249
|
-
description: Description of percentage
|
250
|
-
source: Source identifier
|
251
|
-
|
252
|
-
Returns:
|
253
|
-
Validation result with mathematical verification
|
254
|
-
"""
|
255
|
-
# Calculate expected percentage
|
256
|
-
if denominator != 0:
|
257
|
-
expected_percent = (numerator / denominator) * 100
|
258
|
-
else:
|
259
|
-
expected_percent = 0.0
|
260
|
-
|
261
|
-
return self.validate_financial_calculation(
|
262
|
-
calculated_percent, expected_percent, f"Percentage Validation: {description}", f"{source}_percentage"
|
263
|
-
)
|
264
|
-
|
265
|
-
def validate_sum_aggregation(
|
266
|
-
self, calculated_sum: float, individual_values: List[float], description: str, source: str = "sum_aggregation"
|
267
|
-
) -> ValidationResult:
|
268
|
-
"""
|
269
|
-
Validate sum aggregation accuracy.
|
270
|
-
|
271
|
-
Args:
|
272
|
-
calculated_sum: System calculated sum
|
273
|
-
individual_values: Individual values to sum
|
274
|
-
description: Description of aggregation
|
275
|
-
source: Source identifier
|
276
|
-
|
277
|
-
Returns:
|
278
|
-
Validation result for aggregation
|
279
|
-
"""
|
280
|
-
# Calculate expected sum with safe Decimal precision
|
281
|
-
try:
|
282
|
-
# Convert each value safely to Decimal
|
283
|
-
decimal_values = []
|
284
|
-
for val in individual_values:
|
285
|
-
try:
|
286
|
-
decimal_val = Decimal(str(val)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
287
|
-
decimal_values.append(decimal_val)
|
288
|
-
except:
|
289
|
-
# If individual value fails, use rounded float
|
290
|
-
decimal_values.append(Decimal(str(round(float(val), 2))))
|
291
|
-
|
292
|
-
expected_sum = sum(decimal_values)
|
293
|
-
except Exception:
|
294
|
-
# Ultimate fallback to float calculation
|
295
|
-
expected_sum = Decimal(str(round(sum(individual_values), 2)))
|
296
|
-
|
297
|
-
return self.validate_financial_calculation(
|
298
|
-
calculated_sum, float(expected_sum), f"Sum Aggregation: {description}", f"{source}_aggregation"
|
299
|
-
)
|
300
|
-
|
301
|
-
async def cross_validate_with_aws_api(
|
302
|
-
self, runbooks_data: Dict[str, Any], aws_profiles: List[str]
|
303
|
-
) -> List[ValidationResult]:
|
304
|
-
"""
|
305
|
-
Cross-validate runbooks data against AWS API independently.
|
306
|
-
|
307
|
-
Args:
|
308
|
-
runbooks_data: Data from runbooks analysis
|
309
|
-
aws_profiles: AWS profiles for independent validation
|
310
|
-
|
311
|
-
Returns:
|
312
|
-
List of cross-validation results
|
313
|
-
"""
|
314
|
-
cross_validation_results = []
|
315
|
-
|
316
|
-
with Progress(
|
317
|
-
SpinnerColumn(),
|
318
|
-
TextColumn("[progress.description]{task.description}"),
|
319
|
-
BarColumn(),
|
320
|
-
TaskProgressColumn(),
|
321
|
-
console=self.console,
|
322
|
-
) as progress:
|
323
|
-
task = progress.add_task("Cross-validating with AWS APIs...", total=len(aws_profiles))
|
324
|
-
|
325
|
-
for profile in aws_profiles:
|
326
|
-
try:
|
327
|
-
# Get independent AWS data
|
328
|
-
aws_data = await self._get_independent_aws_data(profile)
|
329
|
-
|
330
|
-
# Find corresponding runbooks data
|
331
|
-
runbooks_profile_data = self._extract_profile_data(runbooks_data, profile)
|
332
|
-
|
333
|
-
# Validate total costs
|
334
|
-
if "total_cost" in runbooks_profile_data and "total_cost" in aws_data:
|
335
|
-
cost_validation = self.validate_financial_calculation(
|
336
|
-
runbooks_profile_data["total_cost"],
|
337
|
-
aws_data["total_cost"],
|
338
|
-
f"Total cost cross-validation: {profile[:30]}...",
|
339
|
-
"aws_api_cross_validation",
|
340
|
-
)
|
341
|
-
cross_validation_results.append(cost_validation)
|
342
|
-
|
343
|
-
# Validate service-level costs
|
344
|
-
runbooks_services = runbooks_profile_data.get("services", {})
|
345
|
-
aws_services = aws_data.get("services", {})
|
346
|
-
|
347
|
-
for service in set(runbooks_services.keys()) & set(aws_services.keys()):
|
348
|
-
service_validation = self.validate_financial_calculation(
|
349
|
-
runbooks_services[service],
|
350
|
-
aws_services[service],
|
351
|
-
f"Service cost cross-validation: {service}",
|
352
|
-
f"aws_api_service_validation_{profile[:20]}",
|
353
|
-
)
|
354
|
-
cross_validation_results.append(service_validation)
|
355
|
-
|
356
|
-
progress.advance(task)
|
357
|
-
|
358
|
-
except Exception as e:
|
359
|
-
error_result = ValidationResult(
|
360
|
-
description=f"Cross-validation error for {profile[:30]}...",
|
361
|
-
calculated_value=0.0,
|
362
|
-
reference_value=0.0,
|
363
|
-
accuracy_percent=0.0,
|
364
|
-
absolute_difference=0.0,
|
365
|
-
tolerance_met=False,
|
366
|
-
validation_status=ValidationStatus.ERROR,
|
367
|
-
source="aws_api_cross_validation_error",
|
368
|
-
metadata={"error": str(e)},
|
369
|
-
)
|
370
|
-
cross_validation_results.append(error_result)
|
371
|
-
self._track_validation_result(error_result)
|
372
|
-
progress.advance(task)
|
373
|
-
|
374
|
-
return cross_validation_results
|
375
|
-
|
376
|
-
async def _get_independent_aws_data(self, profile: str) -> Dict[str, Any]:
|
377
|
-
"""Get independent cost data from AWS API for cross-validation."""
|
378
|
-
try:
|
379
|
-
session = boto3.Session(profile_name=profile)
|
380
|
-
ce_client = session.client("ce", region_name="us-east-1")
|
381
|
-
|
382
|
-
# Get current month cost data with September 1st fix
|
383
|
-
end_date = datetime.now().date()
|
384
|
-
start_date = end_date.replace(day=1)
|
385
|
-
|
386
|
-
# CRITICAL FIX: September 1st boundary handling (matches cost_processor.py)
|
387
|
-
if end_date.day == 1:
|
388
|
-
self.console.log(f"[yellow]⚠️ Cross-Validator: First day of month detected ({end_date.strftime('%B %d, %Y')}) - using partial period[/]")
|
389
|
-
# For AWS Cost Explorer, end date is exclusive, so add one day to include today
|
390
|
-
end_date = end_date + timedelta(days=1)
|
391
|
-
else:
|
392
|
-
# Normal case: include up to today (exclusive end date)
|
393
|
-
end_date = end_date + timedelta(days=1)
|
394
|
-
|
395
|
-
response = ce_client.get_cost_and_usage(
|
396
|
-
TimePeriod={"Start": start_date.isoformat(), "End": end_date.isoformat()},
|
397
|
-
Granularity="MONTHLY",
|
398
|
-
Metrics=["UnblendedCost"],
|
399
|
-
GroupBy=[{"Type": "DIMENSION", "Key": "SERVICE"}],
|
400
|
-
)
|
401
|
-
|
402
|
-
# Process response
|
403
|
-
total_cost = 0.0
|
404
|
-
services = {}
|
405
|
-
|
406
|
-
if response.get("ResultsByTime"):
|
407
|
-
for result in response["ResultsByTime"]:
|
408
|
-
for group in result.get("Groups", []):
|
409
|
-
service = group.get("Keys", ["Unknown"])[0]
|
410
|
-
cost = float(group.get("Metrics", {}).get("UnblendedCost", {}).get("Amount", 0))
|
411
|
-
services[service] = cost
|
412
|
-
total_cost += cost
|
413
|
-
|
414
|
-
return {
|
415
|
-
"total_cost": total_cost,
|
416
|
-
"services": services,
|
417
|
-
"profile": profile,
|
418
|
-
"data_source": "independent_aws_api",
|
419
|
-
}
|
420
|
-
|
421
|
-
except Exception as e:
|
422
|
-
return {
|
423
|
-
"total_cost": 0.0,
|
424
|
-
"services": {},
|
425
|
-
"profile": profile,
|
426
|
-
"data_source": "error_fallback",
|
427
|
-
"error": str(e),
|
428
|
-
}
|
429
|
-
|
430
|
-
def _extract_profile_data(self, runbooks_data: Dict[str, Any], profile: str) -> Dict[str, Any]:
|
431
|
-
"""Extract data for specific profile from runbooks results."""
|
432
|
-
# Adapt based on actual runbooks data structure
|
433
|
-
# This is a simplified implementation
|
434
|
-
return {
|
435
|
-
"total_cost": runbooks_data.get("total_cost", 0.0),
|
436
|
-
"services": runbooks_data.get("services", {}),
|
437
|
-
"profile": profile,
|
438
|
-
}
|
439
|
-
|
440
|
-
def _track_validation_result(self, result: ValidationResult) -> None:
|
441
|
-
"""Track validation result for reporting."""
|
442
|
-
self.validation_results.append(result)
|
443
|
-
self.validation_counts[result.validation_status] += 1
|
444
|
-
|
445
|
-
def generate_accuracy_report(self) -> CrossValidationReport:
|
446
|
-
"""
|
447
|
-
Generate comprehensive accuracy report for enterprise compliance.
|
448
|
-
|
449
|
-
Returns:
|
450
|
-
Complete cross-validation report with audit trail
|
451
|
-
"""
|
452
|
-
if not self.validation_results:
|
453
|
-
return CrossValidationReport(
|
454
|
-
total_validations=0,
|
455
|
-
passed_validations=0,
|
456
|
-
failed_validations=0,
|
457
|
-
overall_accuracy=0.0,
|
458
|
-
accuracy_level_met=AccuracyLevel.DEVELOPMENT,
|
459
|
-
validation_results=[],
|
460
|
-
execution_time=0.0,
|
461
|
-
report_timestamp=datetime.now().isoformat(),
|
462
|
-
compliance_status={"status": "NO_VALIDATIONS"},
|
463
|
-
quality_gates={"audit_ready": False},
|
464
|
-
)
|
465
|
-
|
466
|
-
# Calculate metrics
|
467
|
-
total_validations = len(self.validation_results)
|
468
|
-
passed_validations = self.validation_counts[ValidationStatus.PASSED]
|
469
|
-
failed_validations = self.validation_counts[ValidationStatus.FAILED]
|
470
|
-
|
471
|
-
# Calculate overall accuracy
|
472
|
-
valid_results = [r for r in self.validation_results if r.accuracy_percent > 0]
|
473
|
-
if valid_results:
|
474
|
-
overall_accuracy = sum(r.accuracy_percent for r in valid_results) / len(valid_results)
|
475
|
-
else:
|
476
|
-
overall_accuracy = 0.0
|
477
|
-
|
478
|
-
# Determine accuracy level met
|
479
|
-
accuracy_level_met = AccuracyLevel.DEVELOPMENT
|
480
|
-
if overall_accuracy >= AccuracyLevel.ENTERPRISE.value:
|
481
|
-
accuracy_level_met = AccuracyLevel.ENTERPRISE
|
482
|
-
elif overall_accuracy >= AccuracyLevel.BUSINESS.value:
|
483
|
-
accuracy_level_met = AccuracyLevel.BUSINESS
|
484
|
-
elif overall_accuracy >= AccuracyLevel.OPERATIONAL.value:
|
485
|
-
accuracy_level_met = AccuracyLevel.OPERATIONAL
|
486
|
-
|
487
|
-
# Calculate execution time
|
488
|
-
execution_time = time.time() - (self.validation_start_time or time.time())
|
489
|
-
|
490
|
-
# Compliance assessment
|
491
|
-
compliance_status = {
|
492
|
-
"enterprise_grade": overall_accuracy >= AccuracyLevel.ENTERPRISE.value,
|
493
|
-
"audit_ready": overall_accuracy >= AccuracyLevel.ENTERPRISE.value
|
494
|
-
and (passed_validations / total_validations) >= 0.95,
|
495
|
-
"regulatory_compliant": overall_accuracy >= AccuracyLevel.BUSINESS.value,
|
496
|
-
"meets_tolerance": sum(1 for r in self.validation_results if r.tolerance_met) / total_validations >= 0.95,
|
497
|
-
}
|
498
|
-
|
499
|
-
# Quality gates
|
500
|
-
quality_gates = {
|
501
|
-
"accuracy_threshold_met": overall_accuracy >= self.accuracy_level.value,
|
502
|
-
"tolerance_requirements_met": compliance_status["meets_tolerance"],
|
503
|
-
"performance_acceptable": execution_time < 30.0, # 30 second performance target
|
504
|
-
"audit_ready": compliance_status["audit_ready"],
|
505
|
-
}
|
506
|
-
|
507
|
-
return CrossValidationReport(
|
508
|
-
total_validations=total_validations,
|
509
|
-
passed_validations=passed_validations,
|
510
|
-
failed_validations=failed_validations,
|
511
|
-
overall_accuracy=overall_accuracy,
|
512
|
-
accuracy_level_met=accuracy_level_met,
|
513
|
-
validation_results=self.validation_results,
|
514
|
-
execution_time=execution_time,
|
515
|
-
report_timestamp=datetime.now().isoformat(),
|
516
|
-
compliance_status=compliance_status,
|
517
|
-
quality_gates=quality_gates,
|
518
|
-
)
|
519
|
-
|
520
|
-
def display_accuracy_report(self, report: CrossValidationReport) -> None:
|
521
|
-
"""Display accuracy report with Rich CLI formatting."""
|
522
|
-
# Create summary table
|
523
|
-
summary_table = Table(title="📊 Numerical Accuracy Validation Report")
|
524
|
-
summary_table.add_column("Metric", style="cyan")
|
525
|
-
summary_table.add_column("Value", style="green")
|
526
|
-
summary_table.add_column("Status", style="bold")
|
527
|
-
|
528
|
-
# Add summary rows
|
529
|
-
summary_table.add_row("Total Validations", str(report.total_validations), "📋")
|
530
|
-
summary_table.add_row("Passed Validations", str(report.passed_validations), "✅")
|
531
|
-
summary_table.add_row(
|
532
|
-
"Failed Validations", str(report.failed_validations), "❌" if report.failed_validations > 0 else "✅"
|
533
|
-
)
|
534
|
-
summary_table.add_row(
|
535
|
-
"Overall Accuracy",
|
536
|
-
f"{report.overall_accuracy:.2f}%",
|
537
|
-
"✅" if report.overall_accuracy >= self.accuracy_level.value else "⚠️",
|
538
|
-
)
|
539
|
-
summary_table.add_row(
|
540
|
-
"Accuracy Level",
|
541
|
-
report.accuracy_level_met.name,
|
542
|
-
"🏆" if report.accuracy_level_met == AccuracyLevel.ENTERPRISE else "📊",
|
543
|
-
)
|
544
|
-
summary_table.add_row(
|
545
|
-
"Execution Time", f"{report.execution_time:.2f}s", "⚡" if report.execution_time < 30 else "⏰"
|
546
|
-
)
|
547
|
-
|
548
|
-
self.console.print(summary_table)
|
549
|
-
|
550
|
-
# Compliance status
|
551
|
-
if report.compliance_status["audit_ready"]:
|
552
|
-
print_success("✅ System meets enterprise audit requirements")
|
553
|
-
elif report.compliance_status["enterprise_grade"]:
|
554
|
-
print_warning("⚠️ Enterprise accuracy achieved, but validation coverage needs improvement")
|
555
|
-
else:
|
556
|
-
print_error("❌ System does not meet enterprise accuracy requirements")
|
557
|
-
|
558
|
-
# Quality gates summary
|
559
|
-
gates_passed = sum(1 for gate_met in report.quality_gates.values() if gate_met)
|
560
|
-
gates_total = len(report.quality_gates)
|
561
|
-
|
562
|
-
if gates_passed == gates_total:
|
563
|
-
print_success(f"✅ All quality gates passed ({gates_passed}/{gates_total})")
|
564
|
-
else:
|
565
|
-
print_warning(f"⚠️ Quality gates: {gates_passed}/{gates_total} passed")
|
566
|
-
|
567
|
-
def export_audit_report(self, report: CrossValidationReport, file_path: str) -> None:
|
568
|
-
"""Export comprehensive audit report for compliance review."""
|
569
|
-
audit_data = {
|
570
|
-
"report_metadata": {
|
571
|
-
"report_type": "numerical_accuracy_cross_validation",
|
572
|
-
"accuracy_level_required": self.accuracy_level.name,
|
573
|
-
"tolerance_threshold": self.tolerance_percent,
|
574
|
-
"report_timestamp": report.report_timestamp,
|
575
|
-
"execution_time": report.execution_time,
|
576
|
-
},
|
577
|
-
"summary_metrics": {
|
578
|
-
"total_validations": report.total_validations,
|
579
|
-
"passed_validations": report.passed_validations,
|
580
|
-
"failed_validations": report.failed_validations,
|
581
|
-
"overall_accuracy": report.overall_accuracy,
|
582
|
-
"accuracy_level_achieved": report.accuracy_level_met.name,
|
583
|
-
},
|
584
|
-
"compliance_assessment": report.compliance_status,
|
585
|
-
"quality_gates": report.quality_gates,
|
586
|
-
"detailed_validation_results": [
|
587
|
-
{
|
588
|
-
"description": r.description,
|
589
|
-
"calculated_value": r.calculated_value,
|
590
|
-
"reference_value": r.reference_value,
|
591
|
-
"accuracy_percent": r.accuracy_percent,
|
592
|
-
"absolute_difference": r.absolute_difference,
|
593
|
-
"tolerance_met": r.tolerance_met,
|
594
|
-
"validation_status": r.validation_status.value,
|
595
|
-
"source": r.source,
|
596
|
-
"timestamp": r.timestamp,
|
597
|
-
"metadata": r.metadata,
|
598
|
-
}
|
599
|
-
for r in report.validation_results
|
600
|
-
],
|
601
|
-
}
|
602
|
-
|
603
|
-
with open(file_path, "w") as f:
|
604
|
-
json.dump(audit_data, f, indent=2, default=str)
|
605
|
-
|
606
|
-
def start_validation_session(self) -> None:
|
607
|
-
"""Start validation session timing."""
|
608
|
-
self.validation_start_time = time.time()
|
609
|
-
self.validation_results.clear()
|
610
|
-
self.validation_counts = {status: 0 for status in ValidationStatus}
|
611
|
-
|
612
|
-
|
613
|
-
# Convenience functions for integration
|
614
|
-
def create_accuracy_validator(
|
615
|
-
accuracy_level: AccuracyLevel = AccuracyLevel.ENTERPRISE, tolerance_percent: float = 0.01
|
616
|
-
) -> AccuracyCrossValidator:
|
617
|
-
"""Factory function to create accuracy cross-validator."""
|
618
|
-
return AccuracyCrossValidator(accuracy_level=accuracy_level, tolerance_percent=tolerance_percent)
|
619
|
-
|
620
|
-
|
621
|
-
async def validate_finops_data_accuracy(
|
622
|
-
runbooks_data: Dict[str, Any], aws_profiles: List[str], accuracy_level: AccuracyLevel = AccuracyLevel.ENTERPRISE
|
623
|
-
) -> CrossValidationReport:
|
624
|
-
"""
|
625
|
-
Comprehensive FinOps data accuracy validation.
|
626
|
-
|
627
|
-
Args:
|
628
|
-
runbooks_data: Data from runbooks FinOps analysis
|
629
|
-
aws_profiles: AWS profiles for cross-validation
|
630
|
-
accuracy_level: Required accuracy level
|
631
|
-
|
632
|
-
Returns:
|
633
|
-
Complete validation report
|
634
|
-
"""
|
635
|
-
validator = create_accuracy_validator(accuracy_level=accuracy_level)
|
636
|
-
validator.start_validation_session()
|
637
|
-
|
638
|
-
# Perform cross-validation with AWS APIs
|
639
|
-
cross_validation_results = await validator.cross_validate_with_aws_api(runbooks_data, aws_profiles)
|
640
|
-
|
641
|
-
# Generate comprehensive report
|
642
|
-
report = validator.generate_accuracy_report()
|
643
|
-
|
644
|
-
# Display results
|
645
|
-
validator.display_accuracy_report(report)
|
646
|
-
|
647
|
-
return report
|