kailash 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. kailash/__init__.py +33 -1
  2. kailash/access_control/__init__.py +129 -0
  3. kailash/access_control/managers.py +461 -0
  4. kailash/access_control/rule_evaluators.py +467 -0
  5. kailash/access_control_abac.py +825 -0
  6. kailash/config/__init__.py +27 -0
  7. kailash/config/database_config.py +359 -0
  8. kailash/database/__init__.py +28 -0
  9. kailash/database/execution_pipeline.py +499 -0
  10. kailash/middleware/__init__.py +306 -0
  11. kailash/middleware/auth/__init__.py +33 -0
  12. kailash/middleware/auth/access_control.py +436 -0
  13. kailash/middleware/auth/auth_manager.py +422 -0
  14. kailash/middleware/auth/jwt_auth.py +477 -0
  15. kailash/middleware/auth/kailash_jwt_auth.py +616 -0
  16. kailash/middleware/communication/__init__.py +37 -0
  17. kailash/middleware/communication/ai_chat.py +989 -0
  18. kailash/middleware/communication/api_gateway.py +802 -0
  19. kailash/middleware/communication/events.py +470 -0
  20. kailash/middleware/communication/realtime.py +710 -0
  21. kailash/middleware/core/__init__.py +21 -0
  22. kailash/middleware/core/agent_ui.py +890 -0
  23. kailash/middleware/core/schema.py +643 -0
  24. kailash/middleware/core/workflows.py +396 -0
  25. kailash/middleware/database/__init__.py +63 -0
  26. kailash/middleware/database/base.py +113 -0
  27. kailash/middleware/database/base_models.py +525 -0
  28. kailash/middleware/database/enums.py +106 -0
  29. kailash/middleware/database/migrations.py +12 -0
  30. kailash/{api/database.py → middleware/database/models.py} +183 -291
  31. kailash/middleware/database/repositories.py +685 -0
  32. kailash/middleware/database/session_manager.py +19 -0
  33. kailash/middleware/mcp/__init__.py +38 -0
  34. kailash/middleware/mcp/client_integration.py +585 -0
  35. kailash/middleware/mcp/enhanced_server.py +576 -0
  36. kailash/nodes/__init__.py +25 -3
  37. kailash/nodes/admin/__init__.py +35 -0
  38. kailash/nodes/admin/audit_log.py +794 -0
  39. kailash/nodes/admin/permission_check.py +864 -0
  40. kailash/nodes/admin/role_management.py +823 -0
  41. kailash/nodes/admin/security_event.py +1519 -0
  42. kailash/nodes/admin/user_management.py +944 -0
  43. kailash/nodes/ai/a2a.py +24 -7
  44. kailash/nodes/ai/ai_providers.py +1 -0
  45. kailash/nodes/ai/embedding_generator.py +11 -11
  46. kailash/nodes/ai/intelligent_agent_orchestrator.py +99 -11
  47. kailash/nodes/ai/llm_agent.py +407 -2
  48. kailash/nodes/ai/self_organizing.py +85 -10
  49. kailash/nodes/api/auth.py +287 -6
  50. kailash/nodes/api/rest.py +151 -0
  51. kailash/nodes/auth/__init__.py +17 -0
  52. kailash/nodes/auth/directory_integration.py +1228 -0
  53. kailash/nodes/auth/enterprise_auth_provider.py +1328 -0
  54. kailash/nodes/auth/mfa.py +2338 -0
  55. kailash/nodes/auth/risk_assessment.py +872 -0
  56. kailash/nodes/auth/session_management.py +1093 -0
  57. kailash/nodes/auth/sso.py +1040 -0
  58. kailash/nodes/base.py +344 -13
  59. kailash/nodes/base_cycle_aware.py +4 -2
  60. kailash/nodes/base_with_acl.py +1 -1
  61. kailash/nodes/code/python.py +293 -12
  62. kailash/nodes/compliance/__init__.py +9 -0
  63. kailash/nodes/compliance/data_retention.py +1888 -0
  64. kailash/nodes/compliance/gdpr.py +2004 -0
  65. kailash/nodes/data/__init__.py +22 -2
  66. kailash/nodes/data/async_connection.py +469 -0
  67. kailash/nodes/data/async_sql.py +757 -0
  68. kailash/nodes/data/async_vector.py +598 -0
  69. kailash/nodes/data/readers.py +767 -0
  70. kailash/nodes/data/retrieval.py +360 -1
  71. kailash/nodes/data/sharepoint_graph.py +397 -21
  72. kailash/nodes/data/sql.py +94 -5
  73. kailash/nodes/data/streaming.py +68 -8
  74. kailash/nodes/data/vector_db.py +54 -4
  75. kailash/nodes/enterprise/__init__.py +13 -0
  76. kailash/nodes/enterprise/batch_processor.py +741 -0
  77. kailash/nodes/enterprise/data_lineage.py +497 -0
  78. kailash/nodes/logic/convergence.py +31 -9
  79. kailash/nodes/logic/operations.py +14 -3
  80. kailash/nodes/mixins/__init__.py +8 -0
  81. kailash/nodes/mixins/event_emitter.py +201 -0
  82. kailash/nodes/mixins/mcp.py +9 -4
  83. kailash/nodes/mixins/security.py +165 -0
  84. kailash/nodes/monitoring/__init__.py +7 -0
  85. kailash/nodes/monitoring/performance_benchmark.py +2497 -0
  86. kailash/nodes/rag/__init__.py +284 -0
  87. kailash/nodes/rag/advanced.py +1615 -0
  88. kailash/nodes/rag/agentic.py +773 -0
  89. kailash/nodes/rag/conversational.py +999 -0
  90. kailash/nodes/rag/evaluation.py +875 -0
  91. kailash/nodes/rag/federated.py +1188 -0
  92. kailash/nodes/rag/graph.py +721 -0
  93. kailash/nodes/rag/multimodal.py +671 -0
  94. kailash/nodes/rag/optimized.py +933 -0
  95. kailash/nodes/rag/privacy.py +1059 -0
  96. kailash/nodes/rag/query_processing.py +1335 -0
  97. kailash/nodes/rag/realtime.py +764 -0
  98. kailash/nodes/rag/registry.py +547 -0
  99. kailash/nodes/rag/router.py +837 -0
  100. kailash/nodes/rag/similarity.py +1854 -0
  101. kailash/nodes/rag/strategies.py +566 -0
  102. kailash/nodes/rag/workflows.py +575 -0
  103. kailash/nodes/security/__init__.py +19 -0
  104. kailash/nodes/security/abac_evaluator.py +1411 -0
  105. kailash/nodes/security/audit_log.py +91 -0
  106. kailash/nodes/security/behavior_analysis.py +1893 -0
  107. kailash/nodes/security/credential_manager.py +401 -0
  108. kailash/nodes/security/rotating_credentials.py +760 -0
  109. kailash/nodes/security/security_event.py +132 -0
  110. kailash/nodes/security/threat_detection.py +1103 -0
  111. kailash/nodes/testing/__init__.py +9 -0
  112. kailash/nodes/testing/credential_testing.py +499 -0
  113. kailash/nodes/transform/__init__.py +10 -2
  114. kailash/nodes/transform/chunkers.py +592 -1
  115. kailash/nodes/transform/processors.py +484 -14
  116. kailash/nodes/validation.py +321 -0
  117. kailash/runtime/access_controlled.py +1 -1
  118. kailash/runtime/async_local.py +41 -7
  119. kailash/runtime/docker.py +1 -1
  120. kailash/runtime/local.py +474 -55
  121. kailash/runtime/parallel.py +1 -1
  122. kailash/runtime/parallel_cyclic.py +1 -1
  123. kailash/runtime/testing.py +210 -2
  124. kailash/utils/migrations/__init__.py +25 -0
  125. kailash/utils/migrations/generator.py +433 -0
  126. kailash/utils/migrations/models.py +231 -0
  127. kailash/utils/migrations/runner.py +489 -0
  128. kailash/utils/secure_logging.py +342 -0
  129. kailash/workflow/__init__.py +16 -0
  130. kailash/workflow/cyclic_runner.py +3 -4
  131. kailash/workflow/graph.py +70 -2
  132. kailash/workflow/resilience.py +249 -0
  133. kailash/workflow/templates.py +726 -0
  134. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/METADATA +253 -20
  135. kailash-0.4.0.dist-info/RECORD +223 -0
  136. kailash/api/__init__.py +0 -17
  137. kailash/api/__main__.py +0 -6
  138. kailash/api/studio_secure.py +0 -893
  139. kailash/mcp/__main__.py +0 -13
  140. kailash/mcp/server_new.py +0 -336
  141. kailash/mcp/servers/__init__.py +0 -12
  142. kailash-0.3.1.dist-info/RECORD +0 -136
  143. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/WHEEL +0 -0
  144. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/entry_points.txt +0 -0
  145. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/licenses/LICENSE +0 -0
  146. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,9 @@
