agentshield-sdk 10.0.0 → 12.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.
- package/CHANGELOG.md +88 -79
- package/README.md +252 -11
- package/package.json +3 -3
- package/src/agent-intent.js +359 -672
- package/src/attack-surface.js +408 -0
- package/src/continuous-security.js +237 -0
- package/src/cross-turn.js +215 -563
- package/src/detector-core.js +928 -1
- package/src/drift-monitor.js +18 -6
- package/src/ensemble.js +300 -409
- package/src/incident-response.js +265 -0
- package/src/intent-binding.js +314 -0
- package/src/intent-graph.js +381 -0
- package/src/main.js +143 -33
- package/src/mcp-guard.js +565 -3
- package/src/message-integrity.js +226 -0
- package/src/micro-model.js +199 -11
- package/src/ml-detector.js +110 -266
- package/src/normalizer.js +296 -604
- package/src/persistent-learning.js +104 -620
- package/src/prompt-hardening.js +195 -0
- package/src/redteam-cli.js +5 -4
- package/src/self-training.js +586 -631
- package/src/semantic-isolation.js +304 -0
- package/src/smart-config.js +557 -705
- package/src/sota-benchmark.js +749 -0
- package/src/supply-chain-scanner.js +199 -1
- package/types/index.d.ts +251 -580
package/src/smart-config.js
CHANGED
|
@@ -1,812 +1,664 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Agent Shield — Smart Configuration
|
|
4
|
+
* Agent Shield — Smart Configuration / Policy Engine (v12.0)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Auto-configures Agent Shield based on deployment context. Provides presets
|
|
7
|
+
* for common deployment scenarios (chatbot, coding agent, RAG pipeline,
|
|
8
|
+
* MCP server, enterprise, paranoid) and generates complete configurations
|
|
9
|
+
* with security recommendations.
|
|
8
10
|
*
|
|
9
|
-
*
|
|
10
|
-
* const { createShield } = require('agentshield-sdk');
|
|
11
|
-
* const shield = createShield('chatbot');
|
|
12
|
-
* const result = shield.scan(text);
|
|
13
|
-
*
|
|
14
|
-
* 2. Builder pattern:
|
|
15
|
-
* const shield = createShield()
|
|
16
|
-
* .preset('rag_pipeline')
|
|
17
|
-
* .enableIntent({ purpose: 'Answer questions from docs' })
|
|
18
|
-
* .enableLearning({ persist: true })
|
|
19
|
-
* .enableEnsemble()
|
|
20
|
-
* .build();
|
|
21
|
-
*
|
|
22
|
-
* 3. Config object:
|
|
23
|
-
* const shield = createShield({
|
|
24
|
-
* preset: 'high_security',
|
|
25
|
-
* intent: { purpose: 'Flight booking agent', allowedTools: ['searchFlights', 'bookFlight'] },
|
|
26
|
-
* learning: { persist: true, feedbackEnabled: true },
|
|
27
|
-
* ensemble: true,
|
|
28
|
-
* goalDrift: true,
|
|
29
|
-
* crossTurn: { windowSize: 20 },
|
|
30
|
-
* toolSequence: true,
|
|
31
|
-
* adaptiveThresholds: true
|
|
32
|
-
* });
|
|
11
|
+
* All processing runs locally — no data ever leaves your environment.
|
|
33
12
|
*
|
|
34
13
|
* @module smart-config
|
|
35
14
|
*/
|
|
36
15
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
'coding_agent',
|
|
41
|
-
'rag_pipeline',
|
|
42
|
-
'customer_support',
|
|
43
|
-
'internal_tool',
|
|
44
|
-
'multi_agent',
|
|
45
|
-
'high_security',
|
|
46
|
-
'minimal',
|
|
47
|
-
'mcp_server'
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
/** Valid sensitivity levels */
|
|
51
|
-
const VALID_SENSITIVITIES = ['low', 'medium', 'high'];
|
|
16
|
+
// =========================================================================
|
|
17
|
+
// DEPLOYMENT PRESETS
|
|
18
|
+
// =========================================================================
|
|
52
19
|
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Predefined deployment presets with tuned security settings.
|
|
22
|
+
* @type {Object<string, object>}
|
|
23
|
+
*/
|
|
24
|
+
const DEPLOYMENT_PRESETS = {
|
|
25
|
+
chatbot: {
|
|
26
|
+
name: 'Chatbot',
|
|
27
|
+
description: 'Customer-facing conversational agent with moderate security',
|
|
28
|
+
detection: {
|
|
29
|
+
enablePatternScanner: true,
|
|
30
|
+
enableMicroModel: true,
|
|
31
|
+
enableIntentGraph: false,
|
|
32
|
+
enableOWASP: false,
|
|
33
|
+
sensitivity: 'medium',
|
|
34
|
+
scanTimeout: 50
|
|
35
|
+
},
|
|
36
|
+
protection: {
|
|
37
|
+
blockOnThreat: true,
|
|
38
|
+
piiRedaction: true,
|
|
39
|
+
canaryTokens: false,
|
|
40
|
+
rateLimiting: true,
|
|
41
|
+
rateLimit: { maxRequests: 60, windowMs: 60000 },
|
|
42
|
+
circuitBreaker: { threshold: 10, resetMs: 30000 }
|
|
43
|
+
},
|
|
44
|
+
monitoring: {
|
|
45
|
+
auditLog: true,
|
|
46
|
+
metricsExport: false,
|
|
47
|
+
alerting: false,
|
|
48
|
+
shadowMode: false
|
|
49
|
+
},
|
|
50
|
+
compliance: {
|
|
51
|
+
frameworks: ['gdpr'],
|
|
52
|
+
dataRetention: '30d'
|
|
53
|
+
}
|
|
82
54
|
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
55
|
+
|
|
56
|
+
coding_agent: {
|
|
57
|
+
name: 'Coding Agent',
|
|
58
|
+
description: 'AI coding assistant with tool execution capabilities',
|
|
59
|
+
detection: {
|
|
60
|
+
enablePatternScanner: true,
|
|
61
|
+
enableMicroModel: true,
|
|
62
|
+
enableIntentGraph: true,
|
|
63
|
+
enableOWASP: true,
|
|
64
|
+
sensitivity: 'high',
|
|
65
|
+
scanTimeout: 100
|
|
66
|
+
},
|
|
67
|
+
protection: {
|
|
68
|
+
blockOnThreat: true,
|
|
69
|
+
piiRedaction: true,
|
|
70
|
+
canaryTokens: true,
|
|
71
|
+
rateLimiting: true,
|
|
72
|
+
rateLimit: { maxRequests: 120, windowMs: 60000 },
|
|
73
|
+
circuitBreaker: { threshold: 5, resetMs: 60000 },
|
|
74
|
+
toolGuard: {
|
|
75
|
+
enabled: true,
|
|
76
|
+
blockedTools: ['exec', 'shell', 'eval'],
|
|
77
|
+
requireApproval: ['writeFile', 'deleteFile', 'networkRequest'],
|
|
78
|
+
maxChainDepth: 5
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
monitoring: {
|
|
82
|
+
auditLog: true,
|
|
83
|
+
metricsExport: true,
|
|
84
|
+
alerting: true,
|
|
85
|
+
shadowMode: false
|
|
86
|
+
},
|
|
87
|
+
compliance: {
|
|
88
|
+
frameworks: ['soc2'],
|
|
89
|
+
dataRetention: '90d'
|
|
90
|
+
}
|
|
87
91
|
},
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
|
|
93
|
+
rag_pipeline: {
|
|
94
|
+
name: 'RAG Pipeline',
|
|
95
|
+
description: 'Retrieval-augmented generation with document ingestion',
|
|
96
|
+
detection: {
|
|
97
|
+
enablePatternScanner: true,
|
|
98
|
+
enableMicroModel: true,
|
|
99
|
+
enableIntentGraph: true,
|
|
100
|
+
enableOWASP: true,
|
|
101
|
+
sensitivity: 'high',
|
|
102
|
+
scanTimeout: 150,
|
|
103
|
+
enableIPIA: true,
|
|
104
|
+
enableDocumentScanner: true
|
|
105
|
+
},
|
|
106
|
+
protection: {
|
|
107
|
+
blockOnThreat: true,
|
|
108
|
+
piiRedaction: true,
|
|
109
|
+
canaryTokens: true,
|
|
110
|
+
rateLimiting: true,
|
|
111
|
+
rateLimit: { maxRequests: 30, windowMs: 60000 },
|
|
112
|
+
circuitBreaker: { threshold: 5, resetMs: 60000 },
|
|
113
|
+
semanticIsolation: {
|
|
114
|
+
enabled: true,
|
|
115
|
+
trustLevels: { system: 'trusted', user: 'semi-trusted', rag_chunk: 'untrusted' }
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
monitoring: {
|
|
119
|
+
auditLog: true,
|
|
120
|
+
metricsExport: true,
|
|
121
|
+
alerting: true,
|
|
122
|
+
shadowMode: false
|
|
123
|
+
},
|
|
124
|
+
compliance: {
|
|
125
|
+
frameworks: ['soc2', 'gdpr'],
|
|
126
|
+
dataRetention: '90d'
|
|
127
|
+
}
|
|
92
128
|
},
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
129
|
+
|
|
130
|
+
mcp_server: {
|
|
131
|
+
name: 'MCP Server',
|
|
132
|
+
description: 'Model Context Protocol server with tool exposure',
|
|
133
|
+
detection: {
|
|
134
|
+
enablePatternScanner: true,
|
|
135
|
+
enableMicroModel: true,
|
|
136
|
+
enableIntentGraph: true,
|
|
137
|
+
enableOWASP: true,
|
|
138
|
+
sensitivity: 'high',
|
|
139
|
+
scanTimeout: 100,
|
|
140
|
+
enableSupplyChainScan: true
|
|
141
|
+
},
|
|
142
|
+
protection: {
|
|
143
|
+
blockOnThreat: true,
|
|
144
|
+
piiRedaction: true,
|
|
145
|
+
canaryTokens: true,
|
|
146
|
+
rateLimiting: true,
|
|
147
|
+
rateLimit: { maxRequests: 100, windowMs: 60000 },
|
|
148
|
+
circuitBreaker: { threshold: 3, resetMs: 120000 },
|
|
149
|
+
mcpGuard: {
|
|
150
|
+
enabled: true,
|
|
151
|
+
attestation: true,
|
|
152
|
+
ssrfFirewall: true,
|
|
153
|
+
oauthEnforcement: true,
|
|
154
|
+
crossServerIsolation: true,
|
|
155
|
+
behaviorBaseline: true
|
|
156
|
+
},
|
|
157
|
+
intentBinding: { enabled: true },
|
|
158
|
+
messageIntegrity: { enabled: true }
|
|
159
|
+
},
|
|
160
|
+
monitoring: {
|
|
161
|
+
auditLog: true,
|
|
162
|
+
metricsExport: true,
|
|
163
|
+
alerting: true,
|
|
164
|
+
shadowMode: false,
|
|
165
|
+
driftMonitor: { enabled: true, windowSize: 100 }
|
|
166
|
+
},
|
|
167
|
+
compliance: {
|
|
168
|
+
frameworks: ['soc2', 'owasp-agentic'],
|
|
169
|
+
dataRetention: '180d'
|
|
170
|
+
}
|
|
97
171
|
},
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
172
|
+
|
|
173
|
+
enterprise: {
|
|
174
|
+
name: 'Enterprise',
|
|
175
|
+
description: 'Enterprise deployment with full security, compliance, and monitoring',
|
|
176
|
+
detection: {
|
|
177
|
+
enablePatternScanner: true,
|
|
178
|
+
enableMicroModel: true,
|
|
179
|
+
enableIntentGraph: true,
|
|
180
|
+
enableOWASP: true,
|
|
181
|
+
sensitivity: 'high',
|
|
182
|
+
scanTimeout: 200,
|
|
183
|
+
enableIPIA: true,
|
|
184
|
+
enableDocumentScanner: true,
|
|
185
|
+
enableSupplyChainScan: true
|
|
186
|
+
},
|
|
187
|
+
protection: {
|
|
188
|
+
blockOnThreat: true,
|
|
189
|
+
piiRedaction: true,
|
|
190
|
+
canaryTokens: true,
|
|
191
|
+
rateLimiting: true,
|
|
192
|
+
rateLimit: { maxRequests: 200, windowMs: 60000 },
|
|
193
|
+
circuitBreaker: { threshold: 5, resetMs: 60000 },
|
|
194
|
+
toolGuard: {
|
|
195
|
+
enabled: true,
|
|
196
|
+
blockedTools: ['exec', 'shell', 'eval'],
|
|
197
|
+
requireApproval: [],
|
|
198
|
+
maxChainDepth: 10
|
|
199
|
+
},
|
|
200
|
+
mcpGuard: {
|
|
201
|
+
enabled: true,
|
|
202
|
+
attestation: true,
|
|
203
|
+
ssrfFirewall: true,
|
|
204
|
+
oauthEnforcement: true,
|
|
205
|
+
crossServerIsolation: true,
|
|
206
|
+
behaviorBaseline: true
|
|
207
|
+
},
|
|
208
|
+
semanticIsolation: { enabled: true },
|
|
209
|
+
intentBinding: { enabled: true },
|
|
210
|
+
messageIntegrity: { enabled: true },
|
|
211
|
+
multiTenant: { enabled: true },
|
|
212
|
+
rbac: { enabled: true }
|
|
213
|
+
},
|
|
214
|
+
monitoring: {
|
|
215
|
+
auditLog: true,
|
|
216
|
+
metricsExport: true,
|
|
217
|
+
alerting: true,
|
|
218
|
+
shadowMode: false,
|
|
219
|
+
driftMonitor: { enabled: true, windowSize: 200 },
|
|
220
|
+
socIntegration: { enabled: true },
|
|
221
|
+
immutableAudit: { enabled: true }
|
|
222
|
+
},
|
|
223
|
+
compliance: {
|
|
224
|
+
frameworks: ['soc2', 'hipaa', 'gdpr', 'nist', 'owasp-agentic', 'eu-ai-act'],
|
|
225
|
+
dataRetention: '365d',
|
|
226
|
+
certificationLevel: 'gold'
|
|
227
|
+
}
|
|
102
228
|
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
229
|
+
|
|
230
|
+
paranoid: {
|
|
231
|
+
name: 'Paranoid',
|
|
232
|
+
description: 'Maximum security — all detectors, all protections, strictest thresholds',
|
|
233
|
+
detection: {
|
|
234
|
+
enablePatternScanner: true,
|
|
235
|
+
enableMicroModel: true,
|
|
236
|
+
enableIntentGraph: true,
|
|
237
|
+
enableOWASP: true,
|
|
238
|
+
sensitivity: 'critical',
|
|
239
|
+
scanTimeout: 500,
|
|
240
|
+
enableIPIA: true,
|
|
241
|
+
enableDocumentScanner: true,
|
|
242
|
+
enableSupplyChainScan: true,
|
|
243
|
+
enableBehaviorProfiling: true,
|
|
244
|
+
enableHoneypot: true,
|
|
245
|
+
enableSelfTraining: true,
|
|
246
|
+
enableAttackSurface: true
|
|
247
|
+
},
|
|
248
|
+
protection: {
|
|
249
|
+
blockOnThreat: true,
|
|
250
|
+
piiRedaction: true,
|
|
251
|
+
canaryTokens: true,
|
|
252
|
+
rateLimiting: true,
|
|
253
|
+
rateLimit: { maxRequests: 30, windowMs: 60000 },
|
|
254
|
+
circuitBreaker: { threshold: 2, resetMs: 300000 },
|
|
255
|
+
toolGuard: {
|
|
256
|
+
enabled: true,
|
|
257
|
+
blockedTools: ['exec', 'shell', 'eval', 'spawn', 'fork'],
|
|
258
|
+
requireApproval: ['writeFile', 'deleteFile', 'networkRequest', 'databaseQuery'],
|
|
259
|
+
maxChainDepth: 3
|
|
260
|
+
},
|
|
261
|
+
mcpGuard: {
|
|
262
|
+
enabled: true,
|
|
263
|
+
attestation: true,
|
|
264
|
+
ssrfFirewall: true,
|
|
265
|
+
oauthEnforcement: true,
|
|
266
|
+
crossServerIsolation: true,
|
|
267
|
+
behaviorBaseline: true
|
|
268
|
+
},
|
|
269
|
+
semanticIsolation: { enabled: true },
|
|
270
|
+
intentBinding: { enabled: true },
|
|
271
|
+
messageIntegrity: { enabled: true },
|
|
272
|
+
promptHardening: { enabled: true, level: 4 },
|
|
273
|
+
multiTenant: { enabled: true },
|
|
274
|
+
rbac: { enabled: true }
|
|
275
|
+
},
|
|
276
|
+
monitoring: {
|
|
277
|
+
auditLog: true,
|
|
278
|
+
metricsExport: true,
|
|
279
|
+
alerting: true,
|
|
280
|
+
shadowMode: true,
|
|
281
|
+
driftMonitor: { enabled: true, windowSize: 50 },
|
|
282
|
+
socIntegration: { enabled: true },
|
|
283
|
+
immutableAudit: { enabled: true },
|
|
284
|
+
continuousSecurity: { enabled: true, intervalMs: 60000 }
|
|
285
|
+
},
|
|
286
|
+
compliance: {
|
|
287
|
+
frameworks: ['soc2', 'hipaa', 'gdpr', 'nist', 'owasp-agentic', 'eu-ai-act'],
|
|
288
|
+
dataRetention: '365d',
|
|
289
|
+
certificationLevel: 'platinum'
|
|
290
|
+
}
|
|
108
291
|
}
|
|
109
292
|
};
|
|
110
293
|
|
|
294
|
+
// =========================================================================
|
|
295
|
+
// VALIDATION RULES
|
|
296
|
+
// =========================================================================
|
|
297
|
+
|
|
111
298
|
/**
|
|
112
|
-
*
|
|
113
|
-
* @
|
|
299
|
+
* Configuration validation rules.
|
|
300
|
+
* @type {Array<{ check: function, message: string, severity: string }>}
|
|
114
301
|
*/
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
intent: { purpose: 'General-purpose chatbot' },
|
|
121
|
-
crossTurn: true,
|
|
122
|
-
goalDrift: true
|
|
302
|
+
const VALIDATION_RULES = [
|
|
303
|
+
{
|
|
304
|
+
check: (cfg) => !cfg.detection?.enablePatternScanner && !cfg.detection?.enableMicroModel,
|
|
305
|
+
message: 'No detection engine enabled — all threats will be missed',
|
|
306
|
+
severity: 'critical'
|
|
123
307
|
},
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
intent: { purpose: 'Code generation and assistance' },
|
|
129
|
-
toolSequence: true,
|
|
130
|
-
ensemble: true
|
|
308
|
+
{
|
|
309
|
+
check: (cfg) => !cfg.protection?.blockOnThreat,
|
|
310
|
+
message: 'Threat blocking is disabled — threats will be logged but not stopped',
|
|
311
|
+
severity: 'high'
|
|
131
312
|
},
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
intent: { purpose: 'Answer questions from documents' },
|
|
137
|
-
ensemble: true,
|
|
138
|
-
crossTurn: true,
|
|
139
|
-
adaptiveThresholds: true
|
|
313
|
+
{
|
|
314
|
+
check: (cfg) => !cfg.protection?.piiRedaction,
|
|
315
|
+
message: 'PII redaction is disabled — personal data may leak to LLM providers',
|
|
316
|
+
severity: 'high'
|
|
140
317
|
},
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
intent: { purpose: 'Customer support agent' },
|
|
146
|
-
goalDrift: true,
|
|
147
|
-
crossTurn: true,
|
|
148
|
-
feedback: true
|
|
318
|
+
{
|
|
319
|
+
check: (cfg) => !cfg.monitoring?.auditLog,
|
|
320
|
+
message: 'Audit logging is disabled — no forensic trail for incidents',
|
|
321
|
+
severity: 'medium'
|
|
149
322
|
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
intent: { purpose: 'Internal tooling agent' },
|
|
155
|
-
toolSequence: true
|
|
323
|
+
{
|
|
324
|
+
check: (cfg) => cfg.protection?.rateLimiting && !cfg.protection?.rateLimit?.maxRequests,
|
|
325
|
+
message: 'Rate limiting enabled but no maxRequests set',
|
|
326
|
+
severity: 'medium'
|
|
156
327
|
},
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
intent: { purpose: 'Multi-agent orchestration' },
|
|
162
|
-
ensemble: true,
|
|
163
|
-
toolSequence: true,
|
|
164
|
-
crossTurn: true,
|
|
165
|
-
goalDrift: true
|
|
328
|
+
{
|
|
329
|
+
check: (cfg) => cfg.protection?.mcpGuard?.enabled && !cfg.protection?.mcpGuard?.ssrfFirewall,
|
|
330
|
+
message: 'MCP Guard enabled without SSRF firewall — CVE-2026-26118 risk',
|
|
331
|
+
severity: 'high'
|
|
166
332
|
},
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
intent: { purpose: 'High-security agent' },
|
|
172
|
-
ensemble: { voters: ['pattern', 'tfidf', 'entropy', 'ipia', 'semantic', 'behavioral'], requireUnanimous: false },
|
|
173
|
-
learning: { persist: true },
|
|
174
|
-
goalDrift: { driftThreshold: 0.4 },
|
|
175
|
-
crossTurn: true,
|
|
176
|
-
toolSequence: true,
|
|
177
|
-
adaptiveThresholds: true,
|
|
178
|
-
selfTraining: true
|
|
333
|
+
{
|
|
334
|
+
check: (cfg) => cfg.protection?.mcpGuard?.enabled && !cfg.protection?.mcpGuard?.attestation,
|
|
335
|
+
message: 'MCP Guard enabled without server attestation — tool rug-pull risk',
|
|
336
|
+
severity: 'high'
|
|
179
337
|
},
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
338
|
+
{
|
|
339
|
+
check: (cfg) => cfg.protection?.toolGuard?.enabled && (!cfg.protection?.toolGuard?.blockedTools || cfg.protection.toolGuard.blockedTools.length === 0),
|
|
340
|
+
message: 'Tool guard enabled with empty blocklist — exec/shell/eval should be blocked',
|
|
341
|
+
severity: 'medium'
|
|
184
342
|
},
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
*/
|
|
205
|
-
function deepMerge(target, source) {
|
|
206
|
-
const result = Object.assign({}, target);
|
|
207
|
-
for (const key of Object.keys(source)) {
|
|
208
|
-
const srcVal = source[key];
|
|
209
|
-
const tgtVal = result[key];
|
|
210
|
-
if (srcVal && typeof srcVal === 'object' && !Array.isArray(srcVal) &&
|
|
211
|
-
tgtVal && typeof tgtVal === 'object' && !Array.isArray(tgtVal)) {
|
|
212
|
-
result[key] = deepMerge(tgtVal, srcVal);
|
|
213
|
-
} else {
|
|
214
|
-
result[key] = srcVal;
|
|
215
|
-
}
|
|
343
|
+
{
|
|
344
|
+
check: (cfg) => cfg.detection?.enableIPIA && !cfg.protection?.semanticIsolation?.enabled,
|
|
345
|
+
message: 'IPIA detection enabled without semantic isolation — reduced effectiveness',
|
|
346
|
+
severity: 'medium'
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
check: (cfg) => !cfg.protection?.circuitBreaker,
|
|
350
|
+
message: 'No circuit breaker configured — sustained attacks may overwhelm the system',
|
|
351
|
+
severity: 'medium'
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
check: (cfg) => cfg.detection?.scanTimeout && cfg.detection.scanTimeout > 300,
|
|
355
|
+
message: 'Scan timeout exceeds 300ms — may impact user experience',
|
|
356
|
+
severity: 'low'
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
check: (cfg) => cfg.compliance?.frameworks?.includes('hipaa') && !cfg.monitoring?.immutableAudit?.enabled,
|
|
360
|
+
message: 'HIPAA compliance requires immutable audit logging',
|
|
361
|
+
severity: 'high'
|
|
216
362
|
}
|
|
217
|
-
|
|
218
|
-
}
|
|
363
|
+
];
|
|
219
364
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
* @param {object} obj
|
|
224
|
-
* @returns {object}
|
|
225
|
-
*/
|
|
226
|
-
function deepFreeze(obj) {
|
|
227
|
-
Object.freeze(obj);
|
|
228
|
-
for (const val of Object.values(obj)) {
|
|
229
|
-
if (val && typeof val === 'object' && !Object.isFrozen(val)) {
|
|
230
|
-
deepFreeze(val);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return obj;
|
|
234
|
-
}
|
|
365
|
+
// =========================================================================
|
|
366
|
+
// SMART CONFIG CLASS
|
|
367
|
+
// =========================================================================
|
|
235
368
|
|
|
236
369
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* @
|
|
242
|
-
*
|
|
370
|
+
* Smart Configuration and Policy Engine.
|
|
371
|
+
*
|
|
372
|
+
* Analyzes deployment context and generates optimized security configurations.
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* const config = new SmartConfig();
|
|
376
|
+
* const policy = config.generatePolicy('mcp_server');
|
|
377
|
+
* const analysis = config.analyzeDeployment({
|
|
378
|
+
* tools: ['readFile', 'writeFile', 'exec'],
|
|
379
|
+
* model: 'claude-3-opus',
|
|
380
|
+
* mcpServers: ['filesystem', 'github']
|
|
381
|
+
* });
|
|
243
382
|
*/
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
return Object.assign({}, defaults);
|
|
253
|
-
}
|
|
383
|
+
class SmartConfig {
|
|
384
|
+
/**
|
|
385
|
+
* @param {object} [options]
|
|
386
|
+
* @param {Object<string, object>} [options.customPresets] - Additional presets to register
|
|
387
|
+
*/
|
|
388
|
+
constructor(options = {}) {
|
|
389
|
+
this.presets = { ...DEPLOYMENT_PRESETS };
|
|
254
390
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
function validateConfig(config) {
|
|
261
|
-
const errors = [];
|
|
391
|
+
if (options.customPresets) {
|
|
392
|
+
for (const [name, preset] of Object.entries(options.customPresets)) {
|
|
393
|
+
this.presets[name] = preset;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
262
396
|
|
|
263
|
-
|
|
264
|
-
return { valid: false, errors: ['Config must be a non-null object'] };
|
|
397
|
+
console.log(`[Agent Shield] SmartConfig initialized with ${Object.keys(this.presets).length} presets`);
|
|
265
398
|
}
|
|
266
399
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
400
|
+
/**
|
|
401
|
+
* Analyze a deployment configuration and recommend security settings.
|
|
402
|
+
* @param {object} deployment - Deployment context
|
|
403
|
+
* @param {string[]} [deployment.tools] - Available tools
|
|
404
|
+
* @param {string[]} [deployment.mcpServers] - Connected MCP servers
|
|
405
|
+
* @param {string} [deployment.model] - LLM model name
|
|
406
|
+
* @param {boolean} [deployment.hasRAG] - Whether RAG pipeline is present
|
|
407
|
+
* @param {boolean} [deployment.isPublicFacing] - Whether agent faces external users
|
|
408
|
+
* @param {string[]} [deployment.complianceNeeds] - Required compliance frameworks
|
|
409
|
+
* @param {number} [deployment.expectedQPS] - Expected queries per second
|
|
410
|
+
* @returns {{ recommendedPreset: string, reasons: string[], config: object, warnings: string[] }}
|
|
411
|
+
*/
|
|
412
|
+
analyzeDeployment(deployment = {}) {
|
|
413
|
+
const reasons = [];
|
|
414
|
+
const warnings = [];
|
|
415
|
+
let recommendedPreset = 'chatbot';
|
|
416
|
+
let riskScore = 0;
|
|
417
|
+
|
|
418
|
+
const tools = deployment.tools || [];
|
|
419
|
+
const mcpServers = deployment.mcpServers || [];
|
|
420
|
+
const complianceNeeds = deployment.complianceNeeds || [];
|
|
421
|
+
|
|
422
|
+
// Analyze tool risk
|
|
423
|
+
const dangerousTools = ['exec', 'shell', 'eval', 'spawn', 'fork', 'system'];
|
|
424
|
+
const hasDangerousTools = tools.some(t => dangerousTools.includes(t.toLowerCase()));
|
|
425
|
+
if (hasDangerousTools) {
|
|
426
|
+
riskScore += 3;
|
|
427
|
+
reasons.push('Dangerous tools detected (exec/shell/eval) — elevated protection required');
|
|
271
428
|
}
|
|
272
|
-
}
|
|
273
429
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (
|
|
277
|
-
|
|
430
|
+
const fileTools = ['readFile', 'writeFile', 'deleteFile', 'listDir', 'mkdir'];
|
|
431
|
+
const hasFileTools = tools.some(t => fileTools.includes(t));
|
|
432
|
+
if (hasFileTools) {
|
|
433
|
+
riskScore += 1;
|
|
434
|
+
reasons.push('File system tools present — path traversal protection recommended');
|
|
278
435
|
}
|
|
279
|
-
}
|
|
280
436
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (
|
|
284
|
-
|
|
437
|
+
const networkTools = ['fetch', 'httpRequest', 'networkRequest', 'curl'];
|
|
438
|
+
const hasNetworkTools = tools.some(t => networkTools.includes(t));
|
|
439
|
+
if (hasNetworkTools) {
|
|
440
|
+
riskScore += 2;
|
|
441
|
+
reasons.push('Network tools present — SSRF protection and domain allowlisting recommended');
|
|
285
442
|
}
|
|
286
|
-
}
|
|
287
443
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
if (config.intent.maxDriftScore !== undefined) {
|
|
295
|
-
if (typeof config.intent.maxDriftScore !== 'number' || config.intent.maxDriftScore < 0 || config.intent.maxDriftScore > 1) {
|
|
296
|
-
errors.push('intent.maxDriftScore must be a number between 0 and 1');
|
|
297
|
-
}
|
|
298
|
-
}
|
|
444
|
+
// MCP servers
|
|
445
|
+
if (mcpServers.length > 0) {
|
|
446
|
+
riskScore += 2;
|
|
447
|
+
reasons.push(`${mcpServers.length} MCP server(s) detected — MCP Guard recommended`);
|
|
448
|
+
recommendedPreset = 'mcp_server';
|
|
299
449
|
}
|
|
300
|
-
}
|
|
301
450
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (typeof config.learning.promotionThreshold !== 'number' || config.learning.promotionThreshold < 0) {
|
|
309
|
-
errors.push('learning.promotionThreshold must be a non-negative number');
|
|
451
|
+
// RAG pipeline
|
|
452
|
+
if (deployment.hasRAG) {
|
|
453
|
+
riskScore += 2;
|
|
454
|
+
reasons.push('RAG pipeline detected — IPIA detection and semantic isolation recommended');
|
|
455
|
+
if (recommendedPreset === 'chatbot') {
|
|
456
|
+
recommendedPreset = 'rag_pipeline';
|
|
310
457
|
}
|
|
311
458
|
}
|
|
312
|
-
}
|
|
313
459
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
errors.push('ensemble.voters must be an array');
|
|
319
|
-
} else {
|
|
320
|
-
for (const voter of config.ensemble.voters) {
|
|
321
|
-
if (!VALID_VOTERS.includes(voter)) {
|
|
322
|
-
errors.push(`Invalid ensemble voter "${voter}". Valid voters: ${VALID_VOTERS.join(', ')}`);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
460
|
+
// Public facing
|
|
461
|
+
if (deployment.isPublicFacing) {
|
|
462
|
+
riskScore += 1;
|
|
463
|
+
reasons.push('Public-facing deployment — stricter rate limiting and PII redaction recommended');
|
|
326
464
|
}
|
|
327
|
-
if (config.ensemble.threshold !== undefined) {
|
|
328
|
-
if (typeof config.ensemble.threshold !== 'number' || config.ensemble.threshold < 0 || config.ensemble.threshold > 1) {
|
|
329
|
-
errors.push('ensemble.threshold must be a number between 0 and 1');
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
465
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
466
|
+
// Compliance
|
|
467
|
+
if (complianceNeeds.length > 0) {
|
|
468
|
+
riskScore += 1;
|
|
469
|
+
reasons.push(`Compliance requirements: ${complianceNeeds.join(', ')}`);
|
|
470
|
+
if (complianceNeeds.includes('hipaa') || complianceNeeds.includes('soc2')) {
|
|
471
|
+
recommendedPreset = 'enterprise';
|
|
339
472
|
}
|
|
340
473
|
}
|
|
341
|
-
}
|
|
342
474
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
475
|
+
// Coding agent detection
|
|
476
|
+
const codeTools = ['readFile', 'writeFile', 'exec', 'shell', 'runCode', 'compile'];
|
|
477
|
+
const hasCodeTools = tools.filter(t => codeTools.includes(t)).length >= 2;
|
|
478
|
+
if (hasCodeTools && recommendedPreset === 'chatbot') {
|
|
479
|
+
recommendedPreset = 'coding_agent';
|
|
480
|
+
reasons.push('Code execution tools detected — coding agent preset recommended');
|
|
349
481
|
}
|
|
350
|
-
}
|
|
351
482
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
483
|
+
// High risk override
|
|
484
|
+
if (riskScore >= 7) {
|
|
485
|
+
recommendedPreset = 'paranoid';
|
|
486
|
+
reasons.push(`Risk score ${riskScore}/10 — paranoid preset recommended`);
|
|
487
|
+
} else if (riskScore >= 5 && recommendedPreset !== 'enterprise') {
|
|
488
|
+
recommendedPreset = 'enterprise';
|
|
489
|
+
reasons.push(`Risk score ${riskScore}/10 — enterprise preset recommended`);
|
|
358
490
|
}
|
|
359
|
-
}
|
|
360
491
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (typeof config.toolSequence.anomalyThreshold !== 'number' || config.toolSequence.anomalyThreshold < 0 || config.toolSequence.anomalyThreshold > 1) {
|
|
365
|
-
errors.push('toolSequence.anomalyThreshold must be a number between 0 and 1');
|
|
366
|
-
}
|
|
492
|
+
// QPS warnings
|
|
493
|
+
if (deployment.expectedQPS && deployment.expectedQPS > 100) {
|
|
494
|
+
warnings.push('High QPS expected — consider enabling worker scanner for non-blocking scans');
|
|
367
495
|
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
return { valid: errors.length === 0, errors };
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Return a human-readable summary of a Shield configuration.
|
|
375
|
-
* @param {object} config - A built configuration object.
|
|
376
|
-
* @returns {string} Multi-line summary string.
|
|
377
|
-
*/
|
|
378
|
-
function describeConfig(config) {
|
|
379
|
-
if (!config || typeof config !== 'object') {
|
|
380
|
-
return '[Agent Shield] No configuration provided.';
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
const lines = [];
|
|
384
|
-
lines.push('Agent Shield Configuration:');
|
|
385
|
-
if (config.preset) {
|
|
386
|
-
lines.push(` Preset: ${config.preset}`);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const sens = config.sensitivity || 'medium';
|
|
390
|
-
const block = config.blockOnThreat ? 'yes' : 'no';
|
|
391
|
-
const thresh = config.blockThreshold || 'medium';
|
|
392
|
-
lines.push(` Sensitivity: ${sens} | Block: ${block} (threshold: ${thresh})`);
|
|
393
|
-
lines.push('');
|
|
394
|
-
lines.push(' Features enabled:');
|
|
395
|
-
|
|
396
|
-
// Intent
|
|
397
|
-
if (config.intent) {
|
|
398
|
-
const purpose = config.intent.purpose || '(not specified)';
|
|
399
|
-
lines.push(` \u2713 Agent Intent \u2014 "${purpose}"`);
|
|
400
|
-
} else {
|
|
401
|
-
lines.push(' \u2717 Agent Intent \u2014 disabled');
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Learning
|
|
405
|
-
if (config.learning) {
|
|
406
|
-
const dest = config.learning.persist
|
|
407
|
-
? `saving to ${config.learning.persistPath || FEATURE_DEFAULTS.learning.persistPath}`
|
|
408
|
-
: 'in-memory only';
|
|
409
|
-
lines.push(` \u2713 Persistent Learning \u2014 ${dest}`);
|
|
410
|
-
} else {
|
|
411
|
-
lines.push(' \u2717 Persistent Learning \u2014 disabled');
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// Feedback
|
|
415
|
-
if (config.feedback) {
|
|
416
|
-
lines.push(` \u2713 Feedback API \u2014 autoRetrain: ${config.feedback.autoRetrain !== false}`);
|
|
417
|
-
} else {
|
|
418
|
-
lines.push(' \u2717 Feedback API \u2014 disabled');
|
|
419
|
-
}
|
|
420
496
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const voters = (config.ensemble.voters || FEATURE_DEFAULTS.ensemble.voters).join(', ');
|
|
424
|
-
lines.push(` \u2713 Ensemble Detection \u2014 voters: ${voters}`);
|
|
425
|
-
} else {
|
|
426
|
-
lines.push(' \u2717 Ensemble Detection \u2014 disabled');
|
|
427
|
-
}
|
|
497
|
+
// Generate config from recommended preset
|
|
498
|
+
const config = this.generatePolicy(recommendedPreset);
|
|
428
499
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
lines.push(' \u2717 Goal Drift Detection \u2014 disabled');
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Cross-Turn
|
|
438
|
-
if (config.crossTurn) {
|
|
439
|
-
const ws = config.crossTurn.windowSize !== undefined ? config.crossTurn.windowSize : FEATURE_DEFAULTS.crossTurn.windowSize;
|
|
440
|
-
lines.push(` \u2713 Cross-Turn Tracking \u2014 window: ${ws} turns`);
|
|
441
|
-
} else {
|
|
442
|
-
lines.push(' \u2717 Cross-Turn Tracking \u2014 disabled');
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Tool Sequence
|
|
446
|
-
if (config.toolSequence) {
|
|
447
|
-
const at = config.toolSequence.anomalyThreshold !== undefined ? config.toolSequence.anomalyThreshold : FEATURE_DEFAULTS.toolSequence.anomalyThreshold;
|
|
448
|
-
lines.push(` \u2713 Tool Sequence Modeling \u2014 anomaly threshold: ${at}`);
|
|
449
|
-
} else {
|
|
450
|
-
lines.push(' \u2717 Tool Sequence Modeling \u2014 disabled');
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// Adaptive Thresholds
|
|
454
|
-
if (config.adaptiveThresholds) {
|
|
455
|
-
const cs = config.adaptiveThresholds.calibrationSamples !== undefined ? config.adaptiveThresholds.calibrationSamples : FEATURE_DEFAULTS.adaptiveThresholds.calibrationSamples;
|
|
456
|
-
lines.push(` \u2713 Adaptive Thresholds \u2014 calibration samples: ${cs}`);
|
|
457
|
-
} else {
|
|
458
|
-
lines.push(' \u2717 Adaptive Thresholds \u2014 disabled');
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Self-Training
|
|
462
|
-
if (config.selfTraining) {
|
|
463
|
-
const gen = config.selfTraining.generations !== undefined ? config.selfTraining.generations : FEATURE_DEFAULTS.selfTraining.generations;
|
|
464
|
-
lines.push(` \u2713 Self-Training \u2014 ${gen} generations`);
|
|
465
|
-
} else {
|
|
466
|
-
lines.push(' \u2717 Self-Training \u2014 disabled');
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
return lines.join('\n');
|
|
470
|
-
}
|
|
500
|
+
// Apply deployment-specific overrides
|
|
501
|
+
if (complianceNeeds.length > 0) {
|
|
502
|
+
config.compliance = config.compliance || {};
|
|
503
|
+
config.compliance.frameworks = [...new Set([...(config.compliance.frameworks || []), ...complianceNeeds])];
|
|
504
|
+
}
|
|
471
505
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
class ShieldBuilder {
|
|
479
|
-
constructor() {
|
|
480
|
-
/** @private */
|
|
481
|
-
this._config = {
|
|
482
|
-
preset: null,
|
|
483
|
-
sensitivity: 'medium',
|
|
484
|
-
blockOnThreat: true,
|
|
485
|
-
blockThreshold: 'medium',
|
|
486
|
-
intent: null,
|
|
487
|
-
learning: null,
|
|
488
|
-
feedback: null,
|
|
489
|
-
ensemble: null,
|
|
490
|
-
goalDrift: null,
|
|
491
|
-
crossTurn: null,
|
|
492
|
-
toolSequence: null,
|
|
493
|
-
adaptiveThresholds: null,
|
|
494
|
-
selfTraining: null,
|
|
495
|
-
callbacks: {
|
|
496
|
-
onThreat: null,
|
|
497
|
-
onDrift: null,
|
|
498
|
-
onAnomaly: null
|
|
499
|
-
}
|
|
506
|
+
return {
|
|
507
|
+
recommendedPreset,
|
|
508
|
+
reasons,
|
|
509
|
+
config,
|
|
510
|
+
warnings,
|
|
511
|
+
riskScore
|
|
500
512
|
};
|
|
501
513
|
}
|
|
502
514
|
|
|
503
515
|
/**
|
|
504
|
-
*
|
|
505
|
-
* @param {string}
|
|
506
|
-
* @returns {
|
|
516
|
+
* Generate a complete security policy configuration from a preset.
|
|
517
|
+
* @param {string} preset - Preset name
|
|
518
|
+
* @returns {object} Complete security configuration
|
|
507
519
|
*/
|
|
508
|
-
preset
|
|
509
|
-
|
|
510
|
-
|
|
520
|
+
generatePolicy(preset) {
|
|
521
|
+
const presetConfig = this.presets[preset];
|
|
522
|
+
if (!presetConfig) {
|
|
523
|
+
const available = Object.keys(this.presets).join(', ');
|
|
524
|
+
throw new Error(`Unknown preset "${preset}". Available: ${available}`);
|
|
511
525
|
}
|
|
512
|
-
this._config.preset = name;
|
|
513
|
-
const presetCfg = PRESET_CONFIGS[name];
|
|
514
|
-
if (presetCfg) {
|
|
515
|
-
this._applyPreset(presetCfg);
|
|
516
|
-
}
|
|
517
|
-
return this;
|
|
518
|
-
}
|
|
519
526
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
* @private
|
|
523
|
-
* @param {object} presetCfg
|
|
524
|
-
*/
|
|
525
|
-
_applyPreset(presetCfg) {
|
|
526
|
-
if (presetCfg.sensitivity) this._config.sensitivity = presetCfg.sensitivity;
|
|
527
|
-
if (presetCfg.blockOnThreat !== undefined) this._config.blockOnThreat = presetCfg.blockOnThreat;
|
|
528
|
-
if (presetCfg.blockThreshold) this._config.blockThreshold = presetCfg.blockThreshold;
|
|
529
|
-
|
|
530
|
-
const features = ['intent', 'learning', 'feedback', 'ensemble', 'goalDrift',
|
|
531
|
-
'crossTurn', 'toolSequence', 'adaptiveThresholds', 'selfTraining'];
|
|
532
|
-
for (const feat of features) {
|
|
533
|
-
if (presetCfg[feat] !== undefined) {
|
|
534
|
-
this._config[feat] = resolveFeature(feat, presetCfg[feat]);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
527
|
+
// Deep clone the preset config
|
|
528
|
+
const config = JSON.parse(JSON.stringify(presetConfig));
|
|
538
529
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
throw new Error(`[Agent Shield] Invalid sensitivity "${level}". Must be one of: ${VALID_SENSITIVITIES.join(', ')}`);
|
|
547
|
-
}
|
|
548
|
-
this._config.sensitivity = level;
|
|
549
|
-
return this;
|
|
550
|
-
}
|
|
530
|
+
// Add metadata
|
|
531
|
+
config._metadata = {
|
|
532
|
+
preset,
|
|
533
|
+
generatedAt: new Date().toISOString(),
|
|
534
|
+
generatedBy: 'Agent Shield SmartConfig',
|
|
535
|
+
version: '12.0'
|
|
536
|
+
};
|
|
551
537
|
|
|
552
|
-
|
|
553
|
-
* Enable or disable blocking on threat detection.
|
|
554
|
-
* @param {boolean} bool
|
|
555
|
-
* @returns {ShieldBuilder} this
|
|
556
|
-
*/
|
|
557
|
-
blockOnThreat(bool) {
|
|
558
|
-
this._config.blockOnThreat = !!bool;
|
|
559
|
-
return this;
|
|
538
|
+
return config;
|
|
560
539
|
}
|
|
561
540
|
|
|
562
541
|
/**
|
|
563
|
-
*
|
|
564
|
-
* @param {
|
|
565
|
-
* @returns {
|
|
542
|
+
* Validate a configuration for misconfigurations and security gaps.
|
|
543
|
+
* @param {object} config - Configuration to validate
|
|
544
|
+
* @returns {{ valid: boolean, issues: Array<{ message: string, severity: string }>, score: number }}
|
|
566
545
|
*/
|
|
567
|
-
|
|
568
|
-
if (!
|
|
569
|
-
|
|
546
|
+
validateConfig(config) {
|
|
547
|
+
if (!config || typeof config !== 'object') {
|
|
548
|
+
return {
|
|
549
|
+
valid: false,
|
|
550
|
+
issues: [{ message: 'Configuration is empty or invalid', severity: 'critical' }],
|
|
551
|
+
score: 0
|
|
552
|
+
};
|
|
570
553
|
}
|
|
571
|
-
this._config.blockThreshold = level;
|
|
572
|
-
return this;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Enable agent intent declaration.
|
|
577
|
-
* @param {object} [opts] - { purpose, allowedTools, allowedTopics, maxDriftScore }
|
|
578
|
-
* @returns {ShieldBuilder} this
|
|
579
|
-
*/
|
|
580
|
-
enableIntent(opts) {
|
|
581
|
-
this._config.intent = resolveFeature('intent', opts || true);
|
|
582
|
-
if (opts && opts.purpose) this._config.intent.purpose = opts.purpose;
|
|
583
|
-
if (opts && opts.allowedTools) this._config.intent.allowedTools = opts.allowedTools;
|
|
584
|
-
if (opts && opts.allowedTopics) this._config.intent.allowedTopics = opts.allowedTopics;
|
|
585
|
-
if (opts && opts.maxDriftScore !== undefined) this._config.intent.maxDriftScore = opts.maxDriftScore;
|
|
586
|
-
return this;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* Enable persistent learning.
|
|
591
|
-
* @param {object} [opts] - { persist, persistPath, promotionThreshold, maxPatterns }
|
|
592
|
-
* @returns {ShieldBuilder} this
|
|
593
|
-
*/
|
|
594
|
-
enableLearning(opts) {
|
|
595
|
-
this._config.learning = resolveFeature('learning', opts || true);
|
|
596
|
-
return this;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* Enable the feedback API.
|
|
601
|
-
* @param {object} [opts] - { autoRetrain, maxPending, cooldownMs }
|
|
602
|
-
* @returns {ShieldBuilder} this
|
|
603
|
-
*/
|
|
604
|
-
enableFeedback(opts) {
|
|
605
|
-
this._config.feedback = resolveFeature('feedback', opts || true);
|
|
606
|
-
return this;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Enable ensemble voting detection.
|
|
611
|
-
* @param {object} [opts] - { voters, threshold, requireUnanimous }
|
|
612
|
-
* @returns {ShieldBuilder} this
|
|
613
|
-
*/
|
|
614
|
-
enableEnsemble(opts) {
|
|
615
|
-
this._config.ensemble = resolveFeature('ensemble', opts || true);
|
|
616
|
-
return this;
|
|
617
|
-
}
|
|
618
554
|
|
|
619
|
-
|
|
620
|
-
* Enable goal drift detection.
|
|
621
|
-
* @param {object} [opts] - { checkInterval, driftThreshold, windowSize }
|
|
622
|
-
* @returns {ShieldBuilder} this
|
|
623
|
-
*/
|
|
624
|
-
enableGoalDrift(opts) {
|
|
625
|
-
this._config.goalDrift = resolveFeature('goalDrift', opts || true);
|
|
626
|
-
return this;
|
|
627
|
-
}
|
|
555
|
+
const issues = [];
|
|
628
556
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
557
|
+
for (const rule of VALIDATION_RULES) {
|
|
558
|
+
try {
|
|
559
|
+
if (rule.check(config)) {
|
|
560
|
+
issues.push({ message: rule.message, severity: rule.severity });
|
|
561
|
+
}
|
|
562
|
+
} catch (_e) {
|
|
563
|
+
// Rule check failed — skip silently
|
|
564
|
+
}
|
|
565
|
+
}
|
|
638
566
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
return this;
|
|
647
|
-
}
|
|
567
|
+
// Compute security score (0-100)
|
|
568
|
+
const severityPenalty = { critical: 25, high: 15, medium: 8, low: 3 };
|
|
569
|
+
let penalty = 0;
|
|
570
|
+
for (const issue of issues) {
|
|
571
|
+
penalty += severityPenalty[issue.severity] || 5;
|
|
572
|
+
}
|
|
573
|
+
const score = Math.max(0, 100 - penalty);
|
|
648
574
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
* @param {object} [opts] - { calibrationSamples, adjustInterval, minConfidence }
|
|
652
|
-
* @returns {ShieldBuilder} this
|
|
653
|
-
*/
|
|
654
|
-
enableAdaptiveThresholds(opts) {
|
|
655
|
-
this._config.adaptiveThresholds = resolveFeature('adaptiveThresholds', opts || true);
|
|
656
|
-
return this;
|
|
657
|
-
}
|
|
575
|
+
const hasCritical = issues.some(i => i.severity === 'critical');
|
|
576
|
+
const valid = !hasCritical && score >= 50;
|
|
658
577
|
|
|
659
|
-
|
|
660
|
-
* Enable adversarial self-training.
|
|
661
|
-
* @param {object} [opts] - { generations, populationSize, mutationRate, interval }
|
|
662
|
-
* @returns {ShieldBuilder} this
|
|
663
|
-
*/
|
|
664
|
-
enableSelfTraining(opts) {
|
|
665
|
-
this._config.selfTraining = resolveFeature('selfTraining', opts || true);
|
|
666
|
-
return this;
|
|
578
|
+
return { valid, issues, score };
|
|
667
579
|
}
|
|
668
580
|
|
|
669
581
|
/**
|
|
670
|
-
*
|
|
671
|
-
* @
|
|
672
|
-
* @returns {ShieldBuilder} this
|
|
582
|
+
* List all available preset names.
|
|
583
|
+
* @returns {string[]}
|
|
673
584
|
*/
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
throw new Error('[Agent Shield] onThreat callback must be a function');
|
|
677
|
-
}
|
|
678
|
-
this._config.callbacks.onThreat = callback;
|
|
679
|
-
return this;
|
|
585
|
+
listPresets() {
|
|
586
|
+
return Object.keys(this.presets);
|
|
680
587
|
}
|
|
681
588
|
|
|
682
589
|
/**
|
|
683
|
-
*
|
|
684
|
-
* @param {
|
|
685
|
-
* @returns {
|
|
590
|
+
* Get a preset by name.
|
|
591
|
+
* @param {string} name - Preset name
|
|
592
|
+
* @returns {object|null}
|
|
686
593
|
*/
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
throw new Error('[Agent Shield] onDrift callback must be a function');
|
|
690
|
-
}
|
|
691
|
-
this._config.callbacks.onDrift = callback;
|
|
692
|
-
return this;
|
|
594
|
+
getPreset(name) {
|
|
595
|
+
return this.presets[name] || null;
|
|
693
596
|
}
|
|
694
597
|
|
|
695
598
|
/**
|
|
696
|
-
*
|
|
697
|
-
* @param {
|
|
698
|
-
* @
|
|
599
|
+
* Register a custom preset.
|
|
600
|
+
* @param {string} name - Preset name
|
|
601
|
+
* @param {object} config - Preset configuration
|
|
699
602
|
*/
|
|
700
|
-
|
|
701
|
-
if (typeof
|
|
702
|
-
throw new Error('
|
|
603
|
+
registerPreset(name, config) {
|
|
604
|
+
if (!name || typeof name !== 'string') {
|
|
605
|
+
throw new Error('Preset name is required');
|
|
703
606
|
}
|
|
704
|
-
this.
|
|
705
|
-
|
|
607
|
+
this.presets[name] = config;
|
|
608
|
+
console.log(`[Agent Shield] Custom preset "${name}" registered`);
|
|
706
609
|
}
|
|
707
610
|
|
|
708
611
|
/**
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
* @
|
|
612
|
+
* Compare two presets and show differences.
|
|
613
|
+
* @param {string} presetA - First preset name
|
|
614
|
+
* @param {string} presetB - Second preset name
|
|
615
|
+
* @returns {object} Comparison summary
|
|
712
616
|
*/
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
delete config.callbacks;
|
|
719
|
-
|
|
720
|
-
const validation = validateConfig(config);
|
|
721
|
-
if (!validation.valid) {
|
|
722
|
-
throw new Error(`[Agent Shield] Invalid configuration:\n - ${validation.errors.join('\n - ')}`);
|
|
617
|
+
comparePresets(presetA, presetB) {
|
|
618
|
+
const a = this.presets[presetA];
|
|
619
|
+
const b = this.presets[presetB];
|
|
620
|
+
if (!a || !b) {
|
|
621
|
+
throw new Error(`Preset not found: ${!a ? presetA : presetB}`);
|
|
723
622
|
}
|
|
724
623
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
* @returns {object|ShieldBuilder} Built config (if string/object) or new ShieldBuilder (if no input).
|
|
744
|
-
*/
|
|
745
|
-
function createShield(input) {
|
|
746
|
-
// No input — return builder for chaining
|
|
747
|
-
if (input === undefined || input === null) {
|
|
748
|
-
return new ShieldBuilder();
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// String — preset name, auto-build
|
|
752
|
-
if (typeof input === 'string') {
|
|
753
|
-
return new ShieldBuilder().preset(input).build();
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// ShieldBuilder instance — build it
|
|
757
|
-
if (input instanceof ShieldBuilder) {
|
|
758
|
-
return input.build();
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
// Object — treat as raw config
|
|
762
|
-
if (typeof input === 'object' && !Array.isArray(input)) {
|
|
763
|
-
const builder = new ShieldBuilder();
|
|
764
|
-
|
|
765
|
-
// Apply preset first if specified
|
|
766
|
-
if (input.preset) {
|
|
767
|
-
builder.preset(input.preset);
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
// Override with explicit values
|
|
771
|
-
if (input.sensitivity) builder.sensitivity(input.sensitivity);
|
|
772
|
-
if (input.blockOnThreat !== undefined) builder.blockOnThreat(input.blockOnThreat);
|
|
773
|
-
if (input.blockThreshold) builder.blockThreshold(input.blockThreshold);
|
|
774
|
-
|
|
775
|
-
const featureMap = {
|
|
776
|
-
intent: 'enableIntent',
|
|
777
|
-
learning: 'enableLearning',
|
|
778
|
-
feedback: 'enableFeedback',
|
|
779
|
-
ensemble: 'enableEnsemble',
|
|
780
|
-
goalDrift: 'enableGoalDrift',
|
|
781
|
-
crossTurn: 'enableCrossTurn',
|
|
782
|
-
toolSequence: 'enableToolSequence',
|
|
783
|
-
adaptiveThresholds: 'enableAdaptiveThresholds',
|
|
784
|
-
selfTraining: 'enableSelfTraining'
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
for (const [key, method] of Object.entries(featureMap)) {
|
|
788
|
-
if (input[key] !== undefined && input[key] !== false && input[key] !== null) {
|
|
789
|
-
const val = input[key] === true ? undefined : input[key];
|
|
790
|
-
builder[method](val);
|
|
624
|
+
const differences = [];
|
|
625
|
+
|
|
626
|
+
const compare = (objA, objB, path = '') => {
|
|
627
|
+
const allKeys = new Set([...Object.keys(objA || {}), ...Object.keys(objB || {})]);
|
|
628
|
+
for (const key of allKeys) {
|
|
629
|
+
const fullPath = path ? `${path}.${key}` : key;
|
|
630
|
+
const va = objA?.[key];
|
|
631
|
+
const vb = objB?.[key];
|
|
632
|
+
|
|
633
|
+
if (va !== undefined && vb === undefined) {
|
|
634
|
+
differences.push({ path: fullPath, inA: va, inB: undefined });
|
|
635
|
+
} else if (va === undefined && vb !== undefined) {
|
|
636
|
+
differences.push({ path: fullPath, inA: undefined, inB: vb });
|
|
637
|
+
} else if (typeof va === 'object' && va !== null && typeof vb === 'object' && vb !== null && !Array.isArray(va)) {
|
|
638
|
+
compare(va, vb, fullPath);
|
|
639
|
+
} else if (JSON.stringify(va) !== JSON.stringify(vb)) {
|
|
640
|
+
differences.push({ path: fullPath, inA: va, inB: vb });
|
|
641
|
+
}
|
|
791
642
|
}
|
|
792
|
-
}
|
|
643
|
+
};
|
|
793
644
|
|
|
794
|
-
|
|
795
|
-
if (typeof input.onThreat === 'function') builder.onThreat(input.onThreat);
|
|
796
|
-
if (typeof input.onDrift === 'function') builder.onDrift(input.onDrift);
|
|
797
|
-
if (typeof input.onAnomaly === 'function') builder.onAnomaly(input.onAnomaly);
|
|
645
|
+
compare(a, b);
|
|
798
646
|
|
|
799
|
-
return
|
|
647
|
+
return {
|
|
648
|
+
presetA,
|
|
649
|
+
presetB,
|
|
650
|
+
differences,
|
|
651
|
+
differenceCount: differences.length
|
|
652
|
+
};
|
|
800
653
|
}
|
|
801
|
-
|
|
802
|
-
throw new Error('[Agent Shield] createShield() accepts a string, object, ShieldBuilder, or no arguments');
|
|
803
654
|
}
|
|
804
655
|
|
|
656
|
+
// =========================================================================
|
|
657
|
+
// EXPORTS
|
|
658
|
+
// =========================================================================
|
|
659
|
+
|
|
805
660
|
module.exports = {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
describeConfig,
|
|
810
|
-
FEATURE_DEFAULTS,
|
|
811
|
-
VALID_PRESETS
|
|
661
|
+
SmartConfig,
|
|
662
|
+
DEPLOYMENT_PRESETS,
|
|
663
|
+
VALIDATION_RULES
|
|
812
664
|
};
|