@wardnmesh/sdk-node 0.2.3 → 0.4.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/README.md CHANGED
@@ -1,7 +1,20 @@
1
1
  # @wardnmesh/sdk-node
2
2
 
3
+ > **Latest Version: v0.4.0** (Released 2026-01-17)
4
+
3
5
  **WardnMesh.AI** (formerly AgentGuard) is an active defense middleware for AI Agents. This SDK allows you to verify LLM inputs/outputs, block prompt injections, and prevent data exfiltration in real-time.
4
6
 
7
+ ## ✨ What's New in v0.4.0
8
+
9
+ 🚨 **Breaking Changes**: Action-based architecture replaces boolean `allowed` field.
10
+
11
+ - ✅ **Granular Actions**: `block`, `confirm`, `warn`, `log`, `allow` instead of `true`/`false`
12
+ - ✅ **Confirmation Support**: Native user confirmation for high-risk operations
13
+ - ✅ **Enhanced Context**: Richer violation metadata with `recommendedAction` and `scope`
14
+ - ✅ **Fail-Closed Security**: Defensive design defaults to `'block'` on invalid states
15
+
16
+ 📖 [Migration Guide](MIGRATION_v0.4.0.md) | [CHANGELOG](CHANGELOG.md)
17
+
5
18
  ## Features
6
19
 
7
20
  - 🛡️ **Active Defense**: Blocks prompt injections, jailbreaks, and PII leaks.
@@ -13,9 +26,68 @@
13
26
  ## Installation
14
27
 
15
28
  ```bash
16
- npm install @wardnmesh/sdk-node
29
+ npm install @wardnmesh/sdk-node@0.4.0
17
30
  # or
18
- yarn add @wardnmesh/sdk-node
31
+ yarn add @wardnmesh/sdk-node@0.4.0
32
+ ```
33
+
34
+ ## v0.4.0 API Overview
35
+
36
+ The new action-based API provides fine-grained control over threat responses:
37
+
38
+ ```typescript
39
+ import { Wardn } from '@wardnmesh/sdk-node';
40
+
41
+ const guard = Wardn.getInstance();
42
+ const result = await guard.scan({ prompt: userInput });
43
+
44
+ // Handle different threat levels
45
+ switch (result.action) {
46
+ case 'block':
47
+ // Critical violation - deny immediately
48
+ throw new Error('Security violation');
49
+
50
+ case 'confirm':
51
+ // High-risk - request user approval
52
+ const approved = await getUserConfirmation(result.confirmationDetails);
53
+ if (!approved) throw new Error('Operation denied');
54
+ break;
55
+
56
+ case 'warn':
57
+ // Medium-risk - log warning and allow
58
+ console.warn('Security warning:', result.violations);
59
+ break;
60
+
61
+ case 'log':
62
+ // Low-risk - log for monitoring
63
+ console.log('Security event:', result.violations);
64
+ break;
65
+
66
+ case 'allow':
67
+ // No violations - safe to proceed
68
+ break;
69
+ }
70
+
71
+ // Continue with your logic...
72
+ ```
73
+
74
+ ### Confirmation Dialog Example
75
+
76
+ When `action === 'confirm'`, the SDK provides pre-formatted confirmation context:
77
+
78
+ ```typescript
79
+ if (result.action === 'confirm') {
80
+ const { message, timeout, defaultAction } = result.confirmationDetails;
81
+
82
+ console.log(message);
83
+ // ⚠️ Security Alert
84
+ // Rule: recursive_delete
85
+ // Severity: HIGH
86
+ // Description: Detected dangerous recursive delete operation
87
+
88
+ const approved = await getUserInput(); // Your confirmation UI
89
+ if (!approved) throw new Error('Operation denied by user');
90
+ }
19
91
  ```
20
92
 
21
93
  ## Quick Start
@@ -1,4 +1,4 @@
1
- import { ToolData, Violation, Rule, Detector, StateProvider, DetectorType } from '../types';
1
+ import { ToolData, Violation, Rule, Detector, StateProvider, DetectorType, ThreatAction } from '../types';
2
2
  /**
3
3
  * Abstract base detector class
4
4
  *
@@ -11,8 +11,25 @@ export declare abstract class BaseDetector implements Detector {
11
11
  * Generate unique violation ID
12
12
  */
