@artemiskit/sdk 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/README.md +173 -0
- package/adapters/openai/dist/index.js +5625 -0
- package/dist/index.js +42577 -0
- package/dist/matchers/index.js +224 -0
- package/dist/matchers/jest.js +257 -0
- package/dist/matchers/vitest.js +257 -0
- package/package.json +78 -0
- package/src/__tests__/artemiskit.test.ts +425 -0
- package/src/__tests__/matchers.test.ts +450 -0
- package/src/artemiskit.ts +791 -0
- package/src/guardian/action-validator.ts +585 -0
- package/src/guardian/circuit-breaker.ts +655 -0
- package/src/guardian/guardian.ts +497 -0
- package/src/guardian/guardrails.ts +536 -0
- package/src/guardian/index.ts +142 -0
- package/src/guardian/intent-classifier.ts +378 -0
- package/src/guardian/interceptor.ts +381 -0
- package/src/guardian/policy.ts +446 -0
- package/src/guardian/types.ts +436 -0
- package/src/index.ts +164 -0
- package/src/matchers/core.ts +315 -0
- package/src/matchers/index.ts +26 -0
- package/src/matchers/jest.ts +112 -0
- package/src/matchers/vitest.ts +84 -0
- package/src/types.ts +259 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates tool/function calls before execution.
|
|
5
|
+
* Ensures agents only perform allowed actions with valid parameters.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { nanoid } from 'nanoid';
|
|
9
|
+
import type {
|
|
10
|
+
ActionDefinition,
|
|
11
|
+
ActionParameter,
|
|
12
|
+
GuardrailResult,
|
|
13
|
+
InterceptedToolCall,
|
|
14
|
+
ParameterValidation,
|
|
15
|
+
Violation,
|
|
16
|
+
ViolationSeverity,
|
|
17
|
+
} from './types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Action validation result
|
|
21
|
+
*/
|
|
22
|
+
export interface ActionValidationResult {
|
|
23
|
+
valid: boolean;
|
|
24
|
+
violations: Violation[];
|
|
25
|
+
sanitizedArguments?: Record<string, unknown>;
|
|
26
|
+
requiresApproval?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Action validator configuration
|
|
31
|
+
*/
|
|
32
|
+
export interface ActionValidatorConfig {
|
|
33
|
+
/** Allowed actions with their definitions */
|
|
34
|
+
allowedActions?: ActionDefinition[];
|
|
35
|
+
/** Default behavior for undefined actions */
|
|
36
|
+
defaultAllow?: boolean;
|
|
37
|
+
/** Default risk level for undefined actions */
|
|
38
|
+
defaultRiskLevel?: ViolationSeverity;
|
|
39
|
+
/** Block high-risk actions automatically */
|
|
40
|
+
blockHighRisk?: boolean;
|
|
41
|
+
/** Custom validation function */
|
|
42
|
+
customValidator?: (toolCall: InterceptedToolCall) => Promise<ActionValidationResult>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Action Validator
|
|
47
|
+
*
|
|
48
|
+
* Validates tool/function calls against defined policies.
|
|
49
|
+
*/
|
|
50
|
+
export class ActionValidator {
|
|
51
|
+
private config: ActionValidatorConfig;
|
|
52
|
+
private actionMap: Map<string, ActionDefinition>;
|
|
53
|
+
private callHistory: InterceptedToolCall[];
|
|
54
|
+
private callCounts: Map<string, { count: number; windowStart: number }>;
|
|
55
|
+
|
|
56
|
+
constructor(config: ActionValidatorConfig = {}) {
|
|
57
|
+
this.config = {
|
|
58
|
+
defaultAllow: false,
|
|
59
|
+
defaultRiskLevel: 'medium',
|
|
60
|
+
blockHighRisk: true,
|
|
61
|
+
...config,
|
|
62
|
+
};
|
|
63
|
+
this.actionMap = new Map();
|
|
64
|
+
this.callHistory = [];
|
|
65
|
+
this.callCounts = new Map();
|
|
66
|
+
|
|
67
|
+
// Index allowed actions
|
|
68
|
+
if (config.allowedActions) {
|
|
69
|
+
for (const action of config.allowedActions) {
|
|
70
|
+
this.actionMap.set(action.name, action);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Validate a tool/function call
|
|
77
|
+
*/
|
|
78
|
+
async validate(toolCall: InterceptedToolCall): Promise<ActionValidationResult> {
|
|
79
|
+
const violations: Violation[] = [];
|
|
80
|
+
let sanitizedArguments = { ...toolCall.arguments };
|
|
81
|
+
let requiresApproval = false;
|
|
82
|
+
|
|
83
|
+
// Record the call
|
|
84
|
+
this.callHistory.push(toolCall);
|
|
85
|
+
|
|
86
|
+
// Get action definition
|
|
87
|
+
const actionDef = this.actionMap.get(toolCall.toolName);
|
|
88
|
+
|
|
89
|
+
// Check if action is defined
|
|
90
|
+
if (!actionDef) {
|
|
91
|
+
if (!this.config.defaultAllow) {
|
|
92
|
+
violations.push({
|
|
93
|
+
id: nanoid(),
|
|
94
|
+
type: 'action_validation',
|
|
95
|
+
severity: this.config.defaultRiskLevel ?? 'medium',
|
|
96
|
+
message: `Unknown action: ${toolCall.toolName}`,
|
|
97
|
+
details: { toolName: toolCall.toolName },
|
|
98
|
+
timestamp: new Date(),
|
|
99
|
+
action: 'block',
|
|
100
|
+
blocked: true,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// Check if action is allowed
|
|
105
|
+
if (actionDef.allowed === false) {
|
|
106
|
+
violations.push({
|
|
107
|
+
id: nanoid(),
|
|
108
|
+
type: 'action_validation',
|
|
109
|
+
severity: actionDef.riskLevel ?? 'high',
|
|
110
|
+
message: `Action not allowed: ${toolCall.toolName}`,
|
|
111
|
+
details: { toolName: toolCall.toolName, reason: 'explicitly_disabled' },
|
|
112
|
+
timestamp: new Date(),
|
|
113
|
+
action: 'block',
|
|
114
|
+
blocked: true,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check rate limits
|
|
119
|
+
const rateLimitViolation = this.checkRateLimit(toolCall.toolName, actionDef);
|
|
120
|
+
if (rateLimitViolation) {
|
|
121
|
+
violations.push(rateLimitViolation);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check if requires approval
|
|
125
|
+
if (actionDef.requiresApproval) {
|
|
126
|
+
requiresApproval = true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Block high-risk actions if configured
|
|
130
|
+
if (
|
|
131
|
+
this.config.blockHighRisk &&
|
|
132
|
+
(actionDef.riskLevel === 'high' || actionDef.riskLevel === 'critical')
|
|
133
|
+
) {
|
|
134
|
+
if (!requiresApproval) {
|
|
135
|
+
// Auto-block unless approval is required
|
|
136
|
+
violations.push({
|
|
137
|
+
id: nanoid(),
|
|
138
|
+
type: 'action_validation',
|
|
139
|
+
severity: actionDef.riskLevel,
|
|
140
|
+
message: `High-risk action blocked: ${toolCall.toolName}`,
|
|
141
|
+
details: { toolName: toolCall.toolName, riskLevel: actionDef.riskLevel },
|
|
142
|
+
timestamp: new Date(),
|
|
143
|
+
action: 'block',
|
|
144
|
+
blocked: true,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Validate parameters
|
|
150
|
+
if (actionDef.parameters) {
|
|
151
|
+
const paramResult = this.validateParameters(toolCall.arguments, actionDef.parameters);
|
|
152
|
+
violations.push(...paramResult.violations);
|
|
153
|
+
if (paramResult.sanitized) {
|
|
154
|
+
sanitizedArguments = paramResult.sanitized;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Run custom validator if provided
|
|
160
|
+
if (this.config.customValidator) {
|
|
161
|
+
const customResult = await this.config.customValidator(toolCall);
|
|
162
|
+
violations.push(...customResult.violations);
|
|
163
|
+
if (customResult.sanitizedArguments) {
|
|
164
|
+
sanitizedArguments = customResult.sanitizedArguments;
|
|
165
|
+
}
|
|
166
|
+
if (customResult.requiresApproval) {
|
|
167
|
+
requiresApproval = true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
valid: violations.length === 0,
|
|
173
|
+
violations,
|
|
174
|
+
sanitizedArguments,
|
|
175
|
+
requiresApproval,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Create a guardrail function from this validator
|
|
181
|
+
*/
|
|
182
|
+
asGuardrail(): (content: string, context?: Record<string, unknown>) => Promise<GuardrailResult> {
|
|
183
|
+
return async (_content: string, context?: Record<string, unknown>) => {
|
|
184
|
+
// Extract tool call from context if available
|
|
185
|
+
const toolCall = context?.toolCall as InterceptedToolCall | undefined;
|
|
186
|
+
|
|
187
|
+
if (!toolCall) {
|
|
188
|
+
return { passed: true, violations: [] };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const result = await this.validate(toolCall);
|
|
192
|
+
return {
|
|
193
|
+
passed: result.valid,
|
|
194
|
+
violations: result.violations,
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Register an allowed action
|
|
201
|
+
*/
|
|
202
|
+
registerAction(action: ActionDefinition): void {
|
|
203
|
+
this.actionMap.set(action.name, action);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Remove an action from allowed list
|
|
208
|
+
*/
|
|
209
|
+
unregisterAction(name: string): void {
|
|
210
|
+
this.actionMap.delete(name);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get all registered actions
|
|
215
|
+
*/
|
|
216
|
+
getRegisteredActions(): ActionDefinition[] {
|
|
217
|
+
return Array.from(this.actionMap.values());
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get call history
|
|
222
|
+
*/
|
|
223
|
+
getCallHistory(): InterceptedToolCall[] {
|
|
224
|
+
return [...this.callHistory];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Clear call history
|
|
229
|
+
*/
|
|
230
|
+
clearHistory(): void {
|
|
231
|
+
this.callHistory = [];
|
|
232
|
+
this.callCounts.clear();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Check rate limit for an action
|
|
237
|
+
*/
|
|
238
|
+
private checkRateLimit(toolName: string, actionDef: ActionDefinition): Violation | null {
|
|
239
|
+
if (!actionDef.maxCallsPerMinute) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const now = Date.now();
|
|
244
|
+
const windowMs = 60000; // 1 minute
|
|
245
|
+
let entry = this.callCounts.get(toolName);
|
|
246
|
+
|
|
247
|
+
if (!entry || now - entry.windowStart >= windowMs) {
|
|
248
|
+
// Start new window
|
|
249
|
+
entry = { count: 1, windowStart: now };
|
|
250
|
+
this.callCounts.set(toolName, entry);
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
entry.count++;
|
|
255
|
+
|
|
256
|
+
if (entry.count > actionDef.maxCallsPerMinute) {
|
|
257
|
+
return {
|
|
258
|
+
id: nanoid(),
|
|
259
|
+
type: 'rate_limit',
|
|
260
|
+
severity: 'medium',
|
|
261
|
+
message: `Rate limit exceeded for action: ${toolName}`,
|
|
262
|
+
details: {
|
|
263
|
+
toolName,
|
|
264
|
+
limit: actionDef.maxCallsPerMinute,
|
|
265
|
+
current: entry.count,
|
|
266
|
+
},
|
|
267
|
+
timestamp: new Date(),
|
|
268
|
+
action: 'block',
|
|
269
|
+
blocked: true,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Validate parameters against definitions
|
|
278
|
+
*/
|
|
279
|
+
private validateParameters(
|
|
280
|
+
args: Record<string, unknown>,
|
|
281
|
+
params: ActionParameter[]
|
|
282
|
+
): { violations: Violation[]; sanitized: Record<string, unknown> | null } {
|
|
283
|
+
const violations: Violation[] = [];
|
|
284
|
+
const sanitized = { ...args };
|
|
285
|
+
|
|
286
|
+
for (const param of params) {
|
|
287
|
+
const value = args[param.name];
|
|
288
|
+
|
|
289
|
+
// Check required
|
|
290
|
+
if (param.required && (value === undefined || value === null)) {
|
|
291
|
+
violations.push({
|
|
292
|
+
id: nanoid(),
|
|
293
|
+
type: 'action_validation',
|
|
294
|
+
severity: 'medium',
|
|
295
|
+
message: `Missing required parameter: ${param.name}`,
|
|
296
|
+
details: { parameter: param.name },
|
|
297
|
+
timestamp: new Date(),
|
|
298
|
+
action: 'block',
|
|
299
|
+
blocked: true,
|
|
300
|
+
});
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (value === undefined || value === null) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Type checking
|
|
309
|
+
if (!this.checkType(value, param.type)) {
|
|
310
|
+
violations.push({
|
|
311
|
+
id: nanoid(),
|
|
312
|
+
type: 'action_validation',
|
|
313
|
+
severity: 'medium',
|
|
314
|
+
message: `Invalid type for parameter: ${param.name} (expected ${param.type})`,
|
|
315
|
+
details: { parameter: param.name, expected: param.type, actual: typeof value },
|
|
316
|
+
timestamp: new Date(),
|
|
317
|
+
action: 'block',
|
|
318
|
+
blocked: true,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Run validation rules
|
|
323
|
+
if (param.validation) {
|
|
324
|
+
const validationViolations = this.runValidation(param.name, value, param.validation);
|
|
325
|
+
violations.push(...validationViolations);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
violations,
|
|
331
|
+
sanitized: violations.length === 0 ? sanitized : null,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Check if value matches expected type
|
|
337
|
+
*/
|
|
338
|
+
private checkType(value: unknown, expectedType: string): boolean {
|
|
339
|
+
switch (expectedType) {
|
|
340
|
+
case 'string':
|
|
341
|
+
return typeof value === 'string';
|
|
342
|
+
case 'number':
|
|
343
|
+
return typeof value === 'number';
|
|
344
|
+
case 'boolean':
|
|
345
|
+
return typeof value === 'boolean';
|
|
346
|
+
case 'array':
|
|
347
|
+
return Array.isArray(value);
|
|
348
|
+
case 'object':
|
|
349
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
350
|
+
default:
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Run validation rules on a parameter value
|
|
357
|
+
*/
|
|
358
|
+
private runValidation(
|
|
359
|
+
paramName: string,
|
|
360
|
+
value: unknown,
|
|
361
|
+
validation: ParameterValidation
|
|
362
|
+
): Violation[] {
|
|
363
|
+
const violations: Violation[] = [];
|
|
364
|
+
const strValue = String(value);
|
|
365
|
+
|
|
366
|
+
// Pattern matching
|
|
367
|
+
if (validation.pattern) {
|
|
368
|
+
const regex = new RegExp(validation.pattern);
|
|
369
|
+
if (!regex.test(strValue)) {
|
|
370
|
+
violations.push({
|
|
371
|
+
id: nanoid(),
|
|
372
|
+
type: 'action_validation',
|
|
373
|
+
severity: 'medium',
|
|
374
|
+
message: `Parameter ${paramName} does not match required pattern`,
|
|
375
|
+
details: { parameter: paramName, pattern: validation.pattern },
|
|
376
|
+
timestamp: new Date(),
|
|
377
|
+
action: 'block',
|
|
378
|
+
blocked: true,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Length checks for strings
|
|
384
|
+
if (typeof value === 'string') {
|
|
385
|
+
if (validation.minLength && value.length < validation.minLength) {
|
|
386
|
+
violations.push({
|
|
387
|
+
id: nanoid(),
|
|
388
|
+
type: 'action_validation',
|
|
389
|
+
severity: 'low',
|
|
390
|
+
message: `Parameter ${paramName} is too short (min: ${validation.minLength})`,
|
|
391
|
+
details: { parameter: paramName, minLength: validation.minLength },
|
|
392
|
+
timestamp: new Date(),
|
|
393
|
+
action: 'warn',
|
|
394
|
+
blocked: false,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
if (validation.maxLength && value.length > validation.maxLength) {
|
|
398
|
+
violations.push({
|
|
399
|
+
id: nanoid(),
|
|
400
|
+
type: 'action_validation',
|
|
401
|
+
severity: 'medium',
|
|
402
|
+
message: `Parameter ${paramName} is too long (max: ${validation.maxLength})`,
|
|
403
|
+
details: { parameter: paramName, maxLength: validation.maxLength },
|
|
404
|
+
timestamp: new Date(),
|
|
405
|
+
action: 'block',
|
|
406
|
+
blocked: true,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Numeric range checks
|
|
412
|
+
if (typeof value === 'number') {
|
|
413
|
+
if (validation.minValue !== undefined && value < validation.minValue) {
|
|
414
|
+
violations.push({
|
|
415
|
+
id: nanoid(),
|
|
416
|
+
type: 'action_validation',
|
|
417
|
+
severity: 'medium',
|
|
418
|
+
message: `Parameter ${paramName} is below minimum (min: ${validation.minValue})`,
|
|
419
|
+
details: { parameter: paramName, minValue: validation.minValue },
|
|
420
|
+
timestamp: new Date(),
|
|
421
|
+
action: 'block',
|
|
422
|
+
blocked: true,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
if (validation.maxValue !== undefined && value > validation.maxValue) {
|
|
426
|
+
violations.push({
|
|
427
|
+
id: nanoid(),
|
|
428
|
+
type: 'action_validation',
|
|
429
|
+
severity: 'medium',
|
|
430
|
+
message: `Parameter ${paramName} exceeds maximum (max: ${validation.maxValue})`,
|
|
431
|
+
details: { parameter: paramName, maxValue: validation.maxValue },
|
|
432
|
+
timestamp: new Date(),
|
|
433
|
+
action: 'block',
|
|
434
|
+
blocked: true,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Allowed values check
|
|
440
|
+
if (validation.allowedValues && !validation.allowedValues.includes(value as string | number)) {
|
|
441
|
+
violations.push({
|
|
442
|
+
id: nanoid(),
|
|
443
|
+
type: 'action_validation',
|
|
444
|
+
severity: 'medium',
|
|
445
|
+
message: `Parameter ${paramName} has invalid value`,
|
|
446
|
+
details: {
|
|
447
|
+
parameter: paramName,
|
|
448
|
+
value,
|
|
449
|
+
allowedValues: validation.allowedValues,
|
|
450
|
+
},
|
|
451
|
+
timestamp: new Date(),
|
|
452
|
+
action: 'block',
|
|
453
|
+
blocked: true,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Blocked values check
|
|
458
|
+
if (validation.blockedValues?.includes(value as string | number)) {
|
|
459
|
+
violations.push({
|
|
460
|
+
id: nanoid(),
|
|
461
|
+
type: 'action_validation',
|
|
462
|
+
severity: 'high',
|
|
463
|
+
message: `Parameter ${paramName} contains blocked value`,
|
|
464
|
+
details: { parameter: paramName, value },
|
|
465
|
+
timestamp: new Date(),
|
|
466
|
+
action: 'block',
|
|
467
|
+
blocked: true,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Blocked patterns check
|
|
472
|
+
if (validation.blockedPatterns) {
|
|
473
|
+
for (const pattern of validation.blockedPatterns) {
|
|
474
|
+
const regex = new RegExp(pattern, 'i');
|
|
475
|
+
if (regex.test(strValue)) {
|
|
476
|
+
violations.push({
|
|
477
|
+
id: nanoid(),
|
|
478
|
+
type: 'action_validation',
|
|
479
|
+
severity: 'high',
|
|
480
|
+
message: `Parameter ${paramName} matches blocked pattern`,
|
|
481
|
+
details: { parameter: paramName, pattern },
|
|
482
|
+
timestamp: new Date(),
|
|
483
|
+
action: 'block',
|
|
484
|
+
blocked: true,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return violations;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Create a pre-configured action validator with common dangerous actions blocked
|
|
496
|
+
*/
|
|
497
|
+
export function createDefaultActionValidator(): ActionValidator {
|
|
498
|
+
return new ActionValidator({
|
|
499
|
+
defaultAllow: true,
|
|
500
|
+
blockHighRisk: true,
|
|
501
|
+
allowedActions: [
|
|
502
|
+
// File operations - high risk
|
|
503
|
+
{
|
|
504
|
+
name: 'delete_file',
|
|
505
|
+
description: 'Delete a file from the filesystem',
|
|
506
|
+
category: 'filesystem',
|
|
507
|
+
riskLevel: 'critical',
|
|
508
|
+
allowed: false,
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
name: 'write_file',
|
|
512
|
+
description: 'Write content to a file',
|
|
513
|
+
category: 'filesystem',
|
|
514
|
+
riskLevel: 'high',
|
|
515
|
+
requiresApproval: true,
|
|
516
|
+
parameters: [
|
|
517
|
+
{
|
|
518
|
+
name: 'path',
|
|
519
|
+
type: 'string',
|
|
520
|
+
required: true,
|
|
521
|
+
validation: {
|
|
522
|
+
blockedPatterns: ['\\.env', 'credentials', 'password', 'secret', '/etc/', '/root/'],
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
],
|
|
526
|
+
},
|
|
527
|
+
// Network operations
|
|
528
|
+
{
|
|
529
|
+
name: 'http_request',
|
|
530
|
+
description: 'Make an HTTP request',
|
|
531
|
+
category: 'network',
|
|
532
|
+
riskLevel: 'medium',
|
|
533
|
+
maxCallsPerMinute: 60,
|
|
534
|
+
parameters: [
|
|
535
|
+
{
|
|
536
|
+
name: 'url',
|
|
537
|
+
type: 'string',
|
|
538
|
+
required: true,
|
|
539
|
+
validation: {
|
|
540
|
+
blockedPatterns: [
|
|
541
|
+
'localhost',
|
|
542
|
+
'127\\.0\\.0\\.1',
|
|
543
|
+
'0\\.0\\.0\\.0',
|
|
544
|
+
'internal',
|
|
545
|
+
'\\.local',
|
|
546
|
+
],
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
},
|
|
551
|
+
// Database operations
|
|
552
|
+
{
|
|
553
|
+
name: 'execute_sql',
|
|
554
|
+
description: 'Execute SQL query',
|
|
555
|
+
category: 'database',
|
|
556
|
+
riskLevel: 'critical',
|
|
557
|
+
allowed: false,
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
name: 'query_database',
|
|
561
|
+
description: 'Read-only database query',
|
|
562
|
+
category: 'database',
|
|
563
|
+
riskLevel: 'medium',
|
|
564
|
+
maxCallsPerMinute: 100,
|
|
565
|
+
},
|
|
566
|
+
// System operations
|
|
567
|
+
{
|
|
568
|
+
name: 'execute_command',
|
|
569
|
+
description: 'Execute a shell command',
|
|
570
|
+
category: 'system',
|
|
571
|
+
riskLevel: 'critical',
|
|
572
|
+
allowed: false,
|
|
573
|
+
},
|
|
574
|
+
// Email/messaging
|
|
575
|
+
{
|
|
576
|
+
name: 'send_email',
|
|
577
|
+
description: 'Send an email',
|
|
578
|
+
category: 'communication',
|
|
579
|
+
riskLevel: 'high',
|
|
580
|
+
requiresApproval: true,
|
|
581
|
+
maxCallsPerMinute: 10,
|
|
582
|
+
},
|
|
583
|
+
],
|
|
584
|
+
});
|
|
585
|
+
}
|