@devilsdev/rag-pipeline-utils 2.2.1 → 2.3.0

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 (40) hide show
  1. package/README.md +244 -11
  2. package/contracts/contract-schema.json +189 -0
  3. package/dist/index.cjs +19 -0
  4. package/dist/index.mjs +15 -1
  5. package/package.json +3 -2
  6. package/src/cli/commands/wizard.js +627 -0
  7. package/src/cli/input-sanitization-middleware.js +356 -0
  8. package/src/cli/templates/development.template.json +64 -0
  9. package/src/cli/templates/minimal.template.json +33 -0
  10. package/src/cli/templates/production.template.json +104 -0
  11. package/src/cli/templates/testing.template.json +45 -0
  12. package/src/config/connection-pool-config.json +259 -0
  13. package/src/config/memory-optimization.js +414 -0
  14. package/src/config/redaction-patterns.json +150 -0
  15. package/src/config/sanitization-rules.json +323 -0
  16. package/src/core/plugin-registry.js +266 -20
  17. package/src/dag/core/error-context.js +391 -0
  18. package/src/dag/core/execution-scheduler.js +350 -0
  19. package/src/dag/core/topology-validation.js +415 -0
  20. package/src/dag/dag-engine.js +26 -424
  21. package/src/dev/README.md +126 -0
  22. package/src/dev/dev-server.js +356 -0
  23. package/src/dev/examples/hot-reload-usage.js +355 -0
  24. package/src/dev/hot-reload.js +807 -0
  25. package/src/enterprise/sso-integration.js +67 -25
  26. package/src/index.js +19 -0
  27. package/src/observability/event-logger.js +62 -2
  28. package/src/plugins/optimized-openai-embedder.js +169 -0
  29. package/src/security/jwt-config.js +431 -0
  30. package/src/security/jwt-validator.js +701 -0
  31. package/src/utils/api-client-pool-integration.js +436 -0
  32. package/src/utils/batch-processor.js +710 -0
  33. package/src/utils/connection-pool.js +605 -0
  34. package/src/utils/contract-validator.js +460 -0
  35. package/src/utils/error-formatter.js +603 -0
  36. package/src/utils/examples/error-formatter-usage.js +351 -0
  37. package/src/utils/input-sanitizer.js +967 -0
  38. package/src/utils/memory-monitor.js +800 -0
  39. package/src/utils/secure-logger-config.js +352 -0
  40. package/src/utils/secure-logger.js +576 -0