13
13
  protected generateViolationId(): string;
14
+ /**
15
+ * v0.4.0: Map severity to recommended action, with optional rule action override
16
+ *
17
+ * Default mapping:
18
+ * - critical → block (immediate threat)
19
+ * - high → confirm (needs user approval)
20
+ * - medium → warn (notify but allow)
21
+ * - low → log (record only)
22
+ *
23
+ * Rules can override default mapping via rule.action
24
+ */
25
+ protected getRecommendedActionForSeverity(rule: Rule): ThreatAction;
26
+ /**
27
+ * v0.3.0: Determine scope description based on rule category
28
+ */
29
+ protected getScopeForCategory(category: string): string;
14
30
  /**
15
31
  * Create violation object
32
+ * v0.4.0: Use rule.action override for recommendedAction
16
33
  */
17
34
  protected createViolation(rule: Rule, toolData: ToolData, additionalInfo?: Record<string, unknown>): Violation;
18
35
  /**
@@ -14,8 +14,47 @@ class BaseDetector {
14
14
  // Note: Using substring() instead of deprecated substr()
15
15
  return `violation_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
16
16
  }
17
+ /**
18
+ * v0.4.0: Map severity to recommended action, with optional rule action override
19
+ *
20
+ * Default mapping:
21
+ * - critical → block (immediate threat)
22
+ * - high → confirm (needs user approval)
23
+ * - medium → warn (notify but allow)
24
+ * - low → log (record only)
25
+ *
26
+ * Rules can override default mapping via rule.action
27
+ */
28
+ getRecommendedActionForSeverity(rule) {
29
+ // Rule action override takes precedence
30
+ if (rule.action) {
31
+ return rule.action;
32
+ }
33
+ // Default severity-to-action mapping
34
+ switch (rule.severity) {
35
+ case 'critical': return 'block';
36
+ case 'high': return 'confirm'; // v0.4.0: Changed from 'warn' to 'confirm'
37
+ case 'medium': return 'warn';
38
+ case 'low': return 'log';
39
+ default: return 'block';
40
+ }
41
+ }
42
+ /**
43
+ * v0.3.0: Determine scope description based on rule category
44
+ */
45
+ getScopeForCategory(category) {
46
+ switch (category) {
47
+ case 'workflow': return 'Workflow safety';
48
+ case 'quality': return 'Code quality';
49
+ case 'safety': return 'Security';
50
+ case 'network_boundary': return 'Network access';
51
+ case 'supply_chain': return 'Supply chain';
52
+ default: return 'Security violation';
53
+ }
54
+ }
17
55
  /**
18
56
  * Create violation object
57
+ * v0.4.0: Use rule.action override for recommendedAction
19
58
  */
20
59
  createViolation(rule, toolData, additionalInfo) {
21
60
  return {
@@ -30,7 +69,10 @@ class BaseDetector {
30
69
  filePath: (toolData.parameters.file_path || toolData.parameters.TargetFile || toolData.parameters.AbsolutePath || toolData.parameters.path),
31
70
  additionalInfo
32
71
  },
33
- timestamp: new Date().toISOString()
72
+ timestamp: new Date().toISOString(),
73
+ // v0.4.0: Support rule.action override
74
+ recommendedAction: this.getRecommendedActionForSeverity(rule),
75
+ scope: this.getScopeForCategory(rule.category)
34
76
  };
35
77
  }
