@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.
@@ -0,0 +1,446 @@
1
+ /**
2
+ * Policy Loader
3
+ *
4
+ * Loads and validates guardian policies from YAML files.
5
+ * Policies define the guardrails, rules, and configurations for the guardian.
6
+ */
7
+
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { resolve } from 'node:path';
10
+ import YAML from 'yaml';
11
+ import { z } from 'zod';
12
+ import type {
13
+ CircuitBreakerConfig,
14
+ CostLimitConfig,
15
+ GuardianMode,
16
+ GuardianPolicy,
17
+ GuardrailType,
18
+ PolicyRule,
19
+ RateLimitConfig,
20
+ ViolationAction,
21
+ ViolationSeverity,
22
+ } from './types';
23
+
24
+ // =============================================================================
25
+ // Schema Definitions
26
+ // =============================================================================
27
+
28
+ const ViolationSeveritySchema = z.enum(['low', 'medium', 'high', 'critical']);
29
+ const ViolationActionSchema = z.enum(['allow', 'warn', 'block', 'transform']);
30
+ const GuardianModeSchema = z.enum(['testing', 'guardian', 'hybrid']);
31
+ const GuardrailTypeSchema = z.enum([
32
+ 'input_validation',
33
+ 'output_validation',
34
+ 'action_validation',
35
+ 'intent_classification',
36
+ 'pii_detection',
37
+ 'injection_detection',
38
+ 'content_filter',
39
+ 'hallucination_check',
40
+ 'rate_limit',
41
+ 'cost_limit',
42
+ ]);
43
+
44
+ const PolicyConditionSchema = z.object({
45
+ field: z.string(),
46
+ operator: z.enum([
47
+ 'equals',
48
+ 'contains',
49
+ 'matches',
50
+ 'not_equals',
51
+ 'not_contains',
52
+ 'greater_than',
53
+ 'less_than',
54
+ ]),
55
+ value: z.union([z.string(), z.number(), z.boolean()]),
56
+ });
57
+
58
+ const PolicyRuleSchema = z.object({
59
+ id: z.string(),
60
+ name: z.string(),
61
+ description: z.string().optional(),
62
+ type: GuardrailTypeSchema,
63
+ enabled: z.boolean().default(true),
64
+ severity: ViolationSeveritySchema,
65
+ action: ViolationActionSchema,
66
+ config: z.record(z.unknown()).optional(),
67
+ conditions: z.array(PolicyConditionSchema).optional(),
68
+ });
69
+
70
+ const CircuitBreakerConfigSchema = z.object({
71
+ enabled: z.boolean().default(false),
72
+ threshold: z.number().min(1).default(5),
73
+ windowMs: z.number().min(1000).default(60000),
74
+ cooldownMs: z.number().min(1000).default(300000),
75
+ halfOpenRequests: z.number().min(1).default(3),
76
+ });
77
+
78
+ const RateLimitConfigSchema = z.object({
79
+ enabled: z.boolean().default(false),
80
+ requestsPerMinute: z.number().optional(),
81
+ requestsPerHour: z.number().optional(),
82
+ requestsPerDay: z.number().optional(),
83
+ burstLimit: z.number().optional(),
84
+ });
85
+
86
+ const CostLimitConfigSchema = z.object({
87
+ enabled: z.boolean().default(false),
88
+ maxCostPerRequest: z.number().optional(),
89
+ maxCostPerMinute: z.number().optional(),
90
+ maxCostPerHour: z.number().optional(),
91
+ maxCostPerDay: z.number().optional(),
92
+ currency: z.string().default('USD'),
93
+ });
94
+
95
+ const GuardianPolicySchema = z.object({
96
+ name: z.string(),
97
+ version: z.string().default('1.0'),
98
+ description: z.string().optional(),
99
+ mode: GuardianModeSchema.default('guardian'),
100
+ rules: z.array(PolicyRuleSchema).min(1),
101
+ defaults: z
102
+ .object({
103
+ severity: ViolationSeveritySchema.optional(),
104
+ action: ViolationActionSchema.optional(),
105
+ })
106
+ .optional(),
107
+ circuitBreaker: CircuitBreakerConfigSchema.optional(),
108
+ rateLimits: RateLimitConfigSchema.optional(),
109
+ costLimits: CostLimitConfigSchema.optional(),
110
+ });
111
+
112
+ // =============================================================================
113
+ // Policy Loader
114
+ // =============================================================================
115
+
116
+ /**
117
+ * Load a guardian policy from a YAML file
118
+ */
119
+ export function loadPolicy(filePath: string): GuardianPolicy {
120
+ const absolutePath = resolve(filePath);
121
+
122
+ if (!existsSync(absolutePath)) {
123
+ throw new PolicyLoadError(`Policy file not found: ${absolutePath}`);
124
+ }
125
+
126
+ try {
127
+ const content = readFileSync(absolutePath, 'utf-8');
128
+ return parsePolicy(content);
129
+ } catch (error) {
130
+ if (error instanceof PolicyLoadError) {
131
+ throw error;
132
+ }
133
+ throw new PolicyLoadError(`Failed to read policy file: ${(error as Error).message}`);
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Parse a guardian policy from YAML string
139
+ */
140
+ export function parsePolicy(yamlContent: string): GuardianPolicy {
141
+ let parsed: unknown;
142
+
143
+ try {
144
+ parsed = YAML.parse(yamlContent);
145
+ } catch (error) {
146
+ throw new PolicyLoadError(`Invalid YAML: ${(error as Error).message}`);
147
+ }
148
+
149
+ const result = GuardianPolicySchema.safeParse(parsed);
150
+
151
+ if (!result.success) {
152
+ const errors = result.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', ');
153
+ throw new PolicyValidationError(`Policy validation failed: ${errors}`);
154
+ }
155
+
156
+ return result.data as GuardianPolicy;
157
+ }
158
+
159
+ /**
160
+ * Validate a guardian policy object
161
+ */
162
+ export function validatePolicy(policy: unknown): GuardianPolicy {
163
+ const result = GuardianPolicySchema.safeParse(policy);
164
+
165
+ if (!result.success) {
166
+ const errors = result.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', ');
167
+ throw new PolicyValidationError(`Policy validation failed: ${errors}`);
168
+ }
169
+
170
+ return result.data as GuardianPolicy;
171
+ }
172
+
173
+ /**
174
+ * Create a default guardian policy
175
+ */
176
+ export function createDefaultPolicy(): GuardianPolicy {
177
+ return {
178
+ name: 'default-guardian-policy',
179
+ version: '1.0',
180
+ description: 'Default guardian policy with standard security rules',
181
+ mode: 'guardian' as GuardianMode,
182
+ rules: [
183
+ {
184
+ id: 'injection-detection',
185
+ name: 'Prompt Injection Detection',
186
+ description: 'Detect and block prompt injection attempts',
187
+ type: 'injection_detection' as GuardrailType,
188
+ enabled: true,
189
+ severity: 'critical' as ViolationSeverity,
190
+ action: 'block' as ViolationAction,
191
+ },
192
+ {
193
+ id: 'pii-detection',
194
+ name: 'PII Detection',
195
+ description: 'Detect and redact personally identifiable information',
196
+ type: 'pii_detection' as GuardrailType,
197
+ enabled: true,
198
+ severity: 'high' as ViolationSeverity,
199
+ action: 'transform' as ViolationAction,
200
+ config: {
201
+ redact: true,
202
+ allowedTypes: [],
203
+ },
204
+ },
205
+ {
206
+ id: 'content-filter',
207
+ name: 'Content Filter',
208
+ description: 'Filter harmful content categories',
209
+ type: 'content_filter' as GuardrailType,
210
+ enabled: true,
211
+ severity: 'high' as ViolationSeverity,
212
+ action: 'block' as ViolationAction,
213
+ config: {
214
+ blockedCategories: ['violence', 'hate_speech', 'self_harm', 'dangerous', 'illegal'],
215
+ warnCategories: ['harassment', 'misinformation'],
216
+ },
217
+ },
218
+ {
219
+ id: 'intent-classification',
220
+ name: 'Intent Classification',
221
+ description: 'Classify and assess risky intents',
222
+ type: 'intent_classification' as GuardrailType,
223
+ enabled: true,
224
+ severity: 'medium' as ViolationSeverity,
225
+ action: 'warn' as ViolationAction,
226
+ config: {
227
+ blockHighRisk: true,
228
+ confidenceThreshold: 0.7,
229
+ },
230
+ },
231
+ {
232
+ id: 'action-validation',
233
+ name: 'Action Validation',
234
+ description: 'Validate agent tool/function calls',
235
+ type: 'action_validation' as GuardrailType,
236
+ enabled: true,
237
+ severity: 'high' as ViolationSeverity,
238
+ action: 'block' as ViolationAction,
239
+ config: {
240
+ defaultAllow: false,
241
+ blockHighRisk: true,
242
+ },
243
+ },
244
+ ],
245
+ defaults: {
246
+ severity: 'medium' as ViolationSeverity,
247
+ action: 'warn' as ViolationAction,
248
+ },
249
+ circuitBreaker: {
250
+ enabled: true,
251
+ threshold: 5,
252
+ windowMs: 60000,
253
+ cooldownMs: 300000,
254
+ halfOpenRequests: 3,
255
+ } as CircuitBreakerConfig,
256
+ rateLimits: {
257
+ enabled: true,
258
+ requestsPerMinute: 100,
259
+ requestsPerHour: 1000,
260
+ burstLimit: 20,
261
+ } as RateLimitConfig,
262
+ costLimits: {
263
+ enabled: false,
264
+ currency: 'USD',
265
+ } as CostLimitConfig,
266
+ };
267
+ }
268
+
269
+ /**
270
+ * Merge two policies (second overrides first)
271
+ */
272
+ export function mergePolicies(
273
+ base: GuardianPolicy,
274
+ override: Partial<GuardianPolicy>
275
+ ): GuardianPolicy {
276
+ const merged: GuardianPolicy = {
277
+ ...base,
278
+ ...override,
279
+ name: override.name ?? base.name,
280
+ version: override.version ?? base.version,
281
+ mode: override.mode ?? base.mode,
282
+ rules: override.rules ?? base.rules,
283
+ defaults: {
284
+ ...base.defaults,
285
+ ...override.defaults,
286
+ },
287
+ circuitBreaker: override.circuitBreaker ?? base.circuitBreaker,
288
+ rateLimits: override.rateLimits ?? base.rateLimits,
289
+ costLimits: override.costLimits ?? base.costLimits,
290
+ };
291
+
292
+ return merged;
293
+ }
294
+
295
+ /**
296
+ * Get rules by type from a policy
297
+ */
298
+ export function getRulesByType(policy: GuardianPolicy, type: GuardrailType): PolicyRule[] {
299
+ return policy.rules.filter((rule) => rule.type === type && rule.enabled);
300
+ }
301
+
302
+ /**
303
+ * Check if a rule is enabled in the policy
304
+ */
305
+ export function isRuleEnabled(policy: GuardianPolicy, ruleId: string): boolean {
306
+ const rule = policy.rules.find((r) => r.id === ruleId);
307
+ return rule?.enabled ?? false;
308
+ }
309
+
310
+ // =============================================================================
311
+ // Error Classes
312
+ // =============================================================================
313
+
314
+ /**
315
+ * Error thrown when policy loading fails
316
+ */
317
+ export class PolicyLoadError extends Error {
318
+ constructor(message: string) {
319
+ super(message);
320
+ this.name = 'PolicyLoadError';
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Error thrown when policy validation fails
326
+ */
327
+ export class PolicyValidationError extends Error {
328
+ constructor(message: string) {
329
+ super(message);
330
+ this.name = 'PolicyValidationError';
331
+ }
332
+ }
333
+
334
+ // =============================================================================
335
+ // Policy Template Generator
336
+ // =============================================================================
337
+
338
+ /**
339
+ * Generate a YAML policy template
340
+ */
341
+ export function generatePolicyTemplate(): string {
342
+ return `# Guardian Policy Configuration
343
+ # This file defines the guardrails and security rules for your AI/LLM application.
344
+
345
+ name: my-guardian-policy
346
+ version: "1.0"
347
+ description: Custom guardian policy
348
+
349
+ # Operating mode: 'testing', 'guardian', or 'hybrid'
350
+ mode: guardian
351
+
352
+ # Default settings for all rules
353
+ defaults:
354
+ severity: medium
355
+ action: warn
356
+
357
+ # Guardrail rules
358
+ rules:
359
+ # Prompt injection detection
360
+ - id: injection-detection
361
+ name: Prompt Injection Detection
362
+ description: Detect and block prompt injection attempts
363
+ type: injection_detection
364
+ enabled: true
365
+ severity: critical
366
+ action: block
367
+
368
+ # PII detection and redaction
369
+ - id: pii-detection
370
+ name: PII Detection
371
+ description: Detect and redact personally identifiable information
372
+ type: pii_detection
373
+ enabled: true
374
+ severity: high
375
+ action: transform
376
+ config:
377
+ redact: true
378
+ allowedTypes: []
379
+
380
+ # Content filtering
381
+ - id: content-filter
382
+ name: Content Filter
383
+ description: Filter harmful content categories
384
+ type: content_filter
385
+ enabled: true
386
+ severity: high
387
+ action: block
388
+ config:
389
+ blockedCategories:
390
+ - violence
391
+ - hate_speech
392
+ - self_harm
393
+ - dangerous
394
+ - illegal
395
+ warnCategories:
396
+ - harassment
397
+ - misinformation
398
+
399
+ # Intent classification
400
+ - id: intent-classification
401
+ name: Intent Classification
402
+ description: Classify and assess risky intents
403
+ type: intent_classification
404
+ enabled: true
405
+ severity: medium
406
+ action: warn
407
+ config:
408
+ blockHighRisk: true
409
+ confidenceThreshold: 0.7
410
+
411
+ # Action/tool validation
412
+ - id: action-validation
413
+ name: Action Validation
414
+ description: Validate agent tool and function calls
415
+ type: action_validation
416
+ enabled: true
417
+ severity: high
418
+ action: block
419
+ config:
420
+ defaultAllow: false
421
+ blockHighRisk: true
422
+
423
+ # Circuit breaker configuration
424
+ circuitBreaker:
425
+ enabled: true
426
+ threshold: 5 # Number of violations to trigger
427
+ windowMs: 60000 # Time window in milliseconds (1 minute)
428
+ cooldownMs: 300000 # Cooldown period (5 minutes)
429
+ halfOpenRequests: 3 # Requests to allow in half-open state
430
+
431
+ # Rate limiting configuration
432
+ rateLimits:
433
+ enabled: true
434
+ requestsPerMinute: 100
435
+ requestsPerHour: 1000
436
+ burstLimit: 20
437
+
438
+ # Cost limiting configuration (optional)
439
+ costLimits:
440
+ enabled: false
441
+ maxCostPerRequest: 0.10
442
+ maxCostPerHour: 10.00
443
+ maxCostPerDay: 100.00
444
+ currency: USD
445
+ `;
446
+ }