network-ai 3.0.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 (92) hide show
  1. package/LICENSE +21 -0
  2. package/QUICKSTART.md +260 -0
  3. package/README.md +604 -0
  4. package/SKILL.md +568 -0
  5. package/dist/adapters/adapter-registry.d.ts +94 -0
  6. package/dist/adapters/adapter-registry.d.ts.map +1 -0
  7. package/dist/adapters/adapter-registry.js +355 -0
  8. package/dist/adapters/adapter-registry.js.map +1 -0
  9. package/dist/adapters/agno-adapter.d.ts +112 -0
  10. package/dist/adapters/agno-adapter.d.ts.map +1 -0
  11. package/dist/adapters/agno-adapter.js +140 -0
  12. package/dist/adapters/agno-adapter.js.map +1 -0
  13. package/dist/adapters/autogen-adapter.d.ts +67 -0
  14. package/dist/adapters/autogen-adapter.d.ts.map +1 -0
  15. package/dist/adapters/autogen-adapter.js +141 -0
  16. package/dist/adapters/autogen-adapter.js.map +1 -0
  17. package/dist/adapters/base-adapter.d.ts +51 -0
  18. package/dist/adapters/base-adapter.d.ts.map +1 -0
  19. package/dist/adapters/base-adapter.js +103 -0
  20. package/dist/adapters/base-adapter.js.map +1 -0
  21. package/dist/adapters/crewai-adapter.d.ts +72 -0
  22. package/dist/adapters/crewai-adapter.d.ts.map +1 -0
  23. package/dist/adapters/crewai-adapter.js +148 -0
  24. package/dist/adapters/crewai-adapter.js.map +1 -0
  25. package/dist/adapters/custom-adapter.d.ts +74 -0
  26. package/dist/adapters/custom-adapter.d.ts.map +1 -0
  27. package/dist/adapters/custom-adapter.js +142 -0
  28. package/dist/adapters/custom-adapter.js.map +1 -0
  29. package/dist/adapters/dspy-adapter.d.ts +70 -0
  30. package/dist/adapters/dspy-adapter.d.ts.map +1 -0
  31. package/dist/adapters/dspy-adapter.js +127 -0
  32. package/dist/adapters/dspy-adapter.js.map +1 -0
  33. package/dist/adapters/haystack-adapter.d.ts +83 -0
  34. package/dist/adapters/haystack-adapter.d.ts.map +1 -0
  35. package/dist/adapters/haystack-adapter.js +149 -0
  36. package/dist/adapters/haystack-adapter.js.map +1 -0
  37. package/dist/adapters/index.d.ts +47 -0
  38. package/dist/adapters/index.d.ts.map +1 -0
  39. package/dist/adapters/index.js +56 -0
  40. package/dist/adapters/index.js.map +1 -0
  41. package/dist/adapters/langchain-adapter.d.ts +51 -0
  42. package/dist/adapters/langchain-adapter.d.ts.map +1 -0
  43. package/dist/adapters/langchain-adapter.js +134 -0
  44. package/dist/adapters/langchain-adapter.js.map +1 -0
  45. package/dist/adapters/llamaindex-adapter.d.ts +89 -0
  46. package/dist/adapters/llamaindex-adapter.d.ts.map +1 -0
  47. package/dist/adapters/llamaindex-adapter.js +135 -0
  48. package/dist/adapters/llamaindex-adapter.js.map +1 -0
  49. package/dist/adapters/mcp-adapter.d.ts +90 -0
  50. package/dist/adapters/mcp-adapter.d.ts.map +1 -0
  51. package/dist/adapters/mcp-adapter.js +200 -0
  52. package/dist/adapters/mcp-adapter.js.map +1 -0
  53. package/dist/adapters/openai-assistants-adapter.d.ts +94 -0
  54. package/dist/adapters/openai-assistants-adapter.d.ts.map +1 -0
  55. package/dist/adapters/openai-assistants-adapter.js +130 -0
  56. package/dist/adapters/openai-assistants-adapter.js.map +1 -0
  57. package/dist/adapters/openclaw-adapter.d.ts +21 -0
  58. package/dist/adapters/openclaw-adapter.d.ts.map +1 -0
  59. package/dist/adapters/openclaw-adapter.js +140 -0
  60. package/dist/adapters/openclaw-adapter.js.map +1 -0
  61. package/dist/adapters/semantic-kernel-adapter.d.ts +73 -0
  62. package/dist/adapters/semantic-kernel-adapter.d.ts.map +1 -0
  63. package/dist/adapters/semantic-kernel-adapter.js +123 -0
  64. package/dist/adapters/semantic-kernel-adapter.js.map +1 -0
  65. package/dist/index.d.ts +379 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +1428 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/lib/blackboard-validator.d.ts +205 -0
  70. package/dist/lib/blackboard-validator.d.ts.map +1 -0
  71. package/dist/lib/blackboard-validator.js +756 -0
  72. package/dist/lib/blackboard-validator.js.map +1 -0
  73. package/dist/lib/locked-blackboard.d.ts +174 -0
  74. package/dist/lib/locked-blackboard.d.ts.map +1 -0
  75. package/dist/lib/locked-blackboard.js +654 -0
  76. package/dist/lib/locked-blackboard.js.map +1 -0
  77. package/dist/lib/swarm-utils.d.ts +136 -0
  78. package/dist/lib/swarm-utils.d.ts.map +1 -0
  79. package/dist/lib/swarm-utils.js +510 -0
  80. package/dist/lib/swarm-utils.js.map +1 -0
  81. package/dist/security.d.ts +269 -0
  82. package/dist/security.d.ts.map +1 -0
  83. package/dist/security.js +713 -0
  84. package/dist/security.js.map +1 -0
  85. package/package.json +84 -0
  86. package/scripts/blackboard.py +819 -0
  87. package/scripts/check_permission.py +331 -0
  88. package/scripts/revoke_token.py +243 -0
  89. package/scripts/swarm_guard.py +1140 -0
  90. package/scripts/validate_token.py +97 -0
  91. package/types/agent-adapter.d.ts +244 -0
  92. package/types/openclaw-core.d.ts +52 -0