36
78
  /**
@@ -25,7 +25,10 @@ class StateDetector extends base_1.BaseDetector {
25
25
  additionalInfo: {
26
26
  message: `Required state '${config.requiredState}' is '${currentState || 'undefined'}', expected '${config.targetStateValue}'.`
27
27
  }
28
- }
28
+ },
29
+ // v0.4.0: Support rule.action override
30
+ recommendedAction: this.getRecommendedActionForSeverity(rule),
31
+ scope: this.getScopeForCategory(rule.category)
29
32
  };
30
33
  }
31
34
  if (config.stateDerivation?.validityDurationMs) {
@@ -46,7 +49,10 @@ class StateDetector extends base_1.BaseDetector {
46
49
  additionalInfo: {
47
50
  message: `Required state '${config.requiredState}' has expired (last verified ${Math.floor(timeDiff / 1000)}s ago).`
48
51
  }
49
- }
52
+ },
53
+ // v0.4.0: Support rule.action override
54
+ recommendedAction: this.getRecommendedActionForSeverity(rule),
55
+ scope: this.getScopeForCategory(rule.category)
50
56
  };
51
57
  }
52
58
  }
@@ -27,7 +27,8 @@ function createWardnMiddleware(config) {
27
27
  prompt: content,
28
28
  context: { source: "vercel-ai-sdk" },
29
29
  });
30
- if (!result.allowed) {
30
+ // v0.3.0: Check action instead of allowed
31
+ if (result.action === 'block') {
31
32
  throw new Error(`Security Violation: ${result.violations[0]?.description || "Blocked by Wardn"}`);
32
33
  }
33
34
  };
@@ -29,7 +29,8 @@ function createExpressMiddleware(guard, config) {
29
29
  return next();
30
30
  }
31
31
  const result = await guard.scan(wardnRequest);
32
- if (!result.allowed) {
32
+ // v0.3.0: Check action instead of allowed
33
+ if (result.action === 'block') {
33
34
  if (config?.onBlock) {
34
35
  return config.onBlock(req, res, result);
35
36
  }
@@ -28,7 +28,8 @@ function createNextMiddleware(config) {
28
28
  ip: req.ip || req.headers.get("x-forwarded-for") || "unknown",
29
29
  },
30
30
  });
31
- if (!result.allowed) {
31
+ // v0.3.0: Check action instead of allowed
32
+ if (result.action === 'block') {
32
33
  return server_1.NextResponse.json({
33
34
  error: "Request blocked by Wardn Security Policy",
34
35
  code: "WARDN_BLOCK",
package/dist/types.d.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  * Rule Schema - Core type definitions for WardnMesh rules
3
3
  */
4
4
  export type RuleCategory = "workflow" | "quality" | "safety" | "network_boundary" | "supply_chain";
5
- export type Severity = "critical" | "major" | "minor";
5
+ export type Severity = "critical" | "high" | "medium" | "low";
6
6
  export type DetectorType = "sequence" | "state" | "pattern" | "content_analysis" | "semantic";
7
+ export type ThreatAction = "allow" | "block" | "warn" | "log" | "confirm";
7
8
  export type EscalationLevel = "none" | "warning" | "critical" | "block";
8
9
  export interface SequenceDetectorConfig {
9
10
  lookback: number;
@@ -88,6 +89,7 @@ export interface Rule {
88
89
  };
89
90
  escalation: EscalationConfig;
90
91
  autofix?: AutofixConfig;
92
+ action?: ThreatAction;
91
93
  }