@@ -0,0 +1,356 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * CLI Input Sanitization Middleware
5
+ *
6
+ * Provides automatic input sanitization for CLI commands to prevent:
7
+ * - Command injection attacks
8
+ * - Path traversal attacks
9
+ * - XSS in output
10
+ * - Invalid data types
11
+ *
12
+ * @module cli/input-sanitization-middleware
13
+ * @since 2.3.0
14
+ */
15
+
16
+ const {
17
+ InputSanitizer,
18
+ SanitizationRules,
19
+ sanitizePath,
20
+ sanitizeCommand,
21
+ validateEmail,
22
+ validateUrl,
23
+ } = require("../utils/input-sanitizer");
24
+
25
+ /**
26
+ * CLI-specific sanitization rules mapping
27
+ */
28
+ const CLI_SANITIZATION_RULES = {
29
+ // File and path arguments
30
+ file: SanitizationRules.PATH,
31
+ path: SanitizationRules.PATH,
32
+ output: SanitizationRules.PATH,
33
+ input: SanitizationRules.PATH,
34
+ config: SanitizationRules.PATH,
35
+ report: SanitizationRules.PATH,
36
+
37
+ // URL arguments
38
+ url: SanitizationRules.URL,
39
+
40
+ // Email arguments
41
+ email: SanitizationRules.EMAIL,
42
+
43
+ // String arguments (prompts, queries, templates)
44
+ prompt: SanitizationRules.XSS,
45
+ query: SanitizationRules.XSS,
46
+ template: SanitizationRules.ALPHANUMERIC,
47
+
48
+ // Configuration keys
49
+ key: SanitizationRules.ALPHANUMERIC,
50
+ name: SanitizationRules.SLUG,
51
+
52
+ // Numeric arguments
53
+ timeout: SanitizationRules.INTEGER,
54
+ concurrency: SanitizationRules.INTEGER,
55
+ batchSize: SanitizationRules.INTEGER,
56
+ maxMemory: SanitizationRules.INTEGER,
57
+
58
+ // Categories and sections
59
+ category: SanitizationRules.SLUG,
60
+ section: SanitizationRules.SLUG,
61
+ format: SanitizationRules.SLUG,
62
+ };
63
+
64
+ /**
65
+ * CLI Input Sanitization Middleware
66
+ */
67
+ class CLISanitizationMiddleware {
68
+ constructor(options = {}) {
69
+ this.sanitizer = new InputSanitizer({
70
+ enableCache: options.enableCache !== false,
71
+ cacheSize: options.cacheSize || 500,
72
+ cacheTTL: options.cacheTTL || 300000, // 5 minutes
73
+ throwOnInvalid: options.throwOnInvalid || false,
74
+ stripInvalid: options.stripInvalid !== false,
75
+ trackStats: options.trackStats !== false,
76
+ });
77
+
78
+ this.customRules = options.customRules || {};
79
+ this.enabled = options.enabled !== false;
80
+ this.verbose = options.verbose || false;
81
+ }
82
+
83
+ /**
84
+ * Sanitize command arguments
85
+ *
86
+ * @param {Object} args - Command arguments object
87
+ * @returns {Object} Sanitized arguments
88
+ *
89
+ * @example
90
+ * const sanitized = middleware.sanitizeArgs({
91
+ * file: '../../../etc/passwd',
92
+ * query: '<script>alert("xss")</script>',
93
+ * timeout: '1000'
94
+ * });
95
+ */
96
+ sanitizeArgs(args) {
97
+ if (!this.enabled) {
98
+ return args;
99
+ }
100
+
101
+ if (!args || typeof args !== "object") {
102
+ return args;
103
+ }
104
+
105
+ const sanitized = {};
106
+
107
+ for (const [key, value] of Object.entries(args)) {
108
+ // Skip undefined/null values
109
+ if (value === undefined || value === null) {
110
+ sanitized[key] = value;
111
+ continue;
112
+ }
113
+
114
+ // Determine sanitization rule for this argument
115
+ const rule = this._getRuleForArgument(key, value);
116
+
117
+ // Sanitize the value
118
+ try {
119
+ sanitized[key] = this.sanitizer.sanitize(value, rule);
120
+
121
+ // Log if value was modified (in verbose mode)
122
+ if (this.verbose && sanitized[key] !== value) {
123
+ console.warn(
124
+ `[INPUT_SANITIZER] Sanitized argument '${key}': ${value} => ${sanitized[key]}`,
125
+ );
126
+ }
127
+ } catch (error) {
128
+ console.error(
129
+ `[INPUT_SANITIZER] Error sanitizing argument '${key}':`,
130
+ error.message,
131
+ );
132
+ sanitized[key] = value; // Fall back to original value
133
+ }
134
+ }
135
+
136
+ return sanitized;
137
+ }
138
+
139
+ /**
140
+ * Sanitize command options
141
+ *
142
+ * @param {Object} options - Command options object
143
+ * @returns {Object} Sanitized options
144
+ */
145
+ sanitizeOptions(options) {
146
+ return this.sanitizeArgs(options);
147
+ }
148
+
149
+ /**
150
+ * Sanitize command output before displaying
151
+ *
152
+ * @param {string} output - Command output string
153
+ * @returns {string} Sanitized output
154
+ */
155
+ sanitizeOutput(output) {
156
+ if (!this.enabled) {
157
+ return output;
158
+ }
159
+
160
+ if (typeof output !== "string") {
161
+ return output;
162
+ }
163
+
164
+ // HTML escape for terminal output (prevents potential terminal injection)
165
+ return this.sanitizer.sanitize(output, SanitizationRules.HTML);
166
+ }
167
+
168
+ /**
169
+ * Wrap command action with sanitization
170
+ *
171
+ * @param {Function} action - Original command action
172
+ * @returns {Function} Wrapped action with sanitization
173
+ *
174
+ * @example
175
+ * const wrappedAction = middleware.wrapAction(async (options) => {
176
+ * // Original action
177
+ * });
178
+ */
179
+ wrapAction(action) {
180
+ return async (...args) => {
181
+ // Last argument is typically options object
182
+ const lastArg = args[args.length - 1];
183
+
184
+ if (lastArg && typeof lastArg === "object") {
185
+ // Sanitize options
186
+ args[args.length - 1] = this.sanitizeOptions(lastArg);
187
+ }
188
+
189
+ // Sanitize positional arguments
190
+ for (let i = 0; i < args.length - 1; i++) {
191
+ if (typeof args[i] === "string") {
192
+ args[i] = this.sanitizer.sanitize(args[i], SanitizationRules.HTML);
193
+ }
194
+ }
195
+
196
+ // Execute original action
197
+ return await action(...args);
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Get sanitization rule for argument based on name and type
203
+ * @private
204
+ */
205
+ _getRuleForArgument(argName, value) {
206
+ // Check custom rules first
207
+ if (this.customRules[argName]) {
208
+ return this.customRules[argName];
209
+ }
210
+
211
+ // Check predefined CLI rules
212
+ if (CLI_SANITIZATION_RULES[argName]) {
213
+ return CLI_SANITIZATION_RULES[argName];
214
+ }
215
+
216
+ // Infer rule from argument name patterns
217
+ if (
218
+ argName.includes("path") ||
219
+ argName.includes("file") ||
220
+ argName.includes("dir")
221
+ ) {
222
+ return SanitizationRules.PATH;
223
+ }
224
+
225
+ if (argName.includes("url") || argName.includes("uri")) {
226
+ return SanitizationRules.URL;
227
+ }
228
+
229
+ if (argName.includes("email")) {
230
+ return SanitizationRules.EMAIL;
231
+ }
232
+
233
+ if (argName.includes("id") || argName.includes("uuid")) {
234
+ return SanitizationRules.UUID;
235
+ }
236
+
237
+ // Infer from value type
238
+ if (typeof value === "number" || /^\d+$/.test(value)) {
239
+ return SanitizationRules.INTEGER;
240
+ }
241
+
242
+ if (typeof value === "boolean") {
243
+ return SanitizationRules.BOOLEAN;
244
+ }
245
+
246
+ // Default to XSS sanitization for strings
247
+ return SanitizationRules.XSS;
248
+ }
249
+
250
+ /**
251
+ * Get sanitization statistics
252
+ *
253
+ * @returns {Object} Statistics object
254
+ */
255
+ getStats() {
256
+ return this.sanitizer.getStats();
257
+ }
258
+
259
+ /**
260
+ * Reset statistics
261
+ */
262
+ resetStats() {
263
+ this.sanitizer.resetStats();
264
+ }
265
+
266
+ /**
267
+ * Destroy middleware and cleanup resources
268
+ */
269
+ destroy() {
270
+ this.sanitizer.destroy();
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Create global CLI sanitization middleware instance
276
+ */
277
+ const cliSanitizer = new CLISanitizationMiddleware({
278
+ enabled: process.env.CLI_SANITIZATION !== "false",
279
+ verbose: process.env.CLI_SANITIZATION_VERBOSE === "true",
280
+ });
281
+
282
+ /**
283
+ * Quick sanitization helpers for CLI
284
+ */
285
+ function sanitizeCliPath(pathStr) {
286
+ return sanitizePath(pathStr);
287
+ }
288
+
289
+ function sanitizeCliCommand(cmdStr) {
290
+ return sanitizeCommand(cmdStr);
291
+ }
292
+
293
+ function sanitizeCliQuery(queryStr) {
294
+ return cliSanitizer.sanitizer.sanitize(queryStr, SanitizationRules.XSS);
295
+ }
296
+
297
+ function sanitizeCliEmail(emailStr) {
298
+ return validateEmail(emailStr);
299
+ }
300
+
301
+ function sanitizeCliUrl(urlStr) {
302
+ return validateUrl(urlStr);
303
+ }
304
+
305
+ /**
306
+ * Sanitize file path for CLI operations
307
+ *
308
+ * @param {string} filePath - File path to sanitize
309
+ * @returns {string} Sanitized file path
310
+ */
311
+ function sanitizeFilePath(filePath) {
312
+ if (!filePath || typeof filePath !== "string") {
313
+ return filePath;
314
+ }
315
+
316
+ // Remove path traversal attempts
317
+ let sanitized = filePath;
318
+
319
+ // Remove leading traversal
320
+ sanitized = sanitized.replace(/^(\.\.\/|\.\.\\)+/, "");
321
+
322
+ // Remove embedded traversal
323
+ sanitized = sanitized.replace(/\/(\.\.\/|\.\.\\)/g, "/");
324
+ sanitized = sanitized.replace(/\\(\.\.\/|\.\.\\)/g, "\\");
325
+
326
+ // Normalize path separators
327
+ sanitized = sanitized.replace(/\\/g, "/");
328
+
329
+ // Remove multiple consecutive slashes
330
+ sanitized = sanitized.replace(/\/+/g, "/");
331
+
332
+ return sanitized;
333
+ }
334
+
335
+ /**
336
+ * Sanitize all CLI options at once
337
+ *
338
+ * @param {Object} options - CLI options object
339
+ * @returns {Object} Sanitized options
340
+ */
341
+ function sanitizeAllCliOptions(options) {
342
+ return cliSanitizer.sanitizeOptions(options);
343
+ }
344
+
345
+ module.exports = {
346
+ CLISanitizationMiddleware,
347
+ cliSanitizer,
348
+ sanitizeCliPath,
349
+ sanitizeCliCommand,
350
+ sanitizeCliQuery,
351
+ sanitizeCliEmail,
352
+ sanitizeCliUrl,
353
+ sanitizeFilePath,
354
+ sanitizeAllCliOptions,
355
+ CLI_SANITIZATION_RULES,
356
+ };
@@ -0,0 +1,64 @@
1
+ {
2
+ "$schema": "../config/ragrc.schema.json",
3
+ "metadata": {
4
+ "name": "dev-rag-pipeline",
5
+ "version": "1.0.0",
6
+ "description": "Development RAG pipeline with verbose logging and local models",
7
+ "environment": "development",
8
+ "template": "development"
9
+ },
10
+ "plugins": {
11
+ "loader": {
12
+ "file-loader": "latest"
13
+ },
14
+ "embedder": {
15
+ "local-embedder": {
16
+ "name": "local-embedder",
17
+ "version": "latest",
18
+ "config": {
19
+ "modelPath": "./models/embeddings",
20
+ "dimensions": 768
21
+ }
22
+ }
23
+ },
24
+ "retriever": {
25
+ "vector-retriever": {
26
+ "name": "vector-retriever",
27
+ "version": "latest",
28
+ "config": {
29
+ "topK": 5,
30
+ "threshold": 0.6
31
+ }
32
+ }
33
+ },
34
+ "llm": {
35
+ "local-llm": {
36
+ "name": "local-llm",
37
+ "version": "latest",
38
+ "config": {
39
+ "modelPath": "./models/llm",
40
+ "maxTokens": 500
41
+ }
42
+ }
43
+ }
44
+ },
45
+ "pipeline": {
46
+ "stages": ["loader", "embedder", "retriever", "llm"],
47
+ "timeout": 30000
48
+ },
49
+ "performance": {
50
+ "caching": {
51
+ "enabled": true,
52
+ "maxSize": 100,
53
+ "ttl": 600
54
+ }
55
+ },
56
+ "observability": {
57
+ "logging": {
58
+ "level": "debug",
59
+ "structured": true,
60
+ "events": true,
61
+ "console": true
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "../config/ragrc.schema.json",
3
+ "metadata": {
4
+ "name": "minimal-rag-pipeline",
5
+ "version": "1.0.0",
6
+ "description": "Minimal RAG pipeline configuration with essential plugins",
7
+ "environment": "development",
8
+ "template": "minimal"
9
+ },
10
+ "plugins": {
11
+ "loader": {
12
+ "file-loader": "latest"
13
+ },
14
+ "embedder": {
15
+ "openai-embedder": "latest"
16
+ },
17
+ "retriever": {
18
+ "vector-retriever": "latest"
19
+ },
20
+ "llm": {
21
+ "openai-llm": "latest"
22
+ }
23
+ },
24
+ "pipeline": {
25
+ "stages": ["loader", "embedder", "retriever", "llm"]
26
+ },
27
+ "observability": {
28
+ "logging": {
29
+ "level": "info",
30
+ "structured": true
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,104 @@
1
+ {
2
+ "$schema": "../config/ragrc.schema.json",
3
+ "metadata": {
4
+ "name": "production-rag-pipeline",
5
+ "version": "1.0.0",
6
+ "description": "Production-grade RAG pipeline with full observability and optimization",
7
+ "environment": "production",
8
+ "template": "production"
9
+ },
10
+ "plugins": {
11
+ "loader": {
12
+ "file-loader": "latest"
13
+ },
14
+ "embedder": {
15
+ "openai-embedder": {
16
+ "name": "openai-embedder",
17
+ "version": "latest",
18
+ "config": {
19
+ "batchSize": 100,
20
+ "timeout": 30000,
21
+ "retryAttempts": 3
22
+ }
23
+ }
24
+ },
25
+ "retriever": {
26
+ "vector-retriever": {
27
+ "name": "vector-retriever",
28
+ "version": "latest",
29
+ "config": {
30
+ "topK": 10,
31
+ "threshold": 0.7,
32
+ "includeMetadata": true
33
+ }
34
+ }
35
+ },
36
+ "llm": {
37
+ "openai-llm": {
38
+ "name": "openai-llm",
39
+ "version": "latest",
40
+ "config": {
41
+ "model": "gpt-4",
42
+ "temperature": 0.7,
43
+ "maxTokens": 1000
44
+ }
45
+ }
46
+ },
47
+ "reranker": {
48
+ "similarity-reranker": "latest"
49
+ }
50
+ },
51
+ "pipeline": {
52
+ "stages": ["loader", "embedder", "retriever", "reranker", "llm"],
53
+ "retries": {
54
+ "enabled": true,
55
+ "maxAttempts": 3,
56
+ "backoff": "exponential"
57
+ },
58
+ "timeout": 60000
59
+ },
60
+ "performance": {
61
+ "caching": {
62
+ "enabled": true,
63
+ "maxSize": 1000,
64
+ "ttl": 3600
65
+ },
66
+ "parallel": {
67
+ "enabled": true,
68
+ "maxConcurrency": 5,
69
+ "batchSize": 10
70
+ },
71
+ "streaming": {
72
+ "enabled": true,
73
+ "maxMemoryMB": 512,
74
+ "bufferSize": 100
75
+ }
76
+ },
77
+ "observability": {
78
+ "logging": {
79
+ "level": "info",
80
+ "structured": true,
81
+ "events": true
82
+ },
83
+ "tracing": {
84
+ "enabled": true,
85
+ "sampleRate": 0.1,
86
+ "exportUrl": "http://localhost:4318"
87
+ },
88
+ "metrics": {
89
+ "enabled": true,
90
+ "interval": 60000,
91
+ "exportUrl": "http://localhost:4318"
92
+ }
93
+ },
94
+ "security": {
95
+ "encryption": {
96
+ "enabled": true,
97
+ "algorithm": "aes-256-gcm"
98
+ },
99
+ "authentication": {
100
+ "enabled": true,
101
+ "provider": "jwt"
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "$schema": "../config/ragrc.schema.json",
3
+ "metadata": {
4
+ "name": "test-rag-pipeline",
5
+ "version": "1.0.0",
6
+ "description": "Testing RAG pipeline with mock plugins",
7
+ "environment": "testing",
8
+ "template": "testing"
9
+ },
10
+ "plugins": {
11
+ "loader": {
12
+ "mock-loader": {
13
+ "source": "local",
14
+ "path": "./src/mocks/pdf-loader.js"
15
+ }
16
+ },
17
+ "embedder": {
18
+ "mock-embedder": {
19
+ "source": "local",
20
+ "path": "./src/mocks/openai-embedder.js"
21
+ }
22
+ },
23
+ "retriever": {
24
+ "mock-retriever": {
25
+ "source": "local",
26
+ "path": "./src/mocks/pinecone-retriever.js"
27
+ }
28
+ },
29
+ "llm": {
30
+ "mock-llm": {
31
+ "source": "local",
32
+ "path": "./src/mocks/openai-llm.js"
33
+ }
34
+ }
35
+ },
36
+ "pipeline": {
37
+ "stages": ["loader", "embedder", "retriever", "llm"]
38
+ },
39
+ "observability": {
40
+ "logging": {
41
+ "level": "warn",
42
+ "structured": true
43
+ }
44
+ }
45
+ }