kailash 0.8.4__py3-none-any.whl → 0.8.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.
- kailash/__init__.py +1 -7
- kailash/cli/__init__.py +11 -1
- kailash/cli/validation_audit.py +570 -0
- kailash/core/actors/supervisor.py +1 -1
- kailash/core/resilience/circuit_breaker.py +71 -1
- kailash/core/resilience/health_monitor.py +172 -0
- kailash/edge/compliance.py +33 -0
- kailash/edge/consistency.py +609 -0
- kailash/edge/coordination/__init__.py +30 -0
- kailash/edge/coordination/global_ordering.py +355 -0
- kailash/edge/coordination/leader_election.py +217 -0
- kailash/edge/coordination/partition_detector.py +296 -0
- kailash/edge/coordination/raft.py +485 -0
- kailash/edge/discovery.py +63 -1
- kailash/edge/migration/__init__.py +19 -0
- kailash/edge/migration/edge_migrator.py +832 -0
- kailash/edge/monitoring/__init__.py +21 -0
- kailash/edge/monitoring/edge_monitor.py +736 -0
- kailash/edge/prediction/__init__.py +10 -0
- kailash/edge/prediction/predictive_warmer.py +591 -0
- kailash/edge/resource/__init__.py +102 -0
- kailash/edge/resource/cloud_integration.py +796 -0
- kailash/edge/resource/cost_optimizer.py +949 -0
- kailash/edge/resource/docker_integration.py +919 -0
- kailash/edge/resource/kubernetes_integration.py +893 -0
- kailash/edge/resource/platform_integration.py +913 -0
- kailash/edge/resource/predictive_scaler.py +959 -0
- kailash/edge/resource/resource_analyzer.py +824 -0
- kailash/edge/resource/resource_pools.py +610 -0
- kailash/integrations/dataflow_edge.py +261 -0
- kailash/mcp_server/registry_integration.py +1 -1
- kailash/monitoring/__init__.py +18 -0
- kailash/monitoring/alerts.py +646 -0
- kailash/monitoring/metrics.py +677 -0
- kailash/nodes/__init__.py +2 -0
- kailash/nodes/ai/semantic_memory.py +2 -2
- kailash/nodes/base.py +545 -0
- kailash/nodes/edge/__init__.py +36 -0
- kailash/nodes/edge/base.py +240 -0
- kailash/nodes/edge/cloud_node.py +710 -0
- kailash/nodes/edge/coordination.py +239 -0
- kailash/nodes/edge/docker_node.py +825 -0
- kailash/nodes/edge/edge_data.py +582 -0
- kailash/nodes/edge/edge_migration_node.py +392 -0
- kailash/nodes/edge/edge_monitoring_node.py +421 -0
- kailash/nodes/edge/edge_state.py +673 -0
- kailash/nodes/edge/edge_warming_node.py +393 -0
- kailash/nodes/edge/kubernetes_node.py +652 -0
- kailash/nodes/edge/platform_node.py +766 -0
- kailash/nodes/edge/resource_analyzer_node.py +378 -0
- kailash/nodes/edge/resource_optimizer_node.py +501 -0
- kailash/nodes/edge/resource_scaler_node.py +397 -0
- kailash/nodes/ports.py +676 -0
- kailash/runtime/local.py +344 -1
- kailash/runtime/validation/__init__.py +20 -0
- kailash/runtime/validation/connection_context.py +119 -0
- kailash/runtime/validation/enhanced_error_formatter.py +202 -0
- kailash/runtime/validation/error_categorizer.py +164 -0
- kailash/runtime/validation/metrics.py +380 -0
- kailash/runtime/validation/performance.py +615 -0
- kailash/runtime/validation/suggestion_engine.py +212 -0
- kailash/testing/fixtures.py +2 -2
- kailash/workflow/builder.py +230 -4
- kailash/workflow/contracts.py +418 -0
- kailash/workflow/edge_infrastructure.py +369 -0
- kailash/workflow/migration.py +3 -3
- kailash/workflow/type_inference.py +669 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/METADATA +43 -27
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/RECORD +73 -27
- kailash/nexus/__init__.py +0 -21
- kailash/nexus/cli/__init__.py +0 -5
- kailash/nexus/cli/__main__.py +0 -6
- kailash/nexus/cli/main.py +0 -176
- kailash/nexus/factory.py +0 -413
- kailash/nexus/gateway.py +0 -545
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
"""
|
2
|
+
Enhanced error message formatting for connection validation errors.
|
3
|
+
|
4
|
+
Formats validation errors into structured, readable messages with
|
5
|
+
connection paths, categorization, suggestions, and examples.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import Optional
|
9
|
+
|
10
|
+
from .connection_context import ConnectionContext
|
11
|
+
from .error_categorizer import ErrorCategorizer, ErrorCategory
|
12
|
+
from .suggestion_engine import ValidationSuggestion
|
13
|
+
|
14
|
+
|
15
|
+
class EnhancedErrorFormatter:
|
16
|
+
"""Formats validation errors into enhanced, actionable error messages."""
|
17
|
+
|
18
|
+
def __init__(self):
|
19
|
+
self.categorizer = ErrorCategorizer()
|
20
|
+
|
21
|
+
def format_enhanced_error(
|
22
|
+
self,
|
23
|
+
original_error: str,
|
24
|
+
error_category: ErrorCategory,
|
25
|
+
connection_context: ConnectionContext,
|
26
|
+
suggestion: Optional[ValidationSuggestion] = None,
|
27
|
+
) -> str:
|
28
|
+
"""Format a comprehensive error message with all enhancement details.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
original_error: Original validation error message
|
32
|
+
error_category: Categorized error type
|
33
|
+
connection_context: Context about the failing connection
|
34
|
+
suggestion: Optional actionable suggestion
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
Formatted error message with structured sections
|
38
|
+
"""
|
39
|
+
sections = []
|
40
|
+
|
41
|
+
# Header with error category
|
42
|
+
category_desc = self.categorizer.get_category_description(error_category)
|
43
|
+
severity = self.categorizer.get_severity_level(error_category)
|
44
|
+
|
45
|
+
sections.append(f"🚨 Connection Validation Error: {category_desc} [{severity}]")
|
46
|
+
sections.append("=" * 60)
|
47
|
+
|
48
|
+
# Problem section
|
49
|
+
sections.append("\n📋 Problem:")
|
50
|
+
sections.append(f" {original_error}")
|
51
|
+
|
52
|
+
# Connection path section
|
53
|
+
sections.append("\n🔗 Connection:")
|
54
|
+
connection_path = connection_context.get_connection_path()
|
55
|
+
sections.append(f" {connection_path}")
|
56
|
+
|
57
|
+
# Parameter details (sanitized)
|
58
|
+
if not connection_context.is_security_sensitive():
|
59
|
+
value_repr = connection_context.get_sanitized_value()
|
60
|
+
sections.append(f" Value: {value_repr}")
|
61
|
+
else:
|
62
|
+
sections.append(" Value: **REDACTED** (security-sensitive)")
|
63
|
+
|
64
|
+
sections.append(f" Validation Mode: {connection_context.validation_mode}")
|
65
|
+
|
66
|
+
# Suggestion section
|
67
|
+
if suggestion:
|
68
|
+
sections.append("\n💡 Suggestion:")
|
69
|
+
sections.append(f" {suggestion.message}")
|
70
|
+
|
71
|
+
# Code example
|
72
|
+
if suggestion.code_example:
|
73
|
+
sections.append("\n📝 Example:")
|
74
|
+
example_lines = suggestion.code_example.split("\n")
|
75
|
+
for line in example_lines:
|
76
|
+
sections.append(f" {line}")
|
77
|
+
|
78
|
+
# Alternative approaches
|
79
|
+
if suggestion.alternative_approaches:
|
80
|
+
sections.append("\n🔄 Alternatives:")
|
81
|
+
for i, alt in enumerate(suggestion.alternative_approaches, 1):
|
82
|
+
sections.append(f" {i}. {alt}")
|
83
|
+
|
84
|
+
# Documentation link
|
85
|
+
if suggestion.documentation_link:
|
86
|
+
sections.append("\n📚 Documentation:")
|
87
|
+
sections.append(f" {suggestion.documentation_link}")
|
88
|
+
else:
|
89
|
+
sections.append("\n💡 Suggestion:")
|
90
|
+
sections.append(" Check node documentation for parameter requirements.")
|
91
|
+
sections.append(" Verify data types and connection mapping.")
|
92
|
+
|
93
|
+
# Troubleshooting tips
|
94
|
+
sections.append("\n🛠️ Quick Troubleshooting:")
|
95
|
+
sections.append(" 1. Check the source node output format")
|
96
|
+
sections.append(" 2. Verify target node parameter requirements")
|
97
|
+
sections.append(" 3. Test with simplified data first")
|
98
|
+
sections.append(
|
99
|
+
" 4. Review connection syntax: workflow.add_connection(source, source_port, target, target_port)"
|
100
|
+
)
|
101
|
+
|
102
|
+
return "\n".join(sections)
|
103
|
+
|
104
|
+
def format_simple_error(
|
105
|
+
self, original_error: str, connection_context: ConnectionContext
|
106
|
+
) -> str:
|
107
|
+
"""Format a simple enhanced error message for warn mode.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
original_error: Original validation error message
|
111
|
+
connection_context: Context about the failing connection
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
Simple formatted error message
|
115
|
+
"""
|
116
|
+
connection_path = connection_context.get_connection_path()
|
117
|
+
return f"Connection validation warning: {connection_path} - {original_error}"
|
118
|
+
|
119
|
+
def format_security_error(
|
120
|
+
self,
|
121
|
+
original_error: str,
|
122
|
+
connection_context: ConnectionContext,
|
123
|
+
suggestion: Optional[ValidationSuggestion] = None,
|
124
|
+
) -> str:
|
125
|
+
"""Format security-specific error message with appropriate warnings.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
original_error: Original security error message
|
129
|
+
connection_context: Context about the failing connection
|
130
|
+
suggestion: Optional security-specific suggestion
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
Security-focused error message
|
134
|
+
"""
|
135
|
+
sections = []
|
136
|
+
|
137
|
+
sections.append("🔒 SECURITY ALERT: Potential Security Vulnerability")
|
138
|
+
sections.append("=" * 60)
|
139
|
+
|
140
|
+
sections.append("\n⚠️ Security Issue:")
|
141
|
+
sections.append(f" {original_error}")
|
142
|
+
|
143
|
+
sections.append("\n🔗 Affected Connection:")
|
144
|
+
connection_path = connection_context.get_connection_path()
|
145
|
+
sections.append(f" {connection_path}")
|
146
|
+
|
147
|
+
# Always redact security-sensitive values
|
148
|
+
sections.append(" Value: **REDACTED** (potential security risk)")
|
149
|
+
|
150
|
+
if suggestion:
|
151
|
+
sections.append("\n🛡️ Security Recommendation:")
|
152
|
+
sections.append(f" {suggestion.message}")
|
153
|
+
|
154
|
+
if suggestion.code_example:
|
155
|
+
sections.append("\n🔐 Secure Example:")
|
156
|
+
example_lines = suggestion.code_example.split("\n")
|
157
|
+
for line in example_lines:
|
158
|
+
sections.append(f" {line}")
|
159
|
+
|
160
|
+
sections.append("\n🚨 Immediate Actions:")
|
161
|
+
sections.append(" 1. Review the data source for potential attacks")
|
162
|
+
sections.append(" 2. Implement input validation and sanitization")
|
163
|
+
sections.append(" 3. Use parameterized queries for database operations")
|
164
|
+
sections.append(" 4. Consider implementing rate limiting")
|
165
|
+
|
166
|
+
sections.append("\n📋 Security Checklist:")
|
167
|
+
sections.append(" □ Input validation implemented")
|
168
|
+
sections.append(" □ Output encoding applied")
|
169
|
+
sections.append(" □ Parameterized queries used")
|
170
|
+
sections.append(" □ Access controls verified")
|
171
|
+
|
172
|
+
return "\n".join(sections)
|
173
|
+
|
174
|
+
def get_error_summary(
|
175
|
+
self, error_category: ErrorCategory, connection_context: ConnectionContext
|
176
|
+
) -> str:
|
177
|
+
"""Get a brief summary of the error for logging.
|
178
|
+
|
179
|
+
Args:
|
180
|
+
error_category: Categorized error type
|
181
|
+
connection_context: Context about the failing connection
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
Brief error summary
|
185
|
+
"""
|
186
|
+
category_desc = self.categorizer.get_category_description(error_category)
|
187
|
+
connection_path = connection_context.get_connection_path()
|
188
|
+
|
189
|
+
return f"{category_desc}: {connection_path}"
|
190
|
+
|
191
|
+
def _indent_lines(self, text: str, indent: str = " ") -> str:
|
192
|
+
"""Indent all lines in text with the given prefix.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
text: Text to indent
|
196
|
+
indent: Indentation string
|
197
|
+
|
198
|
+
Returns:
|
199
|
+
Indented text
|
200
|
+
"""
|
201
|
+
lines = text.split("\n")
|
202
|
+
return "\n".join(f"{indent}{line}" for line in lines)
|
@@ -0,0 +1,164 @@
|
|
1
|
+
"""
|
2
|
+
Error categorization for connection validation failures.
|
3
|
+
|
4
|
+
Classifies validation errors into specific categories to enable
|
5
|
+
targeted suggestion generation and better error handling.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import re
|
9
|
+
from enum import Enum
|
10
|
+
from typing import Any, Optional
|
11
|
+
|
12
|
+
|
13
|
+
class ErrorCategory(Enum):
|
14
|
+
"""Categories of connection validation errors."""
|
15
|
+
|
16
|
+
TYPE_MISMATCH = "type_mismatch"
|
17
|
+
"""Parameter type doesn't match expected type"""
|
18
|
+
|
19
|
+
MISSING_PARAMETER = "missing_parameter"
|
20
|
+
"""Required parameter is missing or None"""
|
21
|
+
|
22
|
+
CONSTRAINT_VIOLATION = "constraint_violation"
|
23
|
+
"""Parameter violates validation constraints (range, format, etc.)"""
|
24
|
+
|
25
|
+
SECURITY_VIOLATION = "security_violation"
|
26
|
+
"""Parameter contains potential security issues (injection, etc.)"""
|
27
|
+
|
28
|
+
UNKNOWN = "unknown"
|
29
|
+
"""Error category could not be determined"""
|
30
|
+
|
31
|
+
|
32
|
+
class ErrorCategorizer:
|
33
|
+
"""Categorizes validation errors for enhanced error message generation."""
|
34
|
+
|
35
|
+
# Error patterns for categorization
|
36
|
+
TYPE_ERROR_PATTERNS = [
|
37
|
+
r"expected .+ but got .+",
|
38
|
+
r"object of type .+ has no attribute",
|
39
|
+
r"unsupported operand type",
|
40
|
+
r"can't convert .+ to .+",
|
41
|
+
r"'[^']+' object .+ not .+",
|
42
|
+
r"argument must be .+, not .+",
|
43
|
+
]
|
44
|
+
|
45
|
+
MISSING_PARAMETER_PATTERNS = [
|
46
|
+
r"missing required parameter",
|
47
|
+
r"required argument .+ is missing",
|
48
|
+
r"takes .+ arguments but .+ were given",
|
49
|
+
r"missing .+ required",
|
50
|
+
r"parameter .+ is required",
|
51
|
+
]
|
52
|
+
|
53
|
+
CONSTRAINT_VIOLATION_PATTERNS = [
|
54
|
+
r"must be positive",
|
55
|
+
r"must be greater than",
|
56
|
+
r"must be less than",
|
57
|
+
r"invalid value",
|
58
|
+
r"out of range",
|
59
|
+
r"violates constraint",
|
60
|
+
r"exceeds maximum",
|
61
|
+
r"below minimum",
|
62
|
+
]
|
63
|
+
|
64
|
+
SECURITY_VIOLATION_PATTERNS = [
|
65
|
+
r"sql injection",
|
66
|
+
r"injection detected",
|
67
|
+
r"security violation",
|
68
|
+
r"potential attack",
|
69
|
+
r"malicious",
|
70
|
+
r"dangerous",
|
71
|
+
r"unsafe",
|
72
|
+
r"script injection",
|
73
|
+
]
|
74
|
+
|
75
|
+
def categorize_error(
|
76
|
+
self, error: Exception, node_type: Optional[str] = None
|
77
|
+
) -> ErrorCategory:
|
78
|
+
"""Categorize a validation error based on error message and context.
|
79
|
+
|
80
|
+
Args:
|
81
|
+
error: The validation error exception
|
82
|
+
node_type: Optional node type for additional context
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
ErrorCategory enum value indicating the error type
|
86
|
+
"""
|
87
|
+
error_message = str(error).lower()
|
88
|
+
error_type = type(error).__name__
|
89
|
+
|
90
|
+
# Check for security violations first (highest priority)
|
91
|
+
if self._matches_patterns(error_message, self.SECURITY_VIOLATION_PATTERNS):
|
92
|
+
return ErrorCategory.SECURITY_VIOLATION
|
93
|
+
|
94
|
+
# Check for type errors
|
95
|
+
if error_type in ["TypeError", "AttributeError"] or self._matches_patterns(
|
96
|
+
error_message, self.TYPE_ERROR_PATTERNS
|
97
|
+
):
|
98
|
+
return ErrorCategory.TYPE_MISMATCH
|
99
|
+
|
100
|
+
# Check for missing parameter errors
|
101
|
+
if error_type in ["ValueError", "TypeError"] and self._matches_patterns(
|
102
|
+
error_message, self.MISSING_PARAMETER_PATTERNS
|
103
|
+
):
|
104
|
+
return ErrorCategory.MISSING_PARAMETER
|
105
|
+
|
106
|
+
# Check for constraint violations
|
107
|
+
if error_type == "ValueError" and self._matches_patterns(
|
108
|
+
error_message, self.CONSTRAINT_VIOLATION_PATTERNS
|
109
|
+
):
|
110
|
+
return ErrorCategory.CONSTRAINT_VIOLATION
|
111
|
+
|
112
|
+
# Default to unknown if no pattern matches
|
113
|
+
return ErrorCategory.UNKNOWN
|
114
|
+
|
115
|
+
def _matches_patterns(self, text: str, patterns: list[str]) -> bool:
|
116
|
+
"""Check if text matches any of the given regex patterns.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
text: Text to check
|
120
|
+
patterns: List of regex patterns
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
True if text matches any pattern
|
124
|
+
"""
|
125
|
+
for pattern in patterns:
|
126
|
+
if re.search(pattern, text, re.IGNORECASE):
|
127
|
+
return True
|
128
|
+
return False
|
129
|
+
|
130
|
+
def get_category_description(self, category: ErrorCategory) -> str:
|
131
|
+
"""Get human-readable description of error category.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
category: Error category enum
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
Human-readable description
|
138
|
+
"""
|
139
|
+
descriptions = {
|
140
|
+
ErrorCategory.TYPE_MISMATCH: "Type Mismatch",
|
141
|
+
ErrorCategory.MISSING_PARAMETER: "Missing Required Parameter",
|
142
|
+
ErrorCategory.CONSTRAINT_VIOLATION: "Parameter Constraint Violation",
|
143
|
+
ErrorCategory.SECURITY_VIOLATION: "Security Violation",
|
144
|
+
ErrorCategory.UNKNOWN: "Unknown Validation Error",
|
145
|
+
}
|
146
|
+
return descriptions.get(category, "Unknown Error")
|
147
|
+
|
148
|
+
def get_severity_level(self, category: ErrorCategory) -> str:
|
149
|
+
"""Get severity level for error category.
|
150
|
+
|
151
|
+
Args:
|
152
|
+
category: Error category enum
|
153
|
+
|
154
|
+
Returns:
|
155
|
+
Severity level: 'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'
|
156
|
+
"""
|
157
|
+
severity_map = {
|
158
|
+
ErrorCategory.SECURITY_VIOLATION: "CRITICAL",
|
159
|
+
ErrorCategory.MISSING_PARAMETER: "HIGH",
|
160
|
+
ErrorCategory.TYPE_MISMATCH: "MEDIUM",
|
161
|
+
ErrorCategory.CONSTRAINT_VIOLATION: "MEDIUM",
|
162
|
+
ErrorCategory.UNKNOWN: "LOW",
|
163
|
+
}
|
164
|
+
return severity_map.get(category, "LOW")
|