@devilsdev/rag-pipeline-utils 2.2.0 → 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.
- package/README.md +323 -722
- package/contracts/contract-schema.json +189 -0
- package/contracts/reranker-contract.json +69 -0
- package/dist/index.cjs +19 -0
- package/dist/index.mjs +15 -1
- package/package.json +4 -2
- package/src/cli/commands/wizard.js +627 -0
- package/src/cli/input-sanitization-middleware.js +356 -0
- package/src/cli/templates/development.template.json +64 -0
- package/src/cli/templates/minimal.template.json +33 -0
- package/src/cli/templates/production.template.json +104 -0
- package/src/cli/templates/testing.template.json +45 -0
- package/src/config/connection-pool-config.json +259 -0
- package/src/config/memory-optimization.js +414 -0
- package/src/config/redaction-patterns.json +150 -0
- package/src/config/sanitization-rules.json +323 -0
- package/src/core/performance/streaming-safeguards.js +10 -1
- package/src/core/plugin-registry.js +275 -0
- package/src/dag/core/error-context.js +391 -0
- package/src/dag/core/execution-scheduler.js +350 -0
- package/src/dag/core/topology-validation.js +415 -0
- package/src/dag/dag-engine.js +26 -424
- package/src/dev/README.md +126 -0
- package/src/dev/dev-server.js +356 -0
- package/src/dev/examples/hot-reload-usage.js +355 -0
- package/src/dev/hot-reload.js +807 -0
- package/src/enterprise/sso-integration.js +184 -15
- package/src/index.js +19 -0
- package/src/observability/event-logger.js +62 -2
- package/src/plugins/optimized-openai-embedder.js +169 -0
- package/src/reranker/llm-reranker.js +30 -4
- package/src/security/jwt-config.js +431 -0
- package/src/security/jwt-validator.js +701 -0
- package/src/utils/api-client-pool-integration.js +436 -0
- package/src/utils/batch-processor.js +710 -0
- package/src/utils/connection-pool.js +605 -0
- package/src/utils/contract-validator.js +460 -0
- package/src/utils/error-formatter.js +603 -0
- package/src/utils/examples/error-formatter-usage.js +351 -0
- package/src/utils/input-sanitizer.js +967 -0
- package/src/utils/memory-monitor.js +800 -0
- package/src/utils/rate-limiter.js +244 -0
- package/src/utils/secure-logger-config.js +352 -0
- package/src/utils/secure-logger.js +576 -0
- package/src/utils/secure-logging.js +338 -0
- package/src/utils/structured-logger.js +32 -5
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Secure Logging Utility
|
|
3
|
+
* Redacts sensitive values from log messages and objects to prevent secret leakage
|
|
4
|
+
*
|
|
5
|
+
* @author DevilsDev Team
|
|
6
|
+
* @since 2.2.1
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sensitive field names that should be redacted
|
|
13
|
+
*/
|
|
14
|
+
const SENSITIVE_FIELD_NAMES = new Set([
|
|
15
|
+
'password',
|
|
16
|
+
'passwd',
|
|
17
|
+
'pwd',
|
|
18
|
+
'secret',
|
|
19
|
+
'api_key',
|
|
20
|
+
'apiKey',
|
|
21
|
+
'apikey',
|
|
22
|
+
'api-key',
|
|
23
|
+
'token',
|
|
24
|
+
'accessToken',
|
|
25
|
+
'access_token',
|
|
26
|
+
'refreshToken',
|
|
27
|
+
'refresh_token',
|
|
28
|
+
'auth',
|
|
29
|
+
'authorization',
|
|
30
|
+
'authtoken',
|
|
31
|
+
'sessionid',
|
|
32
|
+
'session_id',
|
|
33
|
+
'sessionId',
|
|
34
|
+
'jwt',
|
|
35
|
+
'bearer',
|
|
36
|
+
'private_key',
|
|
37
|
+
'privatekey', // Added lowercase variant
|
|
38
|
+
'privateKey',
|
|
39
|
+
'private-key',
|
|
40
|
+
'client_secret',
|
|
41
|
+
'clientSecret',
|
|
42
|
+
'client-secret',
|
|
43
|
+
'encryption_key',
|
|
44
|
+
'encryptionKey',
|
|
45
|
+
'signing_key',
|
|
46
|
+
'signingKey',
|
|
47
|
+
'oauth_token',
|
|
48
|
+
'oauthToken',
|
|
49
|
+
'credentials',
|
|
50
|
+
'credential',
|
|
51
|
+
'ssn',
|
|
52
|
+
'credit_card',
|
|
53
|
+
'creditCard',
|
|
54
|
+
'cvv',
|
|
55
|
+
'pin',
|
|
56
|
+
'salt',
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Patterns that match secret-like values
|
|
61
|
+
*/
|
|
62
|
+
const SECRET_PATTERNS = [
|
|
63
|
+
// AWS credentials
|
|
64
|
+
/AKIA[0-9A-Z]{16}/gi, // AWS Access Key ID
|
|
65
|
+
/aws_secret_access_key\s*=\s*[A-Za-z0-9/+=]{40}/gi,
|
|
66
|
+
|
|
67
|
+
// Generic API keys (32+ hex chars, 20+ base64 chars)
|
|
68
|
+
/[a-f0-9]{32,}/gi, // Hex keys
|
|
69
|
+
/[A-Za-z0-9+/]{20,}={0,2}/g, // Base64 keys
|
|
70
|
+
|
|
71
|
+
// JWT tokens (3 base64 parts separated by dots)
|
|
72
|
+
/eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
|
|
73
|
+
|
|
74
|
+
// Bearer tokens
|
|
75
|
+
/Bearer\s+[A-Za-z0-9_\-\.]+/gi,
|
|
76
|
+
|
|
77
|
+
// GitHub tokens
|
|
78
|
+
/gh[pousr]_[A-Za-z0-9]{36}/g,
|
|
79
|
+
|
|
80
|
+
// Generic passwords in URL format
|
|
81
|
+
/:\/\/[^:]+:([^@]+)@/g, // Captures password in user:password@host
|
|
82
|
+
|
|
83
|
+
// Credit card numbers (basic pattern)
|
|
84
|
+
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
|
|
85
|
+
|
|
86
|
+
// SSN pattern
|
|
87
|
+
/\b\d{3}-\d{2}-\d{4}\b/g,
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Redaction marker
|
|
92
|
+
*/
|
|
93
|
+
const REDACTED = '[REDACTED]';
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if a field name is sensitive
|
|
97
|
+
* @param {string} fieldName - Field name to check
|
|
98
|
+
* @returns {boolean} True if sensitive
|
|
99
|
+
*/
|
|
100
|
+
function isSensitiveFieldName(fieldName) {
|
|
101
|
+
if (typeof fieldName !== 'string') return false;
|
|
102
|
+
|
|
103
|
+
const lowerFieldName = fieldName.toLowerCase();
|
|
104
|
+
return SENSITIVE_FIELD_NAMES.has(lowerFieldName);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if a value matches a secret pattern
|
|
109
|
+
* @param {string} value - Value to check
|
|
110
|
+
* @returns {boolean} True if matches secret pattern
|
|
111
|
+
*/
|
|
112
|
+
function matchesSecretPattern(value) {
|
|
113
|
+
if (typeof value !== 'string') return false;
|
|
114
|
+
|
|
115
|
+
// Skip short values to avoid false positives
|
|
116
|
+
if (value.length < 8) return false;
|
|
117
|
+
|
|
118
|
+
// Check against secret patterns
|
|
119
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
120
|
+
// Reset regex lastIndex to avoid stateful regex issues
|
|
121
|
+
pattern.lastIndex = 0;
|
|
122
|
+
|
|
123
|
+
if (pattern.test(value)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Redact a string value if it contains secrets
|
|
133
|
+
* @param {string} value - String value to redact
|
|
134
|
+
* @returns {string} Redacted value if sensitive, original otherwise
|
|
135
|
+
*/
|
|
136
|
+
function redactStringValue(value) {
|
|
137
|
+
if (typeof value !== 'string') return value;
|
|
138
|
+
|
|
139
|
+
// Short strings are unlikely to be secrets
|
|
140
|
+
if (value.length < 8) return value;
|
|
141
|
+
|
|
142
|
+
// Check if entire value matches secret pattern
|
|
143
|
+
if (matchesSecretPattern(value)) {
|
|
144
|
+
return REDACTED;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Redact parts of the string that match patterns
|
|
148
|
+
let redacted = value;
|
|
149
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
150
|
+
pattern.lastIndex = 0;
|
|
151
|
+
redacted = redacted.replace(pattern, REDACTED);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return redacted;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Redact sensitive fields in an object
|
|
159
|
+
* @param {any} obj - Object to redact
|
|
160
|
+
* @param {number} depth - Current recursion depth
|
|
161
|
+
* @param {number} maxDepth - Maximum recursion depth
|
|
162
|
+
* @returns {any} Redacted object
|
|
163
|
+
*/
|
|
164
|
+
function redactObject(obj, depth = 0, maxDepth = 10) {
|
|
165
|
+
// Prevent infinite recursion
|
|
166
|
+
if (depth > maxDepth) return '[MAX_DEPTH_EXCEEDED]';
|
|
167
|
+
|
|
168
|
+
// Handle primitives
|
|
169
|
+
if (obj === null || obj === undefined) return obj;
|
|
170
|
+
if (typeof obj === 'string') return redactStringValue(obj);
|
|
171
|
+
if (typeof obj === 'number' || typeof obj === 'boolean') return obj;
|
|
172
|
+
|
|
173
|
+
// Handle Date objects
|
|
174
|
+
if (obj instanceof Date) return obj;
|
|
175
|
+
|
|
176
|
+
// Handle Error objects specially to preserve standard properties
|
|
177
|
+
if (obj instanceof Error) {
|
|
178
|
+
const errorObj = {
|
|
179
|
+
name: obj.name,
|
|
180
|
+
message: obj.message,
|
|
181
|
+
stack: obj.stack,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Include any other enumerable properties (like code)
|
|
185
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
186
|
+
if (!['name', 'message', 'stack'].includes(key)) {
|
|
187
|
+
errorObj[key] = redactObject(value, depth + 1, maxDepth);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return errorObj;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Handle arrays
|
|
195
|
+
if (Array.isArray(obj)) {
|
|
196
|
+
return obj.map((item) => redactObject(item, depth + 1, maxDepth));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Handle objects
|
|
200
|
+
if (typeof obj === 'object') {
|
|
201
|
+
const redacted = {};
|
|
202
|
+
|
|
203
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
204
|
+
// For sensitive field names, check the value type
|
|
205
|
+
if (isSensitiveFieldName(key)) {
|
|
206
|
+
// If value is an object, still traverse it to redact nested sensitive fields
|
|
207
|
+
if (
|
|
208
|
+
typeof value === 'object' &&
|
|
209
|
+
value !== null &&
|
|
210
|
+
!Array.isArray(value)
|
|
211
|
+
) {
|
|
212
|
+
redacted[key] = redactObject(value, depth + 1, maxDepth);
|
|
213
|
+
} else {
|
|
214
|
+
// For primitives and arrays, redact the entire value
|
|
215
|
+
redacted[key] = REDACTED;
|
|
216
|
+
}
|
|
217
|
+
} else if (typeof value === 'string') {
|
|
218
|
+
// Redact string values that match patterns
|
|
219
|
+
redacted[key] = redactStringValue(value);
|
|
220
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
221
|
+
// Recursively redact nested objects
|
|
222
|
+
redacted[key] = redactObject(value, depth + 1, maxDepth);
|
|
223
|
+
} else {
|
|
224
|
+
// Keep primitive values as-is
|
|
225
|
+
redacted[key] = value;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return redacted;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Default fallback
|
|
233
|
+
return obj;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Redact sensitive information from log data
|
|
238
|
+
* @param {string} message - Log message
|
|
239
|
+
* @param {object} meta - Log metadata object
|
|
240
|
+
* @returns {object} Redacted message and metadata
|
|
241
|
+
*/
|
|
242
|
+
function redactLogData(message, meta = {}) {
|
|
243
|
+
const redactedMessage =
|
|
244
|
+
typeof message === 'string' ? redactStringValue(message) : message;
|
|
245
|
+
|
|
246
|
+
const redactedMeta = redactObject(meta);
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
message: redactedMessage,
|
|
250
|
+
meta: redactedMeta,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Create a redacting wrapper for any logger
|
|
256
|
+
* @param {object} logger - Logger instance to wrap
|
|
257
|
+
* @returns {object} Wrapped logger with automatic redaction
|
|
258
|
+
*/
|
|
259
|
+
function createSecureLogger(logger) {
|
|
260
|
+
return {
|
|
261
|
+
error(message, meta = {}) {
|
|
262
|
+
const { message: redactedMsg, meta: redactedMeta } = redactLogData(
|
|
263
|
+
message,
|
|
264
|
+
meta,
|
|
265
|
+
);
|
|
266
|
+
return logger.error(redactedMsg, redactedMeta);
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
warn(message, meta = {}) {
|
|
270
|
+
const { message: redactedMsg, meta: redactedMeta } = redactLogData(
|
|
271
|
+
message,
|
|
272
|
+
meta,
|
|
273
|
+
);
|
|
274
|
+
return logger.warn(redactedMsg, redactedMeta);
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
info(message, meta = {}) {
|
|
278
|
+
const { message: redactedMsg, meta: redactedMeta } = redactLogData(
|
|
279
|
+
message,
|
|
280
|
+
meta,
|
|
281
|
+
);
|
|
282
|
+
return logger.info(redactedMsg, redactedMeta);
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
debug(message, meta = {}) {
|
|
286
|
+
const { message: redactedMsg, meta: redactedMeta } = redactLogData(
|
|
287
|
+
message,
|
|
288
|
+
meta,
|
|
289
|
+
);
|
|
290
|
+
return logger.debug(redactedMsg, redactedMeta);
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
trace(message, meta = {}) {
|
|
294
|
+
const { message: redactedMsg, meta: redactedMeta } = redactLogData(
|
|
295
|
+
message,
|
|
296
|
+
meta,
|
|
297
|
+
);
|
|
298
|
+
return logger.trace(redactedMsg, redactedMeta);
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
// Preserve other logger methods
|
|
302
|
+
child(...args) {
|
|
303
|
+
const childLogger = logger.child(...args);
|
|
304
|
+
return createSecureLogger(childLogger);
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
withCorrelation(...args) {
|
|
308
|
+
return logger.withCorrelation(...args);
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
getContext(...args) {
|
|
312
|
+
return logger.getContext(...args);
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
getMetrics(...args) {
|
|
316
|
+
return logger.getMetrics(...args);
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
resetMetrics(...args) {
|
|
320
|
+
return logger.resetMetrics?.(...args);
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
module.exports = {
|
|
326
|
+
redactObject,
|
|
327
|
+
redactStringValue,
|
|
328
|
+
redactLogData,
|
|
329
|
+
createSecureLogger,
|
|
330
|
+
isSensitiveFieldName,
|
|
331
|
+
matchesSecretPattern,
|
|
332
|
+
SENSITIVE_FIELD_NAMES,
|
|
333
|
+
SECRET_PATTERNS,
|
|
334
|
+
REDACTED,
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// CommonJS/ESM interop
|
|
338
|
+
module.exports.default = module.exports;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const { AsyncLocalStorage } = require('async_hooks');
|
|
10
10
|
const crypto = require('crypto');
|
|
11
|
+
const { redactLogData } = require('./secure-logging');
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Async local storage for correlation context
|
|
@@ -36,6 +37,7 @@ class StructuredLogger {
|
|
|
36
37
|
this.logLevel = options.logLevel || process.env.LOG_LEVEL || 'info';
|
|
37
38
|
this.enableCorrelation = options.enableCorrelation !== false;
|
|
38
39
|
this.enableMetrics = options.enableMetrics !== false;
|
|
40
|
+
this.enableSecureLogging = options.enableSecureLogging !== false; // Default enabled for security
|
|
39
41
|
this.outputFormat = options.outputFormat || 'json'; // json, console
|
|
40
42
|
|
|
41
43
|
// Performance tracking
|
|
@@ -201,7 +203,12 @@ class StructuredLogger {
|
|
|
201
203
|
error(message, meta = {}) {
|
|
202
204
|
if (!this.shouldLog('error')) return;
|
|
203
205
|
|
|
204
|
-
|
|
206
|
+
// Redact sensitive information if secure logging is enabled
|
|
207
|
+
const { message: safeMessage, meta: safeMeta } = this.enableSecureLogging
|
|
208
|
+
? redactLogData(message, meta)
|
|
209
|
+
: { message, meta };
|
|
210
|
+
|
|
211
|
+
const entry = this.createLogEntry('error', safeMessage, safeMeta);
|
|
205
212
|
this.writeLog(entry);
|
|
206
213
|
}
|
|
207
214
|
|
|
@@ -213,7 +220,12 @@ class StructuredLogger {
|
|
|
213
220
|
warn(message, meta = {}) {
|
|
214
221
|
if (!this.shouldLog('warn')) return;
|
|
215
222
|
|
|
216
|
-
|
|
223
|
+
// Redact sensitive information if secure logging is enabled
|
|
224
|
+
const { message: safeMessage, meta: safeMeta } = this.enableSecureLogging
|
|
225
|
+
? redactLogData(message, meta)
|
|
226
|
+
: { message, meta };
|
|
227
|
+
|
|
228
|
+
const entry = this.createLogEntry('warn', safeMessage, safeMeta);
|
|
217
229
|
this.writeLog(entry);
|
|
218
230
|
}
|
|
219
231
|
|
|
@@ -225,7 +237,12 @@ class StructuredLogger {
|
|
|
225
237
|
info(message, meta = {}) {
|
|
226
238
|
if (!this.shouldLog('info')) return;
|
|
227
239
|
|
|
228
|
-
|
|
240
|
+
// Redact sensitive information if secure logging is enabled
|
|
241
|
+
const { message: safeMessage, meta: safeMeta } = this.enableSecureLogging
|
|
242
|
+
? redactLogData(message, meta)
|
|
243
|
+
: { message, meta };
|
|
244
|
+
|
|
245
|
+
const entry = this.createLogEntry('info', safeMessage, safeMeta);
|
|
229
246
|
this.writeLog(entry);
|
|
230
247
|
}
|
|
231
248
|
|
|
@@ -237,7 +254,12 @@ class StructuredLogger {
|
|
|
237
254
|
debug(message, meta = {}) {
|
|
238
255
|
if (!this.shouldLog('debug')) return;
|
|
239
256
|
|
|
240
|
-
|
|
257
|
+
// Redact sensitive information if secure logging is enabled
|
|
258
|
+
const { message: safeMessage, meta: safeMeta } = this.enableSecureLogging
|
|
259
|
+
? redactLogData(message, meta)
|
|
260
|
+
: { message, meta };
|
|
261
|
+
|
|
262
|
+
const entry = this.createLogEntry('debug', safeMessage, safeMeta);
|
|
241
263
|
this.writeLog(entry);
|
|
242
264
|
}
|
|
243
265
|
|
|
@@ -249,7 +271,12 @@ class StructuredLogger {
|
|
|
249
271
|
trace(message, meta = {}) {
|
|
250
272
|
if (!this.shouldLog('trace')) return;
|
|
251
273
|
|
|
252
|
-
|
|
274
|
+
// Redact sensitive information if secure logging is enabled
|
|
275
|
+
const { message: safeMessage, meta: safeMeta } = this.enableSecureLogging
|
|
276
|
+
? redactLogData(message, meta)
|
|
277
|
+
: { message, meta };
|
|
278
|
+
|
|
279
|
+
const entry = this.createLogEntry('trace', safeMessage, safeMeta);
|
|
253
280
|
this.writeLog(entry);
|
|
254
281
|
}
|
|
255
282
|
|