agentshield-sdk 7.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 (84) hide show
  1. package/CHANGELOG.md +191 -0
  2. package/LICENSE +21 -0
  3. package/README.md +975 -0
  4. package/bin/agent-shield.js +680 -0
  5. package/package.json +118 -0
  6. package/src/adaptive.js +330 -0
  7. package/src/agent-protocol.js +998 -0
  8. package/src/alert-tuning.js +480 -0
  9. package/src/allowlist.js +603 -0
  10. package/src/audit-immutable.js +914 -0
  11. package/src/audit-streaming.js +469 -0
  12. package/src/badges.js +196 -0
  13. package/src/behavior-profiling.js +289 -0
  14. package/src/benchmark-harness.js +804 -0
  15. package/src/canary.js +271 -0
  16. package/src/certification.js +563 -0
  17. package/src/circuit-breaker.js +321 -0
  18. package/src/compliance.js +617 -0
  19. package/src/confidence-tuning.js +324 -0
  20. package/src/confused-deputy.js +624 -0
  21. package/src/context-scoring.js +360 -0
  22. package/src/conversation.js +494 -0
  23. package/src/cost-optimizer.js +1024 -0
  24. package/src/ctf.js +462 -0
  25. package/src/detector-core.js +1999 -0
  26. package/src/distributed.js +359 -0
  27. package/src/document-scanner.js +795 -0
  28. package/src/embedding.js +307 -0
  29. package/src/encoding.js +429 -0
  30. package/src/enterprise.js +405 -0
  31. package/src/errors.js +100 -0
  32. package/src/eu-ai-act.js +523 -0
  33. package/src/fuzzer.js +764 -0
  34. package/src/honeypot.js +328 -0
  35. package/src/i18n-patterns.js +523 -0
  36. package/src/index.js +430 -0
  37. package/src/integrations.js +528 -0
  38. package/src/llm-redteam.js +670 -0
  39. package/src/main.js +741 -0
  40. package/src/main.mjs +38 -0
  41. package/src/mcp-bridge.js +542 -0
  42. package/src/mcp-certification.js +846 -0
  43. package/src/mcp-sdk-integration.js +355 -0
  44. package/src/mcp-security-runtime.js +741 -0
  45. package/src/mcp-server.js +740 -0
  46. package/src/middleware.js +208 -0
  47. package/src/model-finetuning.js +884 -0
  48. package/src/model-fingerprint.js +1042 -0
  49. package/src/multi-agent-trust.js +453 -0
  50. package/src/multi-agent.js +404 -0
  51. package/src/multimodal.js +296 -0
  52. package/src/nist-mapping.js +505 -0
  53. package/src/observability.js +330 -0
  54. package/src/openclaw.js +450 -0
  55. package/src/otel.js +544 -0
  56. package/src/owasp-2025.js +483 -0
  57. package/src/pii.js +390 -0
  58. package/src/plugin-marketplace.js +628 -0
  59. package/src/plugin-system.js +349 -0
  60. package/src/policy-dsl.js +775 -0
  61. package/src/policy-extended.js +635 -0
  62. package/src/policy.js +443 -0
  63. package/src/presets.js +409 -0
  64. package/src/production.js +557 -0
  65. package/src/prompt-leakage.js +321 -0
  66. package/src/rag-vulnerability.js +579 -0
  67. package/src/redteam.js +475 -0
  68. package/src/response-handler.js +429 -0
  69. package/src/scanners.js +357 -0
  70. package/src/self-healing.js +363 -0
  71. package/src/semantic.js +339 -0
  72. package/src/shield-score.js +250 -0
  73. package/src/sso-saml.js +897 -0
  74. package/src/stream-scanner.js +806 -0
  75. package/src/testing.js +505 -0
  76. package/src/threat-encyclopedia.js +629 -0
  77. package/src/threat-intel-network.js +1017 -0
  78. package/src/token-analysis.js +467 -0
  79. package/src/tool-guard.js +412 -0
  80. package/src/tool-output-validator.js +354 -0
  81. package/src/utils.js +83 -0
  82. package/src/watermark.js +235 -0
  83. package/src/worker-scanner.js +601 -0
  84. package/types/index.d.ts +2088 -0