1
+ """Testing nodes for the Kailash SDK.
2
+
3
+ This module provides specialized nodes for testing workflows, including
4
+ credential testing, mock data generation, and scenario simulation.
5
+ """
6
+
7
+ from .credential_testing import CredentialTestingNode
8
+
9
+ __all__ = ["CredentialTestingNode"]
@@ -0,0 +1,499 @@
1
+ """Credential testing node for workflow authentication testing.
2
+
3
+ This module provides a specialized node for testing credential flows in workflows,
4
+ including mock credential generation, validation simulation, and error scenarios.
5
+ """
6
+
7
+ import base64
8
+ import time
9
+ from datetime import datetime, timedelta, timezone
10
+ from typing import Any
11
+ from uuid import uuid4
12
+
13
+ from kailash.nodes.base import Node, NodeParameter, register_node
14
+ from kailash.sdk_exceptions import NodeExecutionError, NodeValidationError
15
+
16
+
17
+ @register_node()
18
+ class CredentialTestingNode(Node):
19
+ """Node for testing credential flows in workflows.
20
+
21
+ This node simulates various credential scenarios for testing authentication
22
+ workflows without requiring actual external services. It can generate mock
23
+ credentials, simulate validation, test expiration scenarios, and inject
24
+ various error conditions.
25
+
26
+ Design Purpose:
27
+ - Enable comprehensive testing of authentication flows
28
+ - Simulate various credential types and scenarios
29
+ - Test error handling and edge cases
30
+ - Validate security patterns in workflows
31
+
32
+ Use Cases:
33
+ - Unit testing authentication workflows
34
+ - Integration testing with mock services
35
+ - Security pattern validation
36
+ - Error scenario testing
37
+ - Token lifecycle simulation
38
+
39
+ Example:
40
+ >>> # Test OAuth2 token expiration
41
+ >>> tester = CredentialTestingNode()
42
+ >>> result = tester.run(
43
+ ... credential_type='oauth2',
44
+ ... scenario='expired',
45
+ ... mock_data={'client_id': 'test_client'}
46
+ ... )
47
+ >>> assert result['expired'] is True
48
+ >>> assert 'expired_token' in result['error_details']
49
+ >>>
50
+ >>> # Test successful API key validation
51
+ >>> result = tester.run(
52
+ ... credential_type='api_key',
53
+ ... scenario='success',
54
+ ... validation_rules={'key_length': 32}
55
+ ... )
56
+ >>> assert result['valid'] is True
57
+ >>> assert len(result['credentials']['api_key']) == 32
58
+ """
59
+
60
+ def get_parameters(self) -> dict[str, NodeParameter]:
61
+ """Define the parameters this node accepts.
62
+
63
+ Returns:
64
+ Dictionary of parameter definitions
65
+ """
66
+ return {
67
+ "credential_type": NodeParameter(
68
+ name="credential_type",
69
+ type=str,
70
+ required=True,
71
+ description="Type of credential to test: oauth2, api_key, basic, jwt",
72
+ ),
73
+ "scenario": NodeParameter(
74
+ name="scenario",
75
+ type=str,
76
+ required=True,
77
+ default="success",
78
+ description="Test scenario: success, expired, invalid, network_error, rate_limit",
79
+ ),
80
+ "mock_data": NodeParameter(
81
+ name="mock_data",
82
+ type=dict,
83
+ required=False,
84
+ default={},
85
+ description="Custom mock data for the test scenario",
86
+ ),
87
+ "validation_rules": NodeParameter(
88
+ name="validation_rules",
89
+ type=dict,
90
+ required=False,
91
+ default={},
92
+ description="Rules to validate generated credentials",
93
+ ),
94
+ "delay_ms": NodeParameter(
95
+ name="delay_ms",
96
+ type=int,
97
+ required=False,
98
+ default=0,
99
+ description="Simulated network delay in milliseconds",
100
+ ),
101
+ "ttl_seconds": NodeParameter(
102
+ name="ttl_seconds",
103
+ type=int,
104
+ required=False,
105
+ default=3600,
106
+ description="Time-to-live for generated credentials in seconds",
107
+ ),
108
+ }
109
+
110
+ def get_output_schema(self) -> dict[str, NodeParameter]:
111
+ """Define the output schema for this node.
112
+
113
+ Returns:
114
+ Dictionary of output parameter definitions
115
+ """
116
+ return {
117
+ "valid": NodeParameter(
118
+ name="valid",
119
+ type=bool,
120
+ required=True,
121
+ description="Whether the credential validation succeeded",
122
+ ),
123
+ "credentials": NodeParameter(
124
+ name="credentials",
125
+ type=dict,
126
+ required=False,
127
+ description="Generated mock credentials (if successful)",
128
+ ),
129
+ "headers": NodeParameter(
130
+ name="headers",
131
+ type=dict,
132
+ required=False,
133
+ description="HTTP headers for the credentials (if applicable)",
134
+ ),
135
+ "expires_at": NodeParameter(
136
+ name="expires_at",
137
+ type=str,
138
+ required=False,
139
+ description="ISO format expiration timestamp",
140
+ ),
141
+ "expired": NodeParameter(
142
+ name="expired",
143
+ type=bool,
144
+ required=False,
145
+ description="Whether the credentials are expired",
146
+ ),
147
+ "error": NodeParameter(
148
+ name="error",
149
+ type=str,
150
+ required=False,
151
+ description="Error message if validation failed",
152
+ ),
153
+ "error_details": NodeParameter(
154
+ name="error_details",
155
+ type=dict,
156
+ required=False,
157
+ description="Detailed error information",
158
+ ),
159
+ "metadata": NodeParameter(
160
+ name="metadata",
161
+ type=dict,
162
+ required=True,
163
+ description="Test metadata including scenario details",
164
+ ),
165
+ }
166
+
167
+ def run(self, **kwargs) -> dict[str, Any]:
168
+ """Execute credential testing based on the specified scenario.
169
+
170
+ Args:
171
+ credential_type: Type of credential to test
172
+ scenario: Test scenario to simulate
173
+ mock_data: Custom mock data
174
+ validation_rules: Validation rules to apply
175
+ delay_ms: Simulated network delay
176
+ ttl_seconds: Credential time-to-live
177
+
178
+ Returns:
179
+ Dictionary containing test results and generated credentials
180
+
181
+ Raises:
182
+ NodeValidationError: If parameters are invalid
183
+ NodeExecutionError: If simulating execution errors
184
+ """
185
+ credential_type = kwargs.get("credential_type")
186
+ scenario = kwargs.get("scenario", "success")
187
+ mock_data = kwargs.get("mock_data", {})
188
+ validation_rules = kwargs.get("validation_rules", {})
189
+ delay_ms = kwargs.get("delay_ms", 0)
190
+ ttl_seconds = kwargs.get("ttl_seconds", 3600)
191
+
192
+ # Validate credential type
193
+ valid_types = ["oauth2", "api_key", "basic", "jwt"]
194
+ if credential_type not in valid_types:
195
+ raise NodeValidationError(
196
+ f"Invalid credential_type: {credential_type}. Must be one of: {valid_types}"
197
+ )
198
+
199
+ # Simulate network delay
200
+ if delay_ms > 0:
201
+ time.sleep(delay_ms / 1000.0)
202
+
203
+ # Handle different scenarios
204
+ if scenario == "network_error":
205
+ raise NodeExecutionError("Simulated network error: Connection timeout")
206
+
207
+ elif scenario == "rate_limit":
208
+ return {
209
+ "valid": False,
210
+ "error": "Rate limit exceeded",
211
+ "error_details": {
212
+ "error_code": "RATE_LIMIT_EXCEEDED",
213
+ "retry_after": 60,
214
+ "limit": 100,
215
+ "remaining": 0,
216
+ },
217
+ "metadata": {
218
+ "scenario": scenario,
219
+ "credential_type": credential_type,
220
+ "timestamp": datetime.now(timezone.utc).isoformat(),
221
+ },
222
+ }
223
+
224
+ # Generate credentials based on type
225
+ if credential_type == "oauth2":
226
+ result = self._generate_oauth2_credentials(
227
+ scenario, mock_data, validation_rules, ttl_seconds
228
+ )
229
+ elif credential_type == "api_key":
230
+ result = self._generate_api_key_credentials(
231
+ scenario, mock_data, validation_rules, ttl_seconds
232
+ )
233
+ elif credential_type == "basic":
234
+ result = self._generate_basic_credentials(
235
+ scenario, mock_data, validation_rules, ttl_seconds
236
+ )
237
+ elif credential_type == "jwt":
238
+ result = self._generate_jwt_credentials(
239
+ scenario, mock_data, validation_rules, ttl_seconds
240
+ )
241
+
242
+ # Add common metadata
243
+ result["metadata"] = {
244
+ "scenario": scenario,
245
+ "credential_type": credential_type,
246
+ "timestamp": datetime.now(timezone.utc).isoformat(),
247
+ "test_id": str(uuid4()),
248
+ }
249
+
250
+ return result
251
+
252
+ def _generate_oauth2_credentials(
253
+ self, scenario: str, mock_data: dict, validation_rules: dict, ttl_seconds: int
254
+ ) -> dict[str, Any]:
255
+ """Generate OAuth2 mock credentials."""
256
+ now = datetime.now(timezone.utc)
257
+
258
+ if scenario == "expired":
259
+ # Generate expired token
260
+ expires_at = now - timedelta(hours=1)
261
+ return {
262
+ "valid": False,
263
+ "expired": True,
264
+ "error": "Token expired",
265
+ "error_details": {
266
+ "error_code": "expired_token",
267
+ "expired_at": expires_at.isoformat(),
268
+ },
269
+ "expires_at": expires_at.isoformat(),
270
+ }
271
+
272
+ elif scenario == "invalid":
273
+ return {
274
+ "valid": False,
275
+ "error": "Invalid client credentials",
276
+ "error_details": {
277
+ "error_code": "invalid_client",
278
+ "error_description": "Client authentication failed",
279
+ },
280
+ }
281
+
282
+ else: # success scenario
283
+ expires_at = now + timedelta(seconds=ttl_seconds)
284
+ access_token = f"mock_access_{uuid4().hex[:16]}"
285
+ refresh_token = f"mock_refresh_{uuid4().hex[:16]}"
286
+
287
+ credentials = {
288
+ "access_token": access_token,
289
+ "token_type": "Bearer",
290
+ "expires_in": ttl_seconds,
291
+ "refresh_token": refresh_token,
292
+ "scope": mock_data.get("scope", "read write"),
293
+ }
294
+
295
+ # Apply custom mock data
296
+ credentials.update(mock_data)
297
+
298
+ # Validate if rules provided
299
+ if validation_rules:
300
+ valid, error = self._validate_oauth2(credentials, validation_rules)
301
+ if not valid:
302
+ return {
303
+ "valid": False,
304
+ "error": error,
305
+ "error_details": {"validation_failed": True},
306
+ }
307
+
308
+ return {
309
+ "valid": True,
310
+ "credentials": credentials,
311
+ "headers": {"Authorization": f"Bearer {access_token}"},
312
+ "expires_at": expires_at.isoformat(),
313
+ "expired": False,
314
+ }
315
+
316
+ def _generate_api_key_credentials(
317
+ self, scenario: str, mock_data: dict, validation_rules: dict, ttl_seconds: int
318
+ ) -> dict[str, Any]:
319
+ """Generate API key mock credentials."""
320
+ if scenario == "invalid":
321
+ return {
322
+ "valid": False,
323
+ "error": "Invalid API key",
324
+ "error_details": {
325
+ "error_code": "invalid_api_key",
326
+ "status_code": 401,
327
+ },
328
+ }
329
+
330
+ else: # success or expired scenario
331
+ key_length = validation_rules.get("key_length", 32)
332
+ api_key = f"sk_test_{uuid4().hex[:key_length]}"
333
+
334
+ credentials = {
335
+ "api_key": api_key,
336
+ "key_prefix": mock_data.get("key_prefix", "sk_test"),
337
+ }
338
+
339
+ # Apply custom mock data
340
+ credentials.update(mock_data)
341
+
342
+ header_name = validation_rules.get("header_name", "X-API-Key")
343
+
344
+ if scenario == "expired":
345
+ return {
346
+ "valid": False,
347
+ "expired": True,
348
+ "error": "API key expired",
349
+ "error_details": {
350
+ "error_code": "expired_api_key",
351
+ "key_id": api_key[:12] + "...",
352
+ },
353
+ "credentials": credentials,
354
+ }
355
+
356
+ return {
357
+ "valid": True,
358
+ "credentials": credentials,
359
+ "headers": {header_name: api_key},
360
+ "expired": False,
361
+ }
362
+
363
+ def _generate_basic_credentials(
364
+ self, scenario: str, mock_data: dict, validation_rules: dict, ttl_seconds: int
365
+ ) -> dict[str, Any]:
366
+ """Generate Basic Auth mock credentials."""
367
+ username = mock_data.get("username", "test_user")
368
+ password = mock_data.get("password", "test_pass123")
369
+
370
+ if scenario == "invalid":
371
+ return {
372
+ "valid": False,
373
+ "error": "Invalid username or password",
374
+ "error_details": {
375
+ "error_code": "invalid_credentials",
376
+ "status_code": 401,
377
+ },
378
+ }
379
+
380
+ else: # success scenario
381
+ credentials = {
382
+ "username": username,
383
+ "password": password,
384
+ }
385
+
386
+ # Generate Basic Auth header
387
+ auth_string = f"{username}:{password}"
388
+ encoded_auth = base64.b64encode(auth_string.encode()).decode()
389
+
390
+ return {
391
+ "valid": True,
392
+ "credentials": credentials,
393
+ "headers": {"Authorization": f"Basic {encoded_auth}"},
394
+ "expired": False,
395
+ }
396
+
397
+ def _generate_jwt_credentials(
398
+ self, scenario: str, mock_data: dict, validation_rules: dict, ttl_seconds: int
399
+ ) -> dict[str, Any]:
400
+ """Generate JWT mock credentials."""
401
+ now = datetime.now(timezone.utc)
402
+
403
+ # Mock JWT structure (not cryptographically valid)
404
+ header = {"alg": "HS256", "typ": "JWT"}
405
+
406
+ if scenario == "expired":
407
+ payload = {
408
+ "sub": mock_data.get("subject", "1234567890"),
409
+ "name": mock_data.get("name", "Test User"),
410
+ "iat": int((now - timedelta(hours=2)).timestamp()),
411
+ "exp": int((now - timedelta(hours=1)).timestamp()),
412
+ }
413
+
414
+ return {
415
+ "valid": False,
416
+ "expired": True,
417
+ "error": "JWT token expired",
418
+ "error_details": {
419
+ "error_code": "jwt_expired",
420
+ "expired_at": datetime.fromtimestamp(
421
+ payload["exp"], tz=timezone.utc
422
+ ).isoformat(),
423
+ },
424
+ }
425
+
426
+ elif scenario == "invalid":
427
+ return {
428
+ "valid": False,
429
+ "error": "Invalid JWT signature",
430
+ "error_details": {
431
+ "error_code": "invalid_signature",
432
+ "status_code": 401,
433
+ },
434
+ }
435
+
436
+ else: # success scenario
437
+ expires_at = now + timedelta(seconds=ttl_seconds)
438
+ payload = {
439
+ "sub": mock_data.get("subject", "1234567890"),
440
+ "name": mock_data.get("name", "Test User"),
441
+ "iat": int(now.timestamp()),
442
+ "exp": int(expires_at.timestamp()),
443
+ "iss": mock_data.get("issuer", "test_issuer"),
444
+ "aud": mock_data.get("audience", "test_audience"),
445
+ }
446
+
447
+ # Apply additional claims from mock_data
448
+ for key, value in mock_data.items():
449
+ if key not in payload:
450
+ payload[key] = value
451
+
452
+ # Create mock JWT (base64 encoded parts separated by dots)
453
+ header_b64 = (
454
+ base64.urlsafe_b64encode(str(header).encode()).decode().rstrip("=")
455
+ )
456
+ payload_b64 = (
457
+ base64.urlsafe_b64encode(str(payload).encode()).decode().rstrip("=")
458
+ )
459
+ signature = uuid4().hex[:32]
460
+
461
+ jwt_token = f"{header_b64}.{payload_b64}.{signature}"
462
+
463
+ credentials = {
464
+ "jwt": jwt_token,
465
+ "header": header,
466
+ "payload": payload,
467
+ }
468
+
469
+ return {
470
+ "valid": True,
471
+ "credentials": credentials,
472
+ "headers": {"Authorization": f"Bearer {jwt_token}"},
473
+ "expires_at": expires_at.isoformat(),
474
+ "expired": False,
475
+ }
476
+
477
+ def _validate_oauth2(self, credentials: dict, rules: dict) -> tuple[bool, str]:
478
+ """Validate OAuth2 credentials against rules."""
479
+ # Check required fields
480
+ required_fields = rules.get("required_fields", ["access_token", "token_type"])
481
+ for field in required_fields:
482
+ if field not in credentials:
483
+ return False, f"Missing required field: {field}"
484
+
485
+ # Check token format
486
+ if "token_format" in rules:
487
+ token = credentials.get("access_token", "")
488
+ if not token.startswith(rules["token_format"]):
489
+ return False, "Invalid token format"
490
+
491
+ # Check scope requirements
492
+ if "required_scopes" in rules:
493
+ granted_scopes = set(credentials.get("scope", "").split())
494
+ required_scopes = set(rules["required_scopes"])
495
+ if not required_scopes.issubset(granted_scopes):
496
+ missing = required_scopes - granted_scopes
497
+ return False, f"Missing required scopes: {missing}"
498
+
499
+ return True, ""
@@ -1,12 +1,17 @@
1
1
  """Transform processing nodes for the Kailash SDK."""
