zexus 1.6.2

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 (227) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +2513 -0
  3. package/bin/zexus +2 -0
  4. package/bin/zpics +2 -0
  5. package/bin/zpm +2 -0
  6. package/bin/zx +2 -0
  7. package/bin/zx-deploy +2 -0
  8. package/bin/zx-dev +2 -0
  9. package/bin/zx-run +2 -0
  10. package/package.json +66 -0
  11. package/scripts/README.md +24 -0
  12. package/scripts/postinstall.js +44 -0
  13. package/shared_config.json +24 -0
  14. package/src/README.md +1525 -0
  15. package/src/tests/run_zexus_tests.py +117 -0
  16. package/src/tests/test_all_phases.zx +346 -0
  17. package/src/tests/test_blockchain_features.zx +306 -0
  18. package/src/tests/test_complexity_features.zx +321 -0
  19. package/src/tests/test_core_integration.py +185 -0
  20. package/src/tests/test_phase10_ecosystem.zx +177 -0
  21. package/src/tests/test_phase1_modifiers.zx +87 -0
  22. package/src/tests/test_phase2_plugins.zx +80 -0
  23. package/src/tests/test_phase3_security.zx +97 -0
  24. package/src/tests/test_phase4_vfs.zx +116 -0
  25. package/src/tests/test_phase5_types.zx +117 -0
  26. package/src/tests/test_phase6_metaprogramming.zx +125 -0
  27. package/src/tests/test_phase7_optimization.zx +132 -0
  28. package/src/tests/test_phase9_advanced_types.zx +157 -0
  29. package/src/tests/test_security_features.py +419 -0
  30. package/src/tests/test_security_features.zx +276 -0
  31. package/src/tests/test_simple_zx.zx +1 -0
  32. package/src/tests/test_verification_simple.zx +69 -0
  33. package/src/zexus/__init__.py +28 -0
  34. package/src/zexus/__main__.py +5 -0
  35. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  36. package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
  37. package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
  38. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  39. package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
  40. package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
  41. package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
  42. package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
  43. package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
  44. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  45. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  46. package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
  47. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  48. package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
  49. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  50. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  51. package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
  52. package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
  53. package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
  54. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  55. package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
  56. package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
  57. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  58. package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
  59. package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
  60. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  61. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  62. package/src/zexus/advanced_types.py +401 -0
  63. package/src/zexus/blockchain/__init__.py +40 -0
  64. package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
  65. package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
  66. package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
  67. package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
  68. package/src/zexus/blockchain/crypto.py +463 -0
  69. package/src/zexus/blockchain/ledger.py +255 -0
  70. package/src/zexus/blockchain/transaction.py +267 -0
  71. package/src/zexus/builtin_modules.py +284 -0
  72. package/src/zexus/builtin_plugins.py +317 -0
  73. package/src/zexus/capability_system.py +372 -0
  74. package/src/zexus/cli/__init__.py +2 -0
  75. package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
  76. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  77. package/src/zexus/cli/main.py +707 -0
  78. package/src/zexus/cli/zpm.py +203 -0
  79. package/src/zexus/compare_interpreter_compiler.py +146 -0
  80. package/src/zexus/compiler/__init__.py +169 -0
  81. package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
  82. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  83. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  84. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  85. package/src/zexus/compiler/bytecode.py +266 -0
  86. package/src/zexus/compiler/compat_runtime.py +277 -0
  87. package/src/zexus/compiler/lexer.py +257 -0
  88. package/src/zexus/compiler/parser.py +779 -0
  89. package/src/zexus/compiler/semantic.py +118 -0
  90. package/src/zexus/compiler/zexus_ast.py +454 -0
  91. package/src/zexus/complexity_system.py +575 -0
  92. package/src/zexus/concurrency_system.py +493 -0
  93. package/src/zexus/config.py +201 -0
  94. package/src/zexus/crypto_bridge.py +19 -0
  95. package/src/zexus/dependency_injection.py +423 -0
  96. package/src/zexus/ecosystem.py +434 -0
  97. package/src/zexus/environment.py +101 -0
  98. package/src/zexus/environment_manager.py +119 -0
  99. package/src/zexus/error_reporter.py +314 -0
  100. package/src/zexus/evaluator/__init__.py +12 -0
  101. package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  103. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  104. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  105. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  106. package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
  107. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  108. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  109. package/src/zexus/evaluator/bytecode_compiler.py +700 -0
  110. package/src/zexus/evaluator/core.py +891 -0
  111. package/src/zexus/evaluator/expressions.py +827 -0
  112. package/src/zexus/evaluator/functions.py +3989 -0
  113. package/src/zexus/evaluator/integration.py +396 -0
  114. package/src/zexus/evaluator/statements.py +4303 -0
  115. package/src/zexus/evaluator/utils.py +126 -0
  116. package/src/zexus/evaluator_original.py +2041 -0
  117. package/src/zexus/external_bridge.py +16 -0
  118. package/src/zexus/find_affected_imports.sh +155 -0
  119. package/src/zexus/hybrid_orchestrator.py +152 -0
  120. package/src/zexus/input_validation.py +259 -0
  121. package/src/zexus/lexer.py +571 -0
  122. package/src/zexus/logging.py +89 -0
  123. package/src/zexus/lsp/__init__.py +9 -0
  124. package/src/zexus/lsp/completion_provider.py +207 -0
  125. package/src/zexus/lsp/definition_provider.py +22 -0
  126. package/src/zexus/lsp/hover_provider.py +71 -0
  127. package/src/zexus/lsp/server.py +269 -0
  128. package/src/zexus/lsp/symbol_provider.py +31 -0
  129. package/src/zexus/metaprogramming.py +321 -0
  130. package/src/zexus/module_cache.py +89 -0
  131. package/src/zexus/module_manager.py +107 -0
  132. package/src/zexus/object.py +973 -0
  133. package/src/zexus/optimization.py +424 -0
  134. package/src/zexus/parser/__init__.py +31 -0
  135. package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
  136. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  137. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  138. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  139. package/src/zexus/parser/integration.py +86 -0
  140. package/src/zexus/parser/parser.py +3977 -0
  141. package/src/zexus/parser/strategy_context.py +7254 -0
  142. package/src/zexus/parser/strategy_structural.py +1033 -0
  143. package/src/zexus/persistence.py +391 -0
  144. package/src/zexus/plugin_system.py +290 -0
  145. package/src/zexus/policy_engine.py +365 -0
  146. package/src/zexus/profiler/__init__.py +5 -0
  147. package/src/zexus/profiler/profiler.py +233 -0
  148. package/src/zexus/purity_system.py +398 -0
  149. package/src/zexus/runtime/__init__.py +20 -0
  150. package/src/zexus/runtime/async_runtime.py +324 -0
  151. package/src/zexus/search_old_imports.sh +65 -0
  152. package/src/zexus/security.py +1407 -0
  153. package/src/zexus/stack_trace.py +233 -0
  154. package/src/zexus/stdlib/__init__.py +27 -0
  155. package/src/zexus/stdlib/blockchain.py +341 -0
  156. package/src/zexus/stdlib/compression.py +167 -0
  157. package/src/zexus/stdlib/crypto.py +124 -0
  158. package/src/zexus/stdlib/datetime.py +163 -0
  159. package/src/zexus/stdlib/db_mongo.py +199 -0
  160. package/src/zexus/stdlib/db_mysql.py +162 -0
  161. package/src/zexus/stdlib/db_postgres.py +163 -0
  162. package/src/zexus/stdlib/db_sqlite.py +133 -0
  163. package/src/zexus/stdlib/encoding.py +230 -0
  164. package/src/zexus/stdlib/fs.py +195 -0
  165. package/src/zexus/stdlib/http.py +219 -0
  166. package/src/zexus/stdlib/http_server.py +248 -0
  167. package/src/zexus/stdlib/json_module.py +61 -0
  168. package/src/zexus/stdlib/math.py +360 -0
  169. package/src/zexus/stdlib/os_module.py +265 -0
  170. package/src/zexus/stdlib/regex.py +148 -0
  171. package/src/zexus/stdlib/sockets.py +253 -0
  172. package/src/zexus/stdlib/test_framework.zx +208 -0
  173. package/src/zexus/stdlib/test_runner.zx +119 -0
  174. package/src/zexus/stdlib_integration.py +341 -0
  175. package/src/zexus/strategy_recovery.py +256 -0
  176. package/src/zexus/syntax_validator.py +356 -0
  177. package/src/zexus/testing/zpics.py +407 -0
  178. package/src/zexus/testing/zpics_runtime.py +369 -0
  179. package/src/zexus/type_system.py +374 -0
  180. package/src/zexus/validation_system.py +569 -0
  181. package/src/zexus/virtual_filesystem.py +355 -0
  182. package/src/zexus/vm/__init__.py +8 -0
  183. package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
  184. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  185. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  186. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  187. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  188. package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
  189. package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
  190. package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
  191. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  192. package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
  193. package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
  194. package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
  195. package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
  196. package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
  197. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  198. package/src/zexus/vm/async_optimizer.py +420 -0
  199. package/src/zexus/vm/bytecode.py +428 -0
  200. package/src/zexus/vm/bytecode_converter.py +297 -0
  201. package/src/zexus/vm/cache.py +532 -0
  202. package/src/zexus/vm/jit.py +720 -0
  203. package/src/zexus/vm/memory_manager.py +520 -0
  204. package/src/zexus/vm/memory_pool.py +511 -0
  205. package/src/zexus/vm/optimizer.py +478 -0
  206. package/src/zexus/vm/parallel_vm.py +899 -0
  207. package/src/zexus/vm/peephole_optimizer.py +452 -0
  208. package/src/zexus/vm/profiler.py +527 -0
  209. package/src/zexus/vm/register_allocator.py +462 -0
  210. package/src/zexus/vm/register_vm.py +520 -0
  211. package/src/zexus/vm/ssa_converter.py +757 -0
  212. package/src/zexus/vm/vm.py +1392 -0
  213. package/src/zexus/zexus_ast.py +1782 -0
  214. package/src/zexus/zexus_token.py +253 -0
  215. package/src/zexus/zpm/__init__.py +15 -0
  216. package/src/zexus/zpm/installer.py +116 -0
  217. package/src/zexus/zpm/package_manager.py +208 -0
  218. package/src/zexus/zpm/publisher.py +98 -0
  219. package/src/zexus/zpm/registry.py +110 -0
  220. package/src/zexus.egg-info/PKG-INFO +2235 -0
  221. package/src/zexus.egg-info/SOURCES.txt +876 -0
  222. package/src/zexus.egg-info/dependency_links.txt +1 -0
  223. package/src/zexus.egg-info/entry_points.txt +3 -0
  224. package/src/zexus.egg-info/not-zip-safe +1 -0
  225. package/src/zexus.egg-info/requires.txt +14 -0
  226. package/src/zexus.egg-info/top_level.txt +2 -0
  227. package/zexus.json +14 -0