92
94
  export interface ToolData {
93
95
  toolName: string;
@@ -110,6 +112,8 @@ export interface Violation {
110
112
  description: string;
111
113
  context: ViolationContext;
112
114
  timestamp: string;
115
+ recommendedAction: ThreatAction;
116
+ scope?: string;
113
117
  }
114
118
  export interface ViolationContext {
115
119
  toolName: string;
@@ -198,9 +202,17 @@ export interface WardnRequest {
198
202
  metadata?: Record<string, unknown>;
199
203
  }
200
204
  export interface ScanResult {
201
- allowed: boolean;
205
+ action: ThreatAction;
202
206
  violations: Violation[];
203
207
  latencyMs: number;
204
208
  metadata: Record<string, unknown>;
209
+ confirmationDetails?: {
210
+ message: string;
211
+ timeout: number;
212
+ defaultAction: 'allow' | 'block';
213
+ ruleId: string;
214
+ ruleName: string;
215
+ severity: Severity;
216
+ };
205
217
  }
206
218
  export type PatternConfig = PatternDetectorConfig;
@@ -12,7 +12,7 @@ const VALID_DETECTOR_TYPES = [
12
12
  "content_analysis",
13
13
  "semantic",
14
14
  ];
15
- const VALID_SEVERITIES = ["critical", "major", "minor"];
15
+ const VALID_SEVERITIES = ["critical", "high", "medium", "low"];
16
16
  const VALID_CATEGORIES = [
17
17
  "workflow",
18
18
  "quality",
package/dist/wardn.d.ts CHANGED
@@ -33,12 +33,32 @@ export declare class Wardn {
33
33
  * @returns ScanResult with allowed/blocked status and violations
34
34
  */
35
35
  scan(request: WardnRequest): Promise<ScanResult>;
36
+ /**
37
+ * v0.3.0: Determine final action based on all violations
38
+ * Priority: block > confirm > warn > log > allow
39
+ *
40
+ * Defensive design: Uses fail-closed approach - defaults to 'block' if
41
+ * recommendedAction is missing or invalid, ensuring security by default.
42
+ */
43
+ private determineAction;
36
44
  /** Normalize request to ToolData format */
37
45
  private normalizeRequest;
38
46
  /** Run detector for a single rule */
39
47
  private detectViolation;
40
48
  /** Handle semantic detection */
41
49
  private detectSemanticViolation;
50
+ /**
51
+ * v0.4.0: Map severity to recommended action, with optional rule action override
52
+ *
53
+ * Default mapping:
54
+ * - critical → block (immediate threat)
55
+ * - high → confirm (needs user approval)
56
+ * - medium → warn (notify but allow)
57
+ * - low → log (record only)
58
+ *
59
+ * Rules can override default mapping via rule.action
60
+ */
61
+ private getRecommendedActionForSeverity;
42
62
  /** Report violation to telemetry */
43
63
  private reportViolation;
44
64
  /** Report scan completion to telemetry */
package/dist/wardn.js CHANGED
@@ -175,7 +175,7 @@ class Wardn {
175
175
  async scan(request) {
176
176
  if (this.isShutdown) {
177
177
  return {
178
- allowed: true,
178
+ action: 'allow',
179
179
  violations: [],
180
180
  latencyMs: 0,
181
181
  metadata: { error: true, errorDetails: "Wardn instance is shutdown" },
@@ -205,8 +205,10 @@ class Wardn {
205
205
  }
206
206
  }
207
207
  await this.stateProvider.setState(currentSessionId, stateAdapter.exportState());
208
+ // v0.3.0: Determine action based on violations
209
+ const action = this.determineAction(violations);
208
210
  const result = {
209
- allowed: !violations.some((v) => v.severity === "critical"),
211
+ action,
210
212
  violations,
211
213
  latencyMs: Date.now() - startTime,
212
214
  metadata: {
@@ -214,6 +216,35 @@ class Wardn {
214
216
  sessionId: currentSessionId,
215
217
  },
216
218
  };
219
+ // v0.4.0: Add confirmation details if action is 'confirm'
220
+ if (action === 'confirm') {
221
+ const confirmViolation = violations.find(v => v.recommendedAction === 'confirm');
222
+ if (confirmViolation) {
223
+ // Extract metadata if available, otherwise use defaults
224
+ const metadata = (confirmViolation.context.additionalInfo?.metadata || {});
225
+ // Generate enhanced default message with violation context
226
+ const additionalDetails = confirmViolation.context.additionalInfo?.message
227
+ ? `\nDetails: ${confirmViolation.context.additionalInfo.message}`
228
+ : '';
229
+ const defaultMessage = `⚠️ Security Alert
230
+
231
+ Rule: ${confirmViolation.ruleName}
232
+ Severity: ${confirmViolation.severity.toUpperCase()}
233
+ Tool: ${confirmViolation.context.toolName}
234
+
235
+ Description: ${confirmViolation.description}${additionalDetails}
236
+
237
+ This operation requires your approval to proceed.`;
238
+ result.confirmationDetails = {
239
+ message: metadata.confirmationMessage || defaultMessage,
240
+ timeout: metadata.timeout || 30000,
241
+ defaultAction: metadata.defaultAction || 'block',
242
+ ruleId: confirmViolation.ruleId,
243
+ ruleName: confirmViolation.ruleName,
244
+ severity: confirmViolation.severity,
245
+ };
246
+ }
247
+ }
217
248
  this.reportScanComplete(result, currentSessionId);
218
249
  return result;
219
250
  }
@@ -229,9 +260,9 @@ class Wardn {
229
260
  },
230
261
  });
231
262
  // Configurable fail mode
232
- const allowed = failMode === "open";
263
+ const action = failMode === "open" ? "allow" : "block";
233
264
  return {
234
- allowed,
265
+ action,
235
266
  violations: [],
236
267
  latencyMs: Date.now() - startTime,
237
268
  metadata: {
@@ -242,6 +273,40 @@ class Wardn {
242
273
  };
243
274
  }
244
275
  }
276
+ /**
277
+ * v0.3.0: Determine final action based on all violations
278
+ * Priority: block > confirm > warn > log > allow
279
+ *
280
+ * Defensive design: Uses fail-closed approach - defaults to 'block' if
281
+ * recommendedAction is missing or invalid, ensuring security by default.
282
+ */
283
+ determineAction(violations) {
284
+ if (violations.length === 0) {
285
+ return 'allow';
286
+ }
287
+ // Define action priority order
288
+ const actionPriority = ['block', 'confirm', 'warn', 'log', 'allow'];
289
+ const validActions = new Set(actionPriority);
290
+ // Find highest priority action from all violations
291
+ for (const action of actionPriority) {
292
+ const hasAction = violations.some(v => {
293
+ // Defensive: validate recommendedAction exists and is valid
294
+ const recommended = v.recommendedAction;
295
+ if (!recommended || !validActions.has(recommended)) {
296
+ // Fail-closed: log warning and treat as 'block'
297
+ logger_1.logger.warn(`Invalid recommendedAction '${recommended}' in violation ${v.id}, defaulting to 'block'`);
298
+ return action === 'block';
299
+ }
300
+ return recommended === action;
301
+ });
302
+ if (hasAction) {
303
+ return action;
304
+ }
305
+ }
306
+ // Fallback: should never reach here, but fail-closed for safety
307
+ logger_1.logger.warn('determineAction fallback: no valid action found, defaulting to block');
308
+ return 'block';
309
+ }
245
310
  /** Normalize request to ToolData format */
246
311
  normalizeRequest(request) {
247
312
  return {
@@ -287,8 +352,41 @@ class Wardn {
287
352
  additionalInfo: { score },
288
353
  },
289
354
  timestamp: new Date().toISOString(),
355
+ // v0.4.0: Set recommended action (rule.action or default severity mapping)
356
+ recommendedAction: this.getRecommendedActionForSeverity(rule),
357
+ scope: 'Semantic analysis',
290
358
  };
291
359
  }
360
+ /**
361
+ * v0.4.0: Map severity to recommended action, with optional rule action override
362
+ *
363
+ * Default mapping:
364
+ * - critical → block (immediate threat)
365
+ * - high → confirm (needs user approval)
366
+ * - medium → warn (notify but allow)
367
+ * - low → log (record only)
368
+ *
369
+ * Rules can override default mapping via rule.action
370
+ */
371
+ getRecommendedActionForSeverity(rule) {
372
+ // Rule action override takes precedence
373
+ if (rule.action) {
374
+ return rule.action;
375
+ }
376
+ // Default severity-to-action mapping
377
+ switch (rule.severity) {
378
+ case 'critical':
379
+ return 'block';
380
+ case 'high':
381
+ return 'confirm'; // v0.4.0: Changed from 'warn' to 'confirm'
382
+ case 'medium':
383
+ return 'warn';
384
+ case 'low':
385
+ return 'log';
386
+ default:
387
+ return 'block'; // Safe default
388
+ }
389
+ }
292
390
  /** Report violation to telemetry */
293
391
  reportViolation(violation, toolData, sessionId) {
294
392
  // REDACTION: Create a safe copy for the cloud
@@ -311,7 +409,7 @@ class Wardn {
311
409
  eventType: "scan_complete",
312
410
  timestamp: new Date().toISOString(),
313
411
  data: {
314
- allowed: result.allowed,
412
+ action: result.action,
315
413
  latencyMs: result.latencyMs,
316
414
  violationCount: result.violations.length,
317
415
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wardnmesh/sdk-node",
3
- "version": "0.2.3",
3
+ "version": "0.4.0",
4
4
  "description": "WardnMesh.AI Node.js SDK - Active Defense Middleware for AI Agents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",