2
2
 
3
- from kailash.nodes.transform.chunkers import HierarchicalChunkerNode
3
+ from kailash.nodes.transform.chunkers import (
4
+ HierarchicalChunkerNode,
5
+ SemanticChunkerNode,
6
+ StatisticalChunkerNode,
7
+ )
4
8
  from kailash.nodes.transform.formatters import (
5
9
  ChunkTextExtractorNode,
6
10
  ContextFormatterNode,
7
11
  QueryTextWrapperNode,
8
12
  )
9
13
  from kailash.nodes.transform.processors import (
14
+ ContextualCompressorNode,
10
15
  DataTransformer,
11
16
  Filter,
12
17
  FilterNode,
@@ -15,12 +20,15 @@ from kailash.nodes.transform.processors import (
15
20
  )
16
21
 
17
22
  __all__ = [
23
+ "ContextualCompressorNode",
24
+ "DataTransformer",
18
25
  "Filter",
19
26
  "FilterNode",
20
27
  "Map",
21
28
  "Sort",
22
- "DataTransformer",
23
29
  "HierarchicalChunkerNode",
30
+ "SemanticChunkerNode",
31
+ "StatisticalChunkerNode",
24
32
  "ChunkTextExtractorNode",
25
33
  "QueryTextWrapperNode",
26
34
  "ContextFormatterNode",