@@ -0,0 +1,713 @@
1
+ "use strict";
2
+ /**
3
+ * SwarmOrchestrator Security Module
4
+ *
5
+ * This module addresses security vulnerabilities in the multi-agent system:
6
+ *
7
+ * 1. Token Security - HMAC-signed tokens with expiration
8
+ * 2. Input Sanitization - Prevent injection attacks
9
+ * 3. Rate Limiting - Prevent DoS from rogue agents
10
+ * 4. Audit Integrity - Cryptographically signed audit logs
11
+ * 5. Data Encryption - Encrypt sensitive blackboard entries
12
+ * 6. Permission Hardening - Prevent privilege escalation
13
+ * 7. Path Traversal Protection - Sanitize file paths
14
+ *
15
+ * @module SwarmSecurity
16
+ * @version 1.0.0
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.DEFAULT_CONFIG = exports.SecureSwarmGateway = exports.SecurityError = exports.PermissionHardener = exports.DataEncryptor = exports.SecureAuditLogger = exports.RateLimiter = exports.InputSanitizer = exports.SecureTokenManager = void 0;
20
+ const crypto_1 = require("crypto");
21
+ const fs_1 = require("fs");
22
+ const path_1 = require("path");
23
+ const DEFAULT_CONFIG = {
24
+ tokenSecret: process.env.SWARM_TOKEN_SECRET || (0, crypto_1.randomBytes)(32).toString('hex'),
25
+ tokenAlgorithm: 'sha256',
26
+ maxTokenAge: 300000, // 5 minutes
27
+ maxRequestsPerMinute: 100,
28
+ maxFailedAuthAttempts: 5,
29
+ lockoutDuration: 900000, // 15 minutes
30
+ encryptionKey: process.env.SWARM_ENCRYPTION_KEY || (0, crypto_1.randomBytes)(32).toString('hex'),
31
+ encryptSensitiveData: true,
32
+ signAuditLogs: true,
33
+ auditLogPath: './security-audit.log',
34
+ allowedBasePath: process.cwd(),
35
+ };
36
+ exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
37
+ class SecureTokenManager {
38
+ config;
39
+ revokedTokens = new Set();
40
+ constructor(config = {}) {
41
+ this.config = { ...DEFAULT_CONFIG, ...config };
42
+ }
43
+ /**
44
+ * Generate a cryptographically signed token
45
+ */
46
+ generateToken(agentId, resourceType, scope) {
47
+ const tokenId = (0, crypto_1.randomBytes)(16).toString('hex');
48
+ const issuedAt = Date.now();
49
+ const expiresAt = issuedAt + this.config.maxTokenAge;
50
+ // Create token payload
51
+ const payload = `${tokenId}:${agentId}:${resourceType}:${scope}:${issuedAt}:${expiresAt}`;
52
+ // Sign the payload
53
+ const signature = this.sign(payload);
54
+ return {
55
+ tokenId,
56
+ agentId,
57
+ resourceType,
58
+ scope,
59
+ issuedAt,
60
+ expiresAt,
61
+ signature,
62
+ };
63
+ }
64
+ /**
65
+ * Validate a token's authenticity and expiration
66
+ */
67
+ validateToken(token) {
68
+ // Check if revoked
69
+ if (this.revokedTokens.has(token.tokenId)) {
70
+ return { valid: false, reason: 'Token has been revoked' };
71
+ }
72
+ // Check expiration
73
+ if (Date.now() > token.expiresAt) {
74
+ return { valid: false, reason: 'Token has expired' };
75
+ }
76
+ // Verify signature
77
+ const payload = `${token.tokenId}:${token.agentId}:${token.resourceType}:${token.scope}:${token.issuedAt}:${token.expiresAt}`;
78
+ const expectedSignature = this.sign(payload);
79
+ if (!this.constantTimeCompare(token.signature, expectedSignature)) {
80
+ return { valid: false, reason: 'Invalid token signature' };
81
+ }
82
+ return { valid: true };
83
+ }
84
+ /**
85
+ * Revoke a token
86
+ */
87
+ revokeToken(tokenId) {
88
+ this.revokedTokens.add(tokenId);
89
+ }
90
+ /**
91
+ * HMAC sign a payload
92
+ */
93
+ sign(payload) {
94
+ return (0, crypto_1.createHmac)(this.config.tokenAlgorithm, this.config.tokenSecret)
95
+ .update(payload)
96
+ .digest('hex');
97
+ }
98
+ /**
99
+ * Constant-time string comparison to prevent timing attacks
100
+ */
101
+ constantTimeCompare(a, b) {
102
+ if (a.length !== b.length)
103
+ return false;
104
+ let result = 0;
105
+ for (let i = 0; i < a.length; i++) {
106
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
107
+ }
108
+ return result === 0;
109
+ }
110
+ }
111
+ exports.SecureTokenManager = SecureTokenManager;
112
+ // ============================================================================
113
+ // 2. INPUT SANITIZER
114
+ // ============================================================================
115
+ class InputSanitizer {
116
+ // Dangerous patterns that could indicate injection attempts
117
+ static DANGEROUS_PATTERNS = [
118
+ /\$\{.*\}/g, // Template injection
119
+ /<script.*?>.*?<\/script>/gi, // XSS
120
+ /javascript:/gi, // JavaScript protocol
121
+ /on\w+\s*=/gi, // Event handlers
122
+ /\.\.\//g, // Path traversal
123
+ /[;&|`$]/g, // Command injection chars
124
+ /__proto__/gi, // Prototype pollution
125
+ /constructor/gi, // Prototype pollution
126
+ ];
127
+ /**
128
+ * Sanitize a string input
129
+ */
130
+ static sanitizeString(input, maxLength = 10000) {
131
+ if (typeof input !== 'string') {
132
+ throw new SecurityError('Input must be a string', 'INVALID_INPUT_TYPE');
133
+ }
134
+ // Truncate to max length
135
+ let sanitized = input.slice(0, maxLength);
136
+ // Remove dangerous patterns
137
+ for (const pattern of this.DANGEROUS_PATTERNS) {
138
+ sanitized = sanitized.replace(pattern, '');
139
+ }
140
+ // Encode special characters
141
+ sanitized = sanitized
142
+ .replace(/&/g, '&amp;')
143
+ .replace(/</g, '&lt;')
144
+ .replace(/>/g, '&gt;')
145
+ .replace(/"/g, '&quot;')
146
+ .replace(/'/g, '&#x27;');
147
+ return sanitized;
148
+ }
149
+ /**
150
+ * Sanitize an object recursively
151
+ */
152
+ static sanitizeObject(obj, depth = 0, maxDepth = 10) {
153
+ if (depth > maxDepth) {
154
+ throw new SecurityError('Object nesting too deep', 'MAX_DEPTH_EXCEEDED');
155
+ }
156
+ if (obj === null || obj === undefined) {
157
+ return obj;
158
+ }
159
+ if (typeof obj === 'string') {
160
+ return this.sanitizeString(obj);
161
+ }
162
+ if (typeof obj === 'number' || typeof obj === 'boolean') {
163
+ return obj;
164
+ }
165
+ if (Array.isArray(obj)) {
166
+ return obj.map(item => this.sanitizeObject(item, depth + 1, maxDepth));
167
+ }
168
+ if (typeof obj === 'object') {
169
+ const sanitized = {};
170
+ for (const [key, value] of Object.entries(obj)) {
171
+ // Sanitize keys too
172
+ const sanitizedKey = this.sanitizeString(key, 100);
173
+ // Block prototype pollution attempts
174
+ if (sanitizedKey === '__proto__' || sanitizedKey === 'constructor' || sanitizedKey === 'prototype') {
175
+ continue;
176
+ }
177
+ sanitized[sanitizedKey] = this.sanitizeObject(value, depth + 1, maxDepth);
178
+ }
179
+ return sanitized;
180
+ }
181
+ return undefined; // Unknown types are dropped
182
+ }
183
+ /**
184
+ * Validate and sanitize an agent ID
185
+ */
186
+ static sanitizeAgentId(agentId) {
187
+ if (typeof agentId !== 'string' || agentId.length === 0) {
188
+ throw new SecurityError('Invalid agent ID', 'INVALID_AGENT_ID');
189
+ }
190
+ // Agent IDs should be alphanumeric with underscores/hyphens only
191
+ const sanitized = agentId.replace(/[^a-zA-Z0-9_-]/g, '');
192
+ if (sanitized.length === 0 || sanitized.length > 64) {
193
+ throw new SecurityError('Agent ID format invalid', 'INVALID_AGENT_ID_FORMAT');
194
+ }
195
+ return sanitized;
196
+ }
197
+ /**
198
+ * Validate and sanitize a file path
199
+ */
200
+ static sanitizePath(inputPath, basePath) {
201
+ // Normalize the path
202
+ const normalized = (0, path_1.normalize)(inputPath);
203
+ // Resolve to absolute
204
+ const absolute = (0, path_1.isAbsolute)(normalized)
205
+ ? normalized
206
+ : (0, path_1.join)(basePath, normalized);
207
+ // Ensure it's within the allowed base path
208
+ const resolvedBase = (0, path_1.normalize)(basePath);
209
+ const resolvedPath = (0, path_1.normalize)(absolute);
210
+ if (!resolvedPath.startsWith(resolvedBase)) {
211
+ throw new SecurityError('Path traversal attempt detected', 'PATH_TRAVERSAL');
212
+ }
213
+ return resolvedPath;
214
+ }
215
+ }
216
+ exports.InputSanitizer = InputSanitizer;
217
+ class RateLimiter {
218
+ limits = new Map();
219
+ config;
220
+ constructor(config = {}) {
221
+ this.config = { ...DEFAULT_CONFIG, ...config };
222
+ }
223
+ /**
224
+ * Check if an agent is rate limited
225
+ */
226
+ isRateLimited(agentId) {
227
+ const entry = this.limits.get(agentId);
228
+ const now = Date.now();
229
+ if (!entry) {
230
+ this.limits.set(agentId, {
231
+ count: 1,
232
+ windowStart: now,
233
+ failedAttempts: 0,
234
+ lockedUntil: null,
235
+ });
236
+ return { limited: false };
237
+ }
238
+ // Check if locked out
239
+ if (entry.lockedUntil && now < entry.lockedUntil) {
240
+ return {
241
+ limited: true,
242
+ retryAfter: Math.ceil((entry.lockedUntil - now) / 1000)
243
+ };
244
+ }
245
+ // Reset window if expired (1 minute)
246
+ if (now - entry.windowStart > 60000) {
247
+ entry.count = 1;
248
+ entry.windowStart = now;
249
+ entry.lockedUntil = null;
250
+ return { limited: false };
251
+ }
252
+ // Increment counter
253
+ entry.count++;
254
+ // Check if over limit
255
+ if (entry.count > this.config.maxRequestsPerMinute) {
256
+ return {
257
+ limited: true,
258
+ retryAfter: Math.ceil((entry.windowStart + 60000 - now) / 1000)
259
+ };
260
+ }
261
+ return { limited: false };
262
+ }
263
+ /**
264
+ * Record a failed authentication attempt
265
+ */
266
+ recordFailedAuth(agentId) {
267
+ const entry = this.limits.get(agentId) || {
268
+ count: 0,
269
+ windowStart: Date.now(),
270
+ failedAttempts: 0,
271
+ lockedUntil: null,
272
+ };
273
+ entry.failedAttempts++;
274
+ if (entry.failedAttempts >= this.config.maxFailedAuthAttempts) {
275
+ entry.lockedUntil = Date.now() + this.config.lockoutDuration;
276
+ this.limits.set(agentId, entry);
277
+ return { locked: true };
278
+ }
279
+ this.limits.set(agentId, entry);
280
+ return {
281
+ locked: false,
282
+ attemptsRemaining: this.config.maxFailedAuthAttempts - entry.failedAttempts
283
+ };
284
+ }
285
+ /**
286
+ * Reset failed attempts after successful auth
287
+ */
288
+ resetFailedAttempts(agentId) {
289
+ const entry = this.limits.get(agentId);
290
+ if (entry) {
291
+ entry.failedAttempts = 0;
292
+ entry.lockedUntil = null;
293
+ }
294
+ }
295
+ /**
296
+ * Get rate limit status for an agent
297
+ */
298
+ getStatus(agentId) {
299
+ return this.limits.get(agentId) || null;
300
+ }
301
+ }
302
+ exports.RateLimiter = RateLimiter;
303
+ class SecureAuditLogger {
304
+ config;
305
+ previousHash = '';
306
+ constructor(config = {}) {
307
+ this.config = { ...DEFAULT_CONFIG, ...config };
308
+ this.initializeLog();
309
+ }
310
+ initializeLog() {
311
+ const logPath = this.config.auditLogPath;
312
+ if (!(0, fs_1.existsSync)(logPath)) {
313
+ (0, fs_1.writeFileSync)(logPath, '');
314
+ }
315
+ else {
316
+ // Continue the hash chain from the last entry so integrity
317
+ // verification works across process restarts.
318
+ try {
319
+ const content = (0, fs_1.readFileSync)(logPath, 'utf-8').trim();
320
+ if (content) {
321
+ const lines = content.split('\n').filter((l) => l);
322
+ const lastLine = lines[lines.length - 1];
323
+ const lastEntry = JSON.parse(lastLine);
324
+ if (lastEntry.signature) {
325
+ this.previousHash = lastEntry.signature;
326
+ }
327
+ }
328
+ }
329
+ catch {
330
+ // If we can't read the last entry, start fresh chain
331
+ }
332
+ }
333
+ }
334
+ /**
335
+ * Log a security event with cryptographic integrity
336
+ */
337
+ log(eventType, agentId, action, outcome, details = {}, resource) {
338
+ const entry = {
339
+ timestamp: new Date().toISOString(),
340
+ eventId: (0, crypto_1.randomBytes)(8).toString('hex'),
341
+ eventType,
342
+ agentId: InputSanitizer.sanitizeAgentId(agentId),
343
+ action,
344
+ resource,
345
+ outcome,
346
+ details: InputSanitizer.sanitizeObject(details),
347
+ };
348
+ // Sign the entry if configured
349
+ if (this.config.signAuditLogs) {
350
+ const payload = JSON.stringify({
351
+ ...entry,
352
+ previousHash: this.previousHash,
353
+ });
354
+ entry.signature = (0, crypto_1.createHmac)('sha256', this.config.tokenSecret)
355
+ .update(payload)
356
+ .digest('hex');
357
+ this.previousHash = entry.signature ?? '';
358
+ }
359
+ // Append to log file
360
+ const logLine = JSON.stringify(entry) + '\n';
361
+ (0, fs_1.appendFileSync)(this.config.auditLogPath, logLine);
362
+ return entry;
363
+ }
364
+ /**
365
+ * Log a permission request
366
+ */
367
+ logPermissionRequest(agentId, resourceType, scope, granted, reason) {
368
+ this.log('PERMISSION_REQUEST', agentId, `request_${resourceType}`, granted ? 'success' : 'denied', { resourceType, scope, reason }, resourceType);
369
+ }
370
+ /**
371
+ * Log a security violation
372
+ */
373
+ logViolation(agentId, violationType, details) {
374
+ this.log('SECURITY_VIOLATION', agentId, violationType, 'denied', details);
375
+ }
376
+ /**
377
+ * Verify audit log integrity
378
+ */
379
+ verifyLogIntegrity() {
380
+ const logContent = (0, fs_1.readFileSync)(this.config.auditLogPath, 'utf-8');
381
+ const lines = logContent.trim().split('\n').filter((l) => l);
382
+ let previousHash = '';
383
+ const invalidEntries = [];
384
+ for (let i = 0; i < lines.length; i++) {
385
+ try {
386
+ const entry = JSON.parse(lines[i]);
387
+ if (entry.signature) {
388
+ const { signature, ...rest } = entry;
389
+ const payload = JSON.stringify({
390
+ ...rest,
391
+ previousHash,
392
+ });
393
+ const expectedSignature = (0, crypto_1.createHmac)('sha256', this.config.tokenSecret)
394
+ .update(payload)
395
+ .digest('hex');
396
+ if (signature !== expectedSignature) {
397
+ invalidEntries.push(i);
398
+ }
399
+ previousHash = signature;
400
+ }
401
+ }
402
+ catch {
403
+ invalidEntries.push(i);
404
+ }
405
+ }
406
+ return {
407
+ valid: invalidEntries.length === 0,
408
+ invalidEntries,
409
+ };
410
+ }
411
+ }
412
+ exports.SecureAuditLogger = SecureAuditLogger;
413
+ // ============================================================================
414
+ // 5. DATA ENCRYPTION
415
+ // ============================================================================
416
+ class DataEncryptor {
417
+ key;
418
+ algorithm = 'aes-256-gcm';
419
+ constructor(encryptionKey) {
420
+ // Derive a proper key from the provided key
421
+ this.key = (0, crypto_1.scryptSync)(encryptionKey, 'swarm-salt', 32);
422
+ }
423
+ /**
424
+ * Encrypt sensitive data
425
+ */
426
+ encrypt(data) {
427
+ const iv = (0, crypto_1.randomBytes)(16);
428
+ const cipher = (0, crypto_1.createCipheriv)(this.algorithm, this.key, iv);
429
+ let encrypted = cipher.update(data, 'utf8', 'hex');
430
+ encrypted += cipher.final('hex');
431
+ const authTag = cipher.getAuthTag();
432
+ // Return iv:authTag:encryptedData
433
+ return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
434
+ }
435
+ /**
436
+ * Decrypt sensitive data
437
+ */
438
+ decrypt(encryptedData) {
439
+ const parts = encryptedData.split(':');
440
+ if (parts.length !== 3) {
441
+ throw new SecurityError('Invalid encrypted data format', 'INVALID_ENCRYPTED_FORMAT');
442
+ }
443
+ const [ivHex, authTagHex, encrypted] = parts;
444
+ const iv = Buffer.from(ivHex, 'hex');
445
+ const authTag = Buffer.from(authTagHex, 'hex');
446
+ const decipher = (0, crypto_1.createDecipheriv)(this.algorithm, this.key, iv);
447
+ decipher.setAuthTag(authTag);
448
+ let decrypted = decipher.update(encrypted, 'hex', 'utf8');
449
+ decrypted += decipher.final('utf8');
450
+ return decrypted;
451
+ }
452
+ /**
453
+ * Encrypt an object
454
+ */
455
+ encryptObject(obj) {
456
+ return this.encrypt(JSON.stringify(obj));
457
+ }
458
+ /**
459
+ * Decrypt to object
460
+ */
461
+ decryptObject(encryptedData) {
462
+ return JSON.parse(this.decrypt(encryptedData));
463
+ }
464
+ }
465
+ exports.DataEncryptor = DataEncryptor;
466
+ class PermissionHardener {
467
+ trustPolicies = new Map();
468
+ auditLogger;
469
+ constructor(auditLogger, defaultPolicies) {
470
+ this.auditLogger = auditLogger;
471
+ this.initializeDefaultPolicies(defaultPolicies);
472
+ }
473
+ initializeDefaultPolicies(customPolicies) {
474
+ if (customPolicies && customPolicies.length > 0) {
475
+ for (const policy of customPolicies) {
476
+ this.trustPolicies.set(policy.agentId, {
477
+ agentId: policy.agentId,
478
+ trustLevel: policy.trustLevel,
479
+ allowedResources: policy.allowedResources,
480
+ maxScope: policy.maxScope ?? ['read'],
481
+ createdBy: 'SYSTEM',
482
+ immutable: policy.immutable ?? false,
483
+ });
484
+ }
485
+ return;
486
+ }
487
+ // Fallback: universal defaults that cover common domains
488
+ this.trustPolicies.set('orchestrator', {
489
+ agentId: 'orchestrator',
490
+ trustLevel: 0.9,
491
+ allowedResources: ['*'],
492
+ maxScope: ['read', 'write', 'execute', 'delegate'],
493
+ createdBy: 'SYSTEM',
494
+ immutable: true,
495
+ });
496
+ }
497
+ /**
498
+ * Register or update a trust policy for an agent at runtime.
499
+ */
500
+ registerPolicy(policy) {
501
+ const existing = this.trustPolicies.get(policy.agentId);
502
+ if (existing?.immutable)
503
+ return; // Cannot overwrite immutable policies
504
+ this.trustPolicies.set(policy.agentId, {
505
+ agentId: policy.agentId,
506
+ trustLevel: policy.trustLevel,
507
+ allowedResources: policy.allowedResources,
508
+ maxScope: policy.maxScope ?? ['read'],
509
+ createdBy: 'RUNTIME',
510
+ immutable: policy.immutable ?? false,
511
+ });
512
+ }
513
+ /**
514
+ * Check if an agent can access a resource
515
+ */
516
+ canAccess(agentId, resourceType, requestedScope) {
517
+ const policy = this.trustPolicies.get(agentId);
518
+ if (!policy) {
519
+ this.auditLogger.logViolation(agentId, 'UNKNOWN_AGENT', { resourceType, requestedScope });
520
+ return { allowed: false, reason: 'Agent has no trust policy' };
521
+ }
522
+ // Check resource access (support '*' wildcard)
523
+ if (!policy.allowedResources.includes('*') && !policy.allowedResources.includes(resourceType)) {
524
+ this.auditLogger.logViolation(agentId, 'RESOURCE_NOT_ALLOWED', {
525
+ resourceType,
526
+ allowedResources: policy.allowedResources
527
+ });
528
+ return { allowed: false, reason: `Agent not allowed to access ${resourceType}` };
529
+ }
530
+ // Check scope
531
+ const scopeMatch = policy.maxScope.some(s => requestedScope.startsWith(s));
532
+ if (!scopeMatch) {
533
+ this.auditLogger.logViolation(agentId, 'SCOPE_EXCEEDED', {
534
+ requestedScope,
535
+ maxScope: policy.maxScope,
536
+ });
537
+ return { allowed: false, reason: 'Requested scope exceeds allowed scope' };
538
+ }
539
+ return { allowed: true };
540
+ }
541
+ /**
542
+ * Attempt to modify trust level (with escalation prevention)
543
+ */
544
+ modifyTrustLevel(requestingAgent, targetAgent, newTrustLevel) {
545
+ const requestorPolicy = this.trustPolicies.get(requestingAgent);
546
+ const targetPolicy = this.trustPolicies.get(targetAgent);
547
+ // Only orchestrator can modify trust
548
+ if (requestingAgent !== 'orchestrator') {
549
+ this.auditLogger.logViolation(requestingAgent, 'UNAUTHORIZED_TRUST_MODIFICATION', {
550
+ targetAgent,
551
+ attemptedTrustLevel: newTrustLevel,
552
+ });
553
+ return { success: false, reason: 'Only orchestrator can modify trust levels' };
554
+ }
555
+ // Cannot modify immutable policies
556
+ if (targetPolicy?.immutable) {
557
+ return { success: false, reason: 'Cannot modify immutable policy' };
558
+ }
559
+ // Cannot set trust higher than your own
560
+ if (requestorPolicy && newTrustLevel > requestorPolicy.trustLevel) {
561
+ this.auditLogger.logViolation(requestingAgent, 'PRIVILEGE_ESCALATION_ATTEMPT', {
562
+ targetAgent,
563
+ attemptedTrustLevel: newTrustLevel,
564
+ requestorTrustLevel: requestorPolicy.trustLevel,
565
+ });
566
+ return { success: false, reason: 'Cannot grant trust level higher than your own' };
567
+ }
568
+ // Apply the modification
569
+ if (targetPolicy) {
570
+ targetPolicy.trustLevel = newTrustLevel;
571
+ }
572
+ else {
573
+ this.trustPolicies.set(targetAgent, {
574
+ agentId: targetAgent,
575
+ trustLevel: newTrustLevel,
576
+ allowedResources: [],
577
+ maxScope: ['read'],
578
+ createdBy: requestingAgent,
579
+ immutable: false,
580
+ });
581
+ }
582
+ return { success: true };
583
+ }
584
+ /**
585
+ * Get policy for an agent
586
+ */
587
+ getPolicy(agentId) {
588
+ return this.trustPolicies.get(agentId);
589
+ }
590
+ }
591
+ exports.PermissionHardener = PermissionHardener;
592
+ // ============================================================================
593
+ // 7. SECURITY ERROR CLASS
594
+ // ============================================================================
595
+ class SecurityError extends Error {
596
+ code;
597
+ constructor(message, code) {
598
+ super(message);
599
+ this.name = 'SecurityError';
600
+ this.code = code;
601
+ }
602
+ }
603
+ exports.SecurityError = SecurityError;
604
+ // ============================================================================
605
+ // 8. SECURE SWARM GATEWAY (Integration Point)
606
+ // ============================================================================
607
+ class SecureSwarmGateway {
608
+ tokenManager;
609
+ rateLimiter;
610
+ auditLogger;
611
+ permissionHardener;
612
+ encryptor;
613
+ constructor(config = {}) {
614
+ const fullConfig = { ...DEFAULT_CONFIG, ...config };
615
+ this.tokenManager = new SecureTokenManager(fullConfig);
616
+ this.rateLimiter = new RateLimiter(fullConfig);
617
+ this.auditLogger = new SecureAuditLogger(fullConfig);
618
+ this.permissionHardener = new PermissionHardener(this.auditLogger);
619
+ this.encryptor = new DataEncryptor(fullConfig.encryptionKey);
620
+ }
621
+ /**
622
+ * Secure request handler - validates all security requirements
623
+ */
624
+ async handleSecureRequest(agentId, action, params, token) {
625
+ // 1. Sanitize agent ID
626
+ let sanitizedAgentId;
627
+ try {
628
+ sanitizedAgentId = InputSanitizer.sanitizeAgentId(agentId);
629
+ }
630
+ catch (error) {
631
+ this.auditLogger.logViolation(agentId, 'INVALID_AGENT_ID', { error: String(error) });
632
+ return { allowed: false, reason: 'Invalid agent ID' };
633
+ }
634
+ // 2. Check rate limit
635
+ const rateLimit = this.rateLimiter.isRateLimited(sanitizedAgentId);
636
+ if (rateLimit.limited) {
637
+ this.auditLogger.log('RATE_LIMITED', sanitizedAgentId, action, 'denied', {
638
+ retryAfter: rateLimit.retryAfter,
639
+ });
640
+ return { allowed: false, reason: `Rate limited. Retry after ${rateLimit.retryAfter}s` };
641
+ }
642
+ // 3. Validate token if provided
643
+ if (token) {
644
+ const tokenValidation = this.tokenManager.validateToken(token);
645
+ if (!tokenValidation.valid) {
646
+ const failedAuth = this.rateLimiter.recordFailedAuth(sanitizedAgentId);
647
+ this.auditLogger.log('TOKEN_VALIDATION_FAILED', sanitizedAgentId, action, 'denied', {
648
+ reason: tokenValidation.reason,
649
+ locked: failedAuth.locked,
650
+ });
651
+ if (failedAuth.locked) {
652
+ return { allowed: false, reason: 'Account locked due to failed authentication attempts' };
653
+ }
654
+ return { allowed: false, reason: tokenValidation.reason };
655
+ }
656
+ // Reset failed attempts on successful validation
657
+ this.rateLimiter.resetFailedAttempts(sanitizedAgentId);
658
+ }
659
+ // 4. Sanitize parameters
660
+ let sanitizedParams;
661
+ try {
662
+ sanitizedParams = InputSanitizer.sanitizeObject(params);
663
+ }
664
+ catch (error) {
665
+ this.auditLogger.logViolation(sanitizedAgentId, 'MALICIOUS_INPUT', {
666
+ action,
667
+ error: String(error),
668
+ });
669
+ return { allowed: false, reason: 'Invalid input parameters' };
670
+ }
671
+ // 5. Log successful request
672
+ this.auditLogger.log('REQUEST_PROCESSED', sanitizedAgentId, action, 'success', {
673
+ paramKeys: Object.keys(sanitizedParams),
674
+ });
675
+ return { allowed: true, sanitizedParams };
676
+ }
677
+ /**
678
+ * Request a new permission grant
679
+ */
680
+ async requestPermission(agentId, resourceType, scope, justification) {
681
+ const sanitizedAgentId = InputSanitizer.sanitizeAgentId(agentId);
682
+ // Check if agent can access this resource
683
+ const accessCheck = this.permissionHardener.canAccess(sanitizedAgentId, resourceType, scope);
684
+ if (!accessCheck.allowed) {
685
+ this.auditLogger.logPermissionRequest(sanitizedAgentId, resourceType, scope, false, accessCheck.reason);
686
+ return { granted: false, reason: accessCheck.reason };
687
+ }
688
+ // Generate secure token
689
+ const token = this.tokenManager.generateToken(sanitizedAgentId, resourceType, scope);
690
+ this.auditLogger.logPermissionRequest(sanitizedAgentId, resourceType, scope, true);
691
+ return { granted: true, token };
692
+ }
693
+ /**
694
+ * Encrypt sensitive data for blackboard storage
695
+ */
696
+ encryptSensitiveData(data) {
697
+ return this.encryptor.encryptObject(data);
698
+ }
699
+ /**
700
+ * Decrypt sensitive data from blackboard
701
+ */
702
+ decryptSensitiveData(encryptedData) {
703
+ return this.encryptor.decryptObject(encryptedData);
704
+ }
705
+ /**
706
+ * Verify audit log integrity
707
+ */
708
+ verifyAuditIntegrity() {
709
+ return this.auditLogger.verifyLogIntegrity();
710
+ }
711
+ }
712
+ exports.SecureSwarmGateway = SecureSwarmGateway;
713
+ //# sourceMappingURL=security.js.map