@@ -0,0 +1,405 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Agent Shield — Enterprise Features
5
+ *
6
+ * - Multi-tenant support
7
+ * - Role-based policies
8
+ * - Debug mode with detailed traces
9
+ * - Policy inheritance and overrides
10
+ */
11
+
12
+ const { AgentShield } = require('./index');
13
+ const { loadPolicy } = require('./policy');
14
+
15
+ // =========================================================================
16
+ // Multi-Tenant Shield
17
+ // =========================================================================
18
+
19
+ class MultiTenantShield {
20
+ constructor(options = {}) {
21
+ this.tenants = new Map();
22
+ this.defaultPolicy = options.defaultPolicy || { sensitivity: 'high', blockOnThreat: true };
23
+ this.globalOverrides = options.globalOverrides || {};
24
+ this.onTenantCreated = options.onTenantCreated || null;
25
+ }
26
+
27
+ /**
28
+ * Register a tenant with its own policy.
29
+ */
30
+ registerTenant(tenantId, policy = {}) {
31
+ const mergedPolicy = { ...this.defaultPolicy, ...policy, ...this.globalOverrides };
32
+ const shield = new AgentShield(mergedPolicy);
33
+
34
+ this.tenants.set(tenantId, {
35
+ id: tenantId,
36
+ policy: mergedPolicy,
37
+ shield,
38
+ stats: { scans: 0, threats: 0, blocked: 0 },
39
+ createdAt: new Date().toISOString()
40
+ });
41
+
42
+ if (this.onTenantCreated) {
43
+ this.onTenantCreated(tenantId, mergedPolicy);
44
+ }
45
+
46
+ return this;
47
+ }
48
+
49
+ /**
50
+ * Get or auto-create a tenant shield.
51
+ */
52
+ getTenant(tenantId) {
53
+ if (!this.tenants.has(tenantId)) {
54
+ this.registerTenant(tenantId);
55
+ }
56
+ return this.tenants.get(tenantId);
57
+ }
58
+
59
+ /**
60
+ * Scan input for a specific tenant.
61
+ */
62
+ scan(tenantId, text, options = {}) {
63
+ const tenant = this.getTenant(tenantId);
64
+ tenant.stats.scans++;
65
+
66
+ const result = tenant.shield.scan(text, options);
67
+
68
+ if (result.threats.length > 0) {
69
+ tenant.stats.threats += result.threats.length;
70
+ }
71
+ if (result.blocked) {
72
+ tenant.stats.blocked++;
73
+ }
74
+
75
+ return { ...result, tenantId };
76
+ }
77
+
78
+ /**
79
+ * Scan input for a specific tenant.
80
+ */
81
+ scanInput(tenantId, text) {
82
+ return this.scan(tenantId, text);
83
+ }
84
+
85
+ /**
86
+ * Scan output for a specific tenant.
87
+ */
88
+ scanOutput(tenantId, text) {
89
+ const tenant = this.getTenant(tenantId);
90
+ return tenant.shield.scanOutput(text);
91
+ }
92
+
93
+ /**
94
+ * Update a tenant's policy.
95
+ */
96
+ updatePolicy(tenantId, policy) {
97
+ const tenant = this.getTenant(tenantId);
98
+ tenant.policy = { ...tenant.policy, ...policy, ...this.globalOverrides };
99
+ tenant.shield = new AgentShield(tenant.policy);
100
+ return tenant.policy;
101
+ }
102
+
103
+ /**
104
+ * Get stats for all tenants.
105
+ */
106
+ getAllStats() {
107
+ const stats = {};
108
+ for (const [id, tenant] of this.tenants) {
109
+ stats[id] = { ...tenant.stats, policy: tenant.policy };
110
+ }
111
+ return stats;
112
+ }
113
+
114
+ /**
115
+ * Remove a tenant.
116
+ */
117
+ removeTenant(tenantId) {
118
+ return this.tenants.delete(tenantId);
119
+ }
120
+
121
+ /**
122
+ * Get tenant count.
123
+ */
124
+ get size() {
125
+ return this.tenants.size;
126
+ }
127
+ }
128
+
129
+ // =========================================================================
130
+ // Role-Based Policies
131
+ // =========================================================================
132
+
133
+ const DEFAULT_ROLES = {
134
+ admin: {
135
+ name: 'Administrator',
136
+ sensitivity: 'medium',
137
+ blockOnThreat: false,
138
+ allowedTools: '*',
139
+ blockedTools: [],
140
+ bypassCircuitBreaker: true,
141
+ canViewAuditTrail: true,
142
+ canModifyPolicy: true
143
+ },
144
+ operator: {
145
+ name: 'Operator',
146
+ sensitivity: 'high',
147
+ blockOnThreat: true,
148
+ allowedTools: ['search', 'readFile', 'calculator'],
149
+ blockedTools: ['bash', 'shell', 'exec'],
150
+ bypassCircuitBreaker: false,
151
+ canViewAuditTrail: true,
152
+ canModifyPolicy: false
153
+ },
154
+ user: {
155
+ name: 'Standard User',
156
+ sensitivity: 'high',
157
+ blockOnThreat: true,
158
+ allowedTools: ['search', 'calculator'],
159
+ blockedTools: ['bash', 'shell', 'exec', 'readFile', 'writeFile'],
160
+ bypassCircuitBreaker: false,
161
+ canViewAuditTrail: false,
162
+ canModifyPolicy: false
163
+ },
164
+ restricted: {
165
+ name: 'Restricted User',
166
+ sensitivity: 'high',
167
+ blockOnThreat: true,
168
+ blockThreshold: 'low',
169
+ allowedTools: [],
170
+ blockedTools: '*',
171
+ bypassCircuitBreaker: false,
172
+ canViewAuditTrail: false,
173
+ canModifyPolicy: false
174
+ }
175
+ };
176
+
177
+ class RoleBasedPolicy {
178
+ constructor(options = {}) {
179
+ this.roles = { ...DEFAULT_ROLES, ...(options.customRoles || {}) };
180
+ this.userRoles = new Map();
181
+ this.shields = new Map();
182
+ }
183
+
184
+ /**
185
+ * Assign a role to a user.
186
+ */
187
+ assignRole(userId, role) {
188
+ if (!this.roles[role]) {
189
+ throw new Error(`Unknown role: ${role}. Available: ${Object.keys(this.roles).join(', ')}`);
190
+ }
191
+ this.userRoles.set(userId, role);
192
+
193
+ // Create a shield for this role if not exists
194
+ if (!this.shields.has(role)) {
195
+ const roleConfig = this.roles[role];
196
+ this.shields.set(role, new AgentShield({
197
+ sensitivity: roleConfig.sensitivity,
198
+ blockOnThreat: roleConfig.blockOnThreat,
199
+ blockThreshold: roleConfig.blockThreshold
200
+ }));
201
+ }
202
+
203
+ return this;
204
+ }
205
+
206
+ /**
207
+ * Get the effective policy for a user.
208
+ */
209
+ getPolicy(userId) {
210
+ const role = this.userRoles.get(userId) || 'user';
211
+ return { role, ...this.roles[role] };
212
+ }
213
+
214
+ /**
215
+ * Scan input with the user's role-based policy.
216
+ */
217
+ scan(userId, text, options = {}) {
218
+ const role = this.userRoles.get(userId) || 'user';
219
+
220
+ // Reuse shield created in assignRole, or create lazily
221
+ if (!this.shields.has(role)) {
222
+ this.assignRole(userId, role);
223
+ }
224
+
225
+ const result = this.shields.get(role).scan(text, options);
226
+ return { ...result, userId, role };
227
+ }
228
+
229
+ /**
230
+ * Check if a user can use a specific tool.
231
+ */
232
+ checkToolAccess(userId, toolName) {
233
+ const role = this.userRoles.get(userId) || 'user';
234
+ const roleConfig = this.roles[role];
235
+
236
+ if (roleConfig.blockedTools === '*') return { allowed: false, reason: 'All tools blocked for this role' };
237
+ if (Array.isArray(roleConfig.blockedTools) && roleConfig.blockedTools.includes(toolName)) {
238
+ return { allowed: false, reason: `Tool "${toolName}" is blocked for role "${role}"` };
239
+ }
240
+
241
+ if (roleConfig.allowedTools === '*') return { allowed: true };
242
+ if (Array.isArray(roleConfig.allowedTools) && roleConfig.allowedTools.includes(toolName)) {
243
+ return { allowed: true };
244
+ }
245
+
246
+ return { allowed: false, reason: `Tool "${toolName}" is not in the allowed list for role "${role}"` };
247
+ }
248
+
249
+ /**
250
+ * Define a custom role.
251
+ */
252
+ defineRole(name, config) {
253
+ this.roles[name] = { name: config.name || name, ...config };
254
+ return this;
255
+ }
256
+
257
+ /**
258
+ * Get all available roles.
259
+ */
260
+ getRoles() {
261
+ return Object.entries(this.roles).map(([key, val]) => ({ key, ...val }));
262
+ }
263
+ }
264
+
265
+ // =========================================================================
266
+ // Debug Mode
267
+ // =========================================================================
268
+
269
+ class DebugShield {
270
+ constructor(options = {}) {
271
+ this.shield = new AgentShield(options);
272
+ this.traces = [];
273
+ this.enabled = options.debug !== false;
274
+ this.maxTraces = options.maxTraces || 1000;
275
+ this.verbose = options.verbose || false;
276
+ }
277
+
278
+ /**
279
+ * Scan with full debug trace.
280
+ */
281
+ scan(text, options = {}) {
282
+ const startTime = this.enabled ? process.hrtime.bigint() : null;
283
+
284
+ // Scan
285
+ const result = this.shield.scan(text, options);
286
+
287
+ // Only build trace if debug is enabled
288
+ let trace = null;
289
+ if (this.enabled) {
290
+ const endTime = process.hrtime.bigint();
291
+ const elapsedMs = Number(endTime - startTime) / 1e6;
292
+
293
+ trace = {
294
+ id: `trace_${Date.now()}_${Math.random().toString(36).slice(2, 8).padEnd(6, '0')}`,
295
+ timestamp: new Date().toISOString(),
296
+ input: text.substring(0, 500),
297
+ inputLength: text.length,
298
+ options,
299
+ steps: [
300
+ {
301
+ step: 'input_received',
302
+ time: 0,
303
+ detail: { length: text.length, hasUnicode: /[^\x00-\x7F]/.test(text) }
304
+ },
305
+ {
306
+ step: 'pattern_matching',
307
+ time: elapsedMs,
308
+ detail: {
309
+ patternsChecked: this.shield.getPatterns().length,
310
+ threatsFound: result.threats.length,
311
+ threats: result.threats.map(t => ({
312
+ severity: t.severity,
313
+ category: t.category,
314
+ description: t.description,
315
+ confidence: t.confidence
316
+ }))
317
+ }
318
+ },
319
+ {
320
+ step: 'decision',
321
+ time: elapsedMs,
322
+ detail: {
323
+ status: result.status,
324
+ blocked: result.blocked,
325
+ threatCount: result.threats.length
326
+ }
327
+ }
328
+ ],
329
+ totalTimeMs: parseFloat(elapsedMs.toFixed(3)),
330
+ result: {
331
+ status: result.status,
332
+ blocked: result.blocked,
333
+ threatCount: result.threats.length
334
+ }
335
+ };
336
+
337
+ this.traces.push(trace);
338
+ while (this.traces.length > this.maxTraces) {
339
+ this.traces.shift();
340
+ }
341
+ }
342
+
343
+ if (this.verbose) {
344
+ const ms = trace ? trace.totalTimeMs : 0;
345
+ console.log(`[Agent Shield] DEBUG Scan: ${text.substring(0, 50)}... → ${result.status} (${ms.toFixed(1)}ms, ${result.threats.length} threats)`);
346
+ }
347
+
348
+ return { ...result, _trace: trace };
349
+ }
350
+
351
+ /**
352
+ * Get all traces.
353
+ */
354
+ getTraces() {
355
+ return this.traces;
356
+ }
357
+
358
+ /**
359
+ * Get the last N traces.
360
+ */
361
+ getRecentTraces(n = 10) {
362
+ return this.traces.slice(-n);
363
+ }
364
+
365
+ /**
366
+ * Export traces as JSON.
367
+ */
368
+ exportTraces() {
369
+ return JSON.stringify(this.traces, null, 2);
370
+ }
371
+
372
+ /**
373
+ * Clear traces.
374
+ */
375
+ clearTraces() {
376
+ this.traces = [];
377
+ }
378
+
379
+ /**
380
+ * Get timing statistics across all traces.
381
+ */
382
+ getTimingStats() {
383
+ if (this.traces.length === 0) return null;
384
+
385
+ const times = this.traces.map(t => t.totalTimeMs);
386
+ times.sort((a, b) => a - b);
387
+
388
+ return {
389
+ count: times.length,
390
+ min: times[0],
391
+ max: times[times.length - 1],
392
+ avg: parseFloat((times.reduce((a, b) => a + b, 0) / times.length).toFixed(3)),
393
+ median: times[Math.floor(times.length / 2)],
394
+ p95: times[Math.min(Math.floor(times.length * 0.95), times.length - 1)],
395
+ p99: times[Math.min(Math.floor(times.length * 0.99), times.length - 1)]
396
+ };
397
+ }
398
+ }
399
+
400
+ module.exports = {
401
+ MultiTenantShield,
402
+ RoleBasedPolicy,
403
+ DebugShield,
404
+ DEFAULT_ROLES
405
+ };
package/src/errors.js ADDED
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Structured error codes for Agent Shield
5
+ * Format: AS-{CATEGORY}-{NUMBER}
6
+ *
7
+ * Categories:
8
+ * DET — Detection engine errors
9
+ * CFG — Configuration errors
10
+ * PLG — Plugin errors
11
+ * INT — Integration errors
12
+ * POL — Policy errors
13
+ * NET — Network/distributed errors
14
+ * AUT — Authentication/authorization errors
15
+ */
16
+
17
+ const ERROR_CODES = {
18
+ // Detection
19
+ 'AS-DET-001': { message: 'Detection engine not initialized', severity: 'critical' },
20
+ 'AS-DET-002': { message: 'Invalid input type — expected string', severity: 'high' },
21
+ 'AS-DET-003': { message: 'Pattern compilation failed', severity: 'high' },
22
+ 'AS-DET-004': { message: 'Scan timeout exceeded', severity: 'medium' },
23
+ 'AS-DET-005': { message: 'Input exceeds maximum length', severity: 'medium' },
24
+
25
+ // Configuration
26
+ 'AS-CFG-001': { message: 'Invalid configuration object', severity: 'critical' },
27
+ 'AS-CFG-002': { message: 'Unknown configuration key', severity: 'low' },
28
+ 'AS-CFG-003': { message: 'Invalid threshold value — must be 0-1', severity: 'high' },
29
+ 'AS-CFG-004': { message: 'Preset not found', severity: 'medium' },
30
+
31
+ // Plugin
32
+ 'AS-PLG-001': { message: 'Plugin failed to load', severity: 'high' },
33
+ 'AS-PLG-002': { message: 'Plugin version incompatible', severity: 'high' },
34
+ 'AS-PLG-003': { message: 'Plugin hook threw an error', severity: 'medium' },
35
+
36
+ // Integration
37
+ 'AS-INT-001': { message: 'Framework adapter not found', severity: 'high' },
38
+ 'AS-INT-002': { message: 'Middleware setup failed', severity: 'critical' },
39
+ 'AS-INT-003': { message: 'Hook registration failed', severity: 'medium' },
40
+
41
+ // Policy
42
+ 'AS-POL-001': { message: 'Policy parse error', severity: 'critical' },
43
+ 'AS-POL-002': { message: 'Policy rule conflict detected', severity: 'high' },
44
+ 'AS-POL-003': { message: 'Policy file not found', severity: 'high' },
45
+
46
+ // Network/Distributed
47
+ 'AS-NET-001': { message: 'Distributed sync failed', severity: 'high' },
48
+ 'AS-NET-002': { message: 'Peer node unreachable', severity: 'medium' },
49
+
50
+ // Auth
51
+ 'AS-AUT-001': { message: 'RBAC permission denied', severity: 'high' },
52
+ 'AS-AUT-002': { message: 'Tenant not found', severity: 'high' },
53
+ 'AS-AUT-003': { message: 'SSO token validation failed', severity: 'critical' },
54
+ };
55
+
56
+ /**
57
+ * Create a structured AgentShield error
58
+ * @param {string} code - Error code (e.g., 'AS-DET-001')
59
+ * @param {Object} [details] - Additional context
60
+ * @returns {Error}
61
+ */
62
+ function createShieldError(code, details = {}) {
63
+ const entry = ERROR_CODES[code];
64
+ if (!entry) {
65
+ const err = new Error(`Unknown error code: ${code}`);
66
+ err.code = 'AS-CFG-002';
67
+ return err;
68
+ }
69
+ const err = new Error(`[Agent Shield ${code}] ${entry.message}`);
70
+ err.code = code;
71
+ err.severity = entry.severity;
72
+ err.details = details;
73
+ err.timestamp = Date.now();
74
+ return err;
75
+ }
76
+
77
+ /**
78
+ * Emit a deprecation warning (once per code)
79
+ * @param {string} feature - Deprecated feature name
80
+ * @param {string} replacement - Suggested replacement
81
+ * @param {string} removeVersion - Version when it will be removed
82
+ */
83
+ const _warned = new Set();
84
+ function deprecationWarning(feature, replacement, removeVersion) {
85
+ const key = `${feature}:${replacement}`;
86
+ if (_warned.has(key)) return;
87
+ _warned.add(key);
88
+ const msg = `[Agent Shield] DEPRECATED: "${feature}" is deprecated and will be removed in v${removeVersion}. Use "${replacement}" instead.`;
89
+ if (typeof process !== 'undefined' && process.emitWarning) {
90
+ process.emitWarning(msg, 'DeprecationWarning');
91
+ } else {
92
+ console.warn(msg); // [Agent Shield] prefix included in msg
93
+ }
94
+ }
95
+
96
+ module.exports = {
97
+ ERROR_CODES,
98
+ createShieldError,
99
+ deprecationWarning,
100
+ };