@@ -0,0 +1,569 @@
1
+ """
2
+ Data Validation & Sanitization System for Zexus.
3
+
4
+ Provides built-in validation and sanitization primitives to prevent
5
+ common security vulnerabilities like injection attacks, type mismatches,
6
+ and malformed input.
7
+
8
+ Key Features:
9
+ - Schema validation (JSON-like schemas with type checking)
10
+ - Input sanitization (remove/escape dangerous characters)
11
+ - Common validators (email, URL, phone, IP, range, length)
12
+ - Custom validator registration
13
+ - Encoding-aware sanitization (HTML, SQL, JavaScript, URL)
14
+ """
15
+
16
+ from typing import Any, Dict, List, Optional, Callable, Pattern, Union
17
+ import re
18
+ import json
19
+ import html
20
+ import urllib.parse
21
+ from abc import ABC, abstractmethod
22
+ from enum import Enum
23
+
24
+
25
+ class ValidationError(Exception):
26
+ """Exception raised when validation fails."""
27
+ def __init__(self, message: str, field: str = "", value: Any = None):
28
+ self.message = message
29
+ self.field = field
30
+ self.value = value
31
+ super().__init__(f"Validation error in '{field}': {message}")
32
+
33
+
34
+ class SanitizationError(Exception):
35
+ """Exception raised when sanitization fails."""
36
+ pass
37
+
38
+
39
+ class Encoding(Enum):
40
+ """Common encoding types for sanitization."""
41
+ HTML = "html" # HTML entity encoding
42
+ URL = "url" # URL percent encoding
43
+ SQL = "sql" # SQL escape sequences
44
+ JAVASCRIPT = "javascript" # JavaScript string escaping
45
+ CSV = "csv" # CSV field escaping
46
+ NONE = "none" # No encoding
47
+
48
+
49
+ class Validator(ABC):
50
+ """Base class for custom validators."""
51
+
52
+ @abstractmethod
53
+ def validate(self, value: Any) -> bool:
54
+ """Return True if valid, False otherwise."""
55
+ pass
56
+
57
+ @abstractmethod
58
+ def get_error_message(self) -> str:
59
+ """Return human-readable error message."""
60
+ pass
61
+
62
+
63
+ class RegexValidator(Validator):
64
+ """Validate against a regex pattern."""
65
+
66
+ def __init__(self, pattern: Union[str, Pattern], message: str = ""):
67
+ self.pattern = pattern if isinstance(pattern, Pattern) else re.compile(pattern)
68
+ self.message = message or f"Value does not match pattern: {pattern}"
69
+
70
+ def validate(self, value: Any) -> bool:
71
+ if not isinstance(value, str):
72
+ return False
73
+ return self.pattern.match(str(value)) is not None
74
+
75
+ def get_error_message(self) -> str:
76
+ return self.message
77
+
78
+
79
+ class RangeValidator(Validator):
80
+ """Validate numeric ranges."""
81
+
82
+ def __init__(self, min_val: Optional[float] = None,
83
+ max_val: Optional[float] = None):
84
+ self.min_val = min_val
85
+ self.max_val = max_val
86
+
87
+ def validate(self, value: Any) -> bool:
88
+ try:
89
+ num = float(value)
90
+ if self.min_val is not None and num < self.min_val:
91
+ return False
92
+ if self.max_val is not None and num > self.max_val:
93
+ return False
94
+ return True
95
+ except (TypeError, ValueError):
96
+ return False
97
+
98
+ def get_error_message(self) -> str:
99
+ if self.min_val is not None and self.max_val is not None:
100
+ return f"Value must be between {self.min_val} and {self.max_val}"
101
+ elif self.min_val is not None:
102
+ return f"Value must be >= {self.min_val}"
103
+ elif self.max_val is not None:
104
+ return f"Value must be <= {self.max_val}"
105
+ return "Invalid range"
106
+
107
+
108
+ class LengthValidator(Validator):
109
+ """Validate string/list length."""
110
+
111
+ def __init__(self, min_len: Optional[int] = None,
112
+ max_len: Optional[int] = None):
113
+ self.min_len = min_len
114
+ self.max_len = max_len
115
+
116
+ def validate(self, value: Any) -> bool:
117
+ try:
118
+ length = len(value)
119
+ if self.min_len is not None and length < self.min_len:
120
+ return False
121
+ if self.max_len is not None and length > self.max_len:
122
+ return False
123
+ return True
124
+ except (TypeError, AttributeError):
125
+ return False
126
+
127
+ def get_error_message(self) -> str:
128
+ if self.min_len is not None and self.max_len is not None:
129
+ return f"Length must be between {self.min_len} and {self.max_len}"
130
+ elif self.min_len is not None:
131
+ return f"Length must be >= {self.min_len}"
132
+ elif self.max_len is not None:
133
+ return f"Length must be <= {self.max_len}"
134
+ return "Invalid length"
135
+
136
+
137
+ class ChoiceValidator(Validator):
138
+ """Validate against allowed choices."""
139
+
140
+ def __init__(self, choices: List[Any]):
141
+ self.choices = set(choices)
142
+
143
+ def validate(self, value: Any) -> bool:
144
+ return value in self.choices
145
+
146
+ def get_error_message(self) -> str:
147
+ return f"Value must be one of: {self.choices}"
148
+
149
+
150
+ class TypeValidator(Validator):
151
+ """Validate type."""
152
+
153
+ def __init__(self, expected_type: Union[type, tuple]):
154
+ self.expected_type = expected_type
155
+
156
+ def validate(self, value: Any) -> bool:
157
+ return isinstance(value, self.expected_type)
158
+
159
+ def get_error_message(self) -> str:
160
+ return f"Value must be of type {self.expected_type}"
161
+
162
+
163
+ class CompositeValidator(Validator):
164
+ """Combine multiple validators (all must pass)."""
165
+
166
+ def __init__(self, validators: List[Validator]):
167
+ self.validators = validators
168
+
169
+ def validate(self, value: Any) -> bool:
170
+ return all(v.validate(value) for v in self.validators)
171
+
172
+ def get_error_message(self) -> str:
173
+ return " AND ".join(v.get_error_message() for v in self.validators)
174
+
175
+
176
+ class ValidationSchema:
177
+ """Define validation rules for data structures."""
178
+
179
+ def __init__(self, rules: Dict[str, Union[Validator, type, List[Validator]]]):
180
+ """
181
+ Initialize schema with validation rules.
182
+
183
+ Args:
184
+ rules: Dict mapping field names to validators or types
185
+ - str value: check isinstance(value, str)
186
+ - Validator instance: use custom validator
187
+ - List[Validator]: use CompositeValidator
188
+ """
189
+ self.rules: Dict[str, Validator] = {}
190
+
191
+ for field, rule in rules.items():
192
+ if isinstance(rule, Validator):
193
+ self.rules[field] = rule
194
+ elif isinstance(rule, type):
195
+ self.rules[field] = TypeValidator(rule)
196
+ elif isinstance(rule, list):
197
+ self.rules[field] = CompositeValidator(rule)
198
+ else:
199
+ raise ValueError(f"Invalid rule for field {field}: {rule}")
200
+
201
+ def validate(self, data: Dict[str, Any]) -> bool:
202
+ """Validate data against schema."""
203
+ for field, validator in self.rules.items():
204
+ if field not in data:
205
+ raise ValidationError(f"Missing required field: {field}", field)
206
+
207
+ value = data[field]
208
+ if not validator.validate(value):
209
+ raise ValidationError(
210
+ validator.get_error_message(),
211
+ field,
212
+ value
213
+ )
214
+
215
+ return True
216
+
217
+ def validate_partial(self, data: Dict[str, Any],
218
+ required_fields: Optional[List[str]] = None) -> bool:
219
+ """Validate only specified fields (partial validation)."""
220
+ fields_to_check = required_fields or list(self.rules.keys())
221
+
222
+ for field in fields_to_check:
223
+ if field not in self.rules:
224
+ continue
225
+
226
+ if field not in data:
227
+ raise ValidationError(f"Missing required field: {field}", field)
228
+
229
+ value = data[field]
230
+ validator = self.rules[field]
231
+ if not validator.validate(value):
232
+ raise ValidationError(
233
+ validator.get_error_message(),
234
+ field,
235
+ value
236
+ )
237
+
238
+ return True
239
+
240
+
241
+ class StandardValidators:
242
+ """Collection of standard, reusable validators."""
243
+
244
+ # Email validation
245
+ EMAIL = RegexValidator(
246
+ r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
247
+ "Invalid email format"
248
+ )
249
+
250
+ # URL validation
251
+ URL = RegexValidator(
252
+ r'^https?://[^\s/$.?#].[^\s]*$',
253
+ "Invalid URL format"
254
+ )
255
+
256
+ # IPv4 address
257
+ IPV4 = RegexValidator(
258
+ r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$',
259
+ "Invalid IPv4 address"
260
+ )
261
+
262
+ # IPv6 address
263
+ IPV6 = RegexValidator(
264
+ r'^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$',
265
+ "Invalid IPv6 address"
266
+ )
267
+
268
+ # Phone number (basic US format)
269
+ PHONE = RegexValidator(
270
+ r'^(\+?1)?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}$',
271
+ "Invalid phone number"
272
+ )
273
+
274
+ # UUID
275
+ UUID = RegexValidator(
276
+ r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
277
+ "Invalid UUID format"
278
+ )
279
+
280
+ # Alphanumeric only
281
+ ALPHANUMERIC = RegexValidator(
282
+ r'^[a-zA-Z0-9]+$',
283
+ "Must contain only alphanumeric characters"
284
+ )
285
+
286
+ # Positive integer
287
+ POSITIVE_INT = CompositeValidator([
288
+ TypeValidator(int),
289
+ RangeValidator(min_val=0)
290
+ ])
291
+
292
+ # Non-empty string
293
+ NON_EMPTY_STRING = CompositeValidator([
294
+ TypeValidator(str),
295
+ LengthValidator(min_len=1)
296
+ ])
297
+
298
+
299
+ class Sanitizer:
300
+ """Sanitize untrusted input to prevent injection attacks."""
301
+
302
+ # HTML injection patterns
303
+ DANGEROUS_HTML_TAGS = {
304
+ 'script', 'iframe', 'embed', 'object', 'link', 'style', 'meta'
305
+ }
306
+
307
+ DANGEROUS_ATTRIBUTES = {
308
+ 'onclick', 'onload', 'onerror', 'onmouseover', 'onmouseout',
309
+ 'onchange', 'onfocus', 'onblur', 'onfocus', 'onsubmit'
310
+ }
311
+
312
+ # SQL keywords for detection
313
+ SQL_KEYWORDS = {
314
+ 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'UNION',
315
+ 'FROM', 'WHERE', 'OR', 'AND'
316
+ }
317
+
318
+ @staticmethod
319
+ def sanitize_string(value: str, encoding: Encoding = Encoding.HTML) -> str:
320
+ """
321
+ Sanitize a string value.
322
+
323
+ Args:
324
+ value: String to sanitize
325
+ encoding: Type of encoding to apply
326
+
327
+ Returns:
328
+ Sanitized string
329
+ """
330
+ if not isinstance(value, str):
331
+ raise SanitizationError(f"Expected string, got {type(value)}")
332
+
333
+ if encoding == Encoding.HTML:
334
+ return Sanitizer._sanitize_html(value)
335
+ elif encoding == Encoding.URL:
336
+ return urllib.parse.quote(value, safe='')
337
+ elif encoding == Encoding.SQL:
338
+ return Sanitizer._sanitize_sql(value)
339
+ elif encoding == Encoding.JAVASCRIPT:
340
+ return Sanitizer._sanitize_javascript(value)
341
+ elif encoding == Encoding.CSV:
342
+ return Sanitizer._sanitize_csv(value)
343
+ elif encoding == Encoding.NONE:
344
+ return value
345
+ else:
346
+ raise SanitizationError(f"Unknown encoding: {encoding}")
347
+
348
+ @staticmethod
349
+ def _sanitize_html(value: str) -> str:
350
+ """Remove dangerous HTML tags and attributes."""
351
+ # Escape HTML entities
352
+ value = html.escape(value, quote=True)
353
+
354
+ # Additional cleanup for remaining tags
355
+ value = re.sub(r'<script[^>]*>.*?</script>', '', value, flags=re.IGNORECASE)
356
+
357
+ return value
358
+
359
+ @staticmethod
360
+ def _sanitize_sql(value: str) -> str:
361
+ """Escape SQL special characters."""
362
+ # Escape single quotes by doubling them
363
+ return value.replace("'", "''")
364
+
365
+ @staticmethod
366
+ def _sanitize_javascript(value: str) -> str:
367
+ """Escape JavaScript special characters."""
368
+ replacements = {
369
+ '"': '\\"',
370
+ "'": "\\'",
371
+ "\n": "\\n",
372
+ "\r": "\\r",
373
+ "\t": "\\t",
374
+ "\b": "\\b",
375
+ "\f": "\\f"
376
+ }
377
+
378
+ for char, escaped in replacements.items():
379
+ value = value.replace(char, escaped)
380
+
381
+ return value
382
+
383
+ @staticmethod
384
+ def _sanitize_csv(value: str) -> str:
385
+ """Escape CSV field."""
386
+ if '"' in value or ',' in value or '\n' in value:
387
+ value = '"' + value.replace('"', '""') + '"'
388
+ return value
389
+
390
+ @staticmethod
391
+ def sanitize_dict(data: Dict[str, Any],
392
+ encoding: Encoding = Encoding.HTML) -> Dict[str, Any]:
393
+ """Sanitize all string values in a dictionary."""
394
+ result = {}
395
+
396
+ for key, value in data.items():
397
+ if isinstance(value, str):
398
+ result[key] = Sanitizer.sanitize_string(value, encoding)
399
+ elif isinstance(value, dict):
400
+ result[key] = Sanitizer.sanitize_dict(value, encoding)
401
+ elif isinstance(value, list):
402
+ result[key] = Sanitizer.sanitize_list(value, encoding)
403
+ else:
404
+ result[key] = value
405
+
406
+ return result
407
+
408
+ @staticmethod
409
+ def sanitize_list(data: List[Any],
410
+ encoding: Encoding = Encoding.HTML) -> List[Any]:
411
+ """Sanitize all string values in a list."""
412
+ result = []
413
+
414
+ for value in data:
415
+ if isinstance(value, str):
416
+ result.append(Sanitizer.sanitize_string(value, encoding))
417
+ elif isinstance(value, dict):
418
+ result.append(Sanitizer.sanitize_dict(value, encoding))
419
+ elif isinstance(value, list):
420
+ result.append(Sanitizer.sanitize_list(value, encoding))
421
+ else:
422
+ result.append(value)
423
+
424
+ return result
425
+
426
+
427
+ class ValidationManager:
428
+ """
429
+ Central validation/sanitization manager for the interpreter.
430
+
431
+ Provides a unified interface for:
432
+ - Registering custom validators
433
+ - Validating data against schemas
434
+ - Sanitizing untrusted input
435
+ - Tracking validation/sanitization history
436
+ """
437
+
438
+ def __init__(self):
439
+ self.custom_validators: Dict[str, Validator] = {}
440
+ self.schemas: Dict[str, ValidationSchema] = {}
441
+ self.history: List[Dict[str, Any]] = []
442
+
443
+ # Initialize built-in schemas for common types
444
+ self._register_builtin_schemas()
445
+
446
+ def _register_builtin_schemas(self):
447
+ """Register built-in schemas for common data types."""
448
+ # String type schema
449
+ self.register_schema("string", ValidationSchema({
450
+ "_type": TypeValidator(str)
451
+ }))
452
+
453
+ # Integer type schema
454
+ self.register_schema("integer", ValidationSchema({
455
+ "_type": TypeValidator(int)
456
+ }))
457
+
458
+ # Number type schema (int or float)
459
+ self.register_schema("number", ValidationSchema({
460
+ "_type": TypeValidator((int, float))
461
+ }))
462
+
463
+ # Boolean type schema
464
+ self.register_schema("boolean", ValidationSchema({
465
+ "_type": TypeValidator(bool)
466
+ }))
467
+
468
+ # Email schema (uses standard validator)
469
+ self.register_schema("email", ValidationSchema({
470
+ "_value": StandardValidators.EMAIL
471
+ }))
472
+
473
+ # URL schema (uses standard validator)
474
+ self.register_schema("url", ValidationSchema({
475
+ "_value": StandardValidators.URL
476
+ }))
477
+
478
+ # Phone schema (uses standard validator)
479
+ self.register_schema("phone", ValidationSchema({
480
+ "_value": StandardValidators.PHONE
481
+ }))
482
+
483
+ # UUID schema (uses standard validator)
484
+ self.register_schema("uuid", ValidationSchema({
485
+ "_value": StandardValidators.UUID
486
+ }))
487
+
488
+ # IPv4 schema
489
+ self.register_schema("ipv4", ValidationSchema({
490
+ "_value": StandardValidators.IPV4
491
+ }))
492
+
493
+ # IPv6 schema
494
+ self.register_schema("ipv6", ValidationSchema({
495
+ "_value": StandardValidators.IPV6
496
+ }))
497
+
498
+ def register_validator(self, name: str, validator: Validator):
499
+ """Register a custom validator."""
500
+ self.custom_validators[name] = validator
501
+
502
+ def get_validator(self, name: str) -> Optional[Validator]:
503
+ """Get a registered validator by name."""
504
+ return self.custom_validators.get(name)
505
+
506
+ def register_schema(self, name: str, schema: ValidationSchema):
507
+ """Register a validation schema."""
508
+ self.schemas[name] = schema
509
+
510
+ def get_schema(self, name: str) -> Optional[ValidationSchema]:
511
+ """Get a registered schema by name."""
512
+ return self.schemas.get(name)
513
+
514
+ def validate(self, value: Any, validator_name: str) -> bool:
515
+ """Validate a value using a registered validator."""
516
+ validator = self.get_validator(validator_name)
517
+ if not validator:
518
+ raise ValueError(f"Unknown validator: {validator_name}")
519
+
520
+ self._record_validation(validator_name, value, validator.validate(value))
521
+ return validator.validate(value)
522
+
523
+ def validate_schema(self, data: Dict[str, Any], schema_name: str) -> bool:
524
+ """Validate data against a registered schema."""
525
+ schema = self.get_schema(schema_name)
526
+ if not schema:
527
+ raise ValueError(f"Unknown schema: {schema_name}")
528
+
529
+ return schema.validate(data)
530
+
531
+ def sanitize(self, value: str, encoding: Encoding = Encoding.HTML) -> str:
532
+ """Sanitize a string value."""
533
+ result = Sanitizer.sanitize_string(value, encoding)
534
+ self._record_sanitization(value, result, encoding.value)
535
+ return result
536
+
537
+ def _record_validation(self, validator: str, value: Any, result: bool):
538
+ """Record validation operation."""
539
+ self.history.append({
540
+ "type": "validation",
541
+ "validator": validator,
542
+ "value": str(value)[:100], # Truncate long values
543
+ "result": result
544
+ })
545
+
546
+ def _record_sanitization(self, original: str, sanitized: str, encoding: str):
547
+ """Record sanitization operation."""
548
+ self.history.append({
549
+ "type": "sanitization",
550
+ "encoding": encoding,
551
+ "original": original[:50],
552
+ "sanitized": sanitized[:50],
553
+ "length": len(original)
554
+ })
555
+
556
+ def get_history(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
557
+ """Get validation/sanitization history."""
558
+ if limit:
559
+ return self.history[-limit:]
560
+ return self.history.copy()
561
+
562
+
563
+ # Global instance
564
+ _validation_manager = ValidationManager()
565
+
566
+
567
+ def get_validation_manager() -> ValidationManager:
568
+ """Get the global validation manager instance."""
569
+ return _validation_manager