veto-sdk 1.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/README.md +209 -0
- package/dist/benchmark/cli.d.ts +22 -0
- package/dist/benchmark/cli.d.ts.map +1 -0
- package/dist/benchmark/cli.js +238 -0
- package/dist/benchmark/cli.js.map +1 -0
- package/dist/benchmark/index.d.ts +10 -0
- package/dist/benchmark/index.d.ts.map +1 -0
- package/dist/benchmark/index.js +10 -0
- package/dist/benchmark/index.js.map +1 -0
- package/dist/benchmark/loader.d.ts +19 -0
- package/dist/benchmark/loader.d.ts.map +1 -0
- package/dist/benchmark/loader.js +321 -0
- package/dist/benchmark/loader.js.map +1 -0
- package/dist/benchmark/metrics.d.ts +35 -0
- package/dist/benchmark/metrics.d.ts.map +1 -0
- package/dist/benchmark/metrics.js +195 -0
- package/dist/benchmark/metrics.js.map +1 -0
- package/dist/benchmark/runner.d.ts +39 -0
- package/dist/benchmark/runner.d.ts.map +1 -0
- package/dist/benchmark/runner.js +279 -0
- package/dist/benchmark/runner.js.map +1 -0
- package/dist/benchmark/types.d.ts +188 -0
- package/dist/benchmark/types.d.ts.map +1 -0
- package/dist/benchmark/types.js +24 -0
- package/dist/benchmark/types.js.map +1 -0
- package/dist/cli/bin.d.ts +8 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +120 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/config.d.ts +126 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +137 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +64 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +160 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/templates.d.ts +22 -0
- package/dist/cli/templates.d.ts.map +1 -0
- package/dist/cli/templates.js +132 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/core/history.d.ts +104 -0
- package/dist/core/history.d.ts.map +1 -0
- package/dist/core/history.js +148 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/index.d.ts +10 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/interceptor.d.ts +96 -0
- package/dist/core/interceptor.d.ts.map +1 -0
- package/dist/core/interceptor.js +227 -0
- package/dist/core/interceptor.js.map +1 -0
- package/dist/core/validator.d.ts +107 -0
- package/dist/core/validator.d.ts.map +1 -0
- package/dist/core/validator.js +263 -0
- package/dist/core/validator.js.map +1 -0
- package/dist/core/veto.d.ts +265 -0
- package/dist/core/veto.d.ts.map +1 -0
- package/dist/core/veto.js +681 -0
- package/dist/core/veto.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/client.d.ts +82 -0
- package/dist/kernel/client.d.ts.map +1 -0
- package/dist/kernel/client.js +162 -0
- package/dist/kernel/client.js.map +1 -0
- package/dist/kernel/index.d.ts +9 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +9 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/kernel/prompt.d.ts +27 -0
- package/dist/kernel/prompt.d.ts.map +1 -0
- package/dist/kernel/prompt.js +127 -0
- package/dist/kernel/prompt.js.map +1 -0
- package/dist/kernel/types.d.ts +85 -0
- package/dist/kernel/types.d.ts.map +1 -0
- package/dist/kernel/types.js +52 -0
- package/dist/kernel/types.js.map +1 -0
- package/dist/providers/adapters.d.ts +167 -0
- package/dist/providers/adapters.d.ts.map +1 -0
- package/dist/providers/adapters.js +244 -0
- package/dist/providers/adapters.js.map +1 -0
- package/dist/providers/index.d.ts +11 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/types.d.ts +92 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +10 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/rules/api-client.d.ts +103 -0
- package/dist/rules/api-client.d.ts.map +1 -0
- package/dist/rules/api-client.js +241 -0
- package/dist/rules/api-client.js.map +1 -0
- package/dist/rules/index.d.ts +10 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +10 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/loader.d.ts +116 -0
- package/dist/rules/loader.d.ts.map +1 -0
- package/dist/rules/loader.js +300 -0
- package/dist/rules/loader.js.map +1 -0
- package/dist/rules/rule-validator.d.ts +135 -0
- package/dist/rules/rule-validator.d.ts.map +1 -0
- package/dist/rules/rule-validator.js +239 -0
- package/dist/rules/rule-validator.js.map +1 -0
- package/dist/rules/types.d.ts +162 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +16 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/types/config.d.ts +171 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +31 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/tool.d.ts +156 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +27 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/utils/glob.d.ts +21 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/glob.js +147 -0
- package/dist/utils/glob.js.map +1 -0
- package/dist/utils/id.d.ts +28 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +43 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +97 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +153 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML rule loader and parser.
|
|
3
|
+
*
|
|
4
|
+
* Loads rules from YAML files and builds an indexed structure for
|
|
5
|
+
* efficient rule lookup during validation.
|
|
6
|
+
*
|
|
7
|
+
* @module rules/loader
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
10
|
+
import { join, extname } from 'node:path';
|
|
11
|
+
/**
|
|
12
|
+
* Default YAML parser that throws an error.
|
|
13
|
+
* Users must provide their own parser.
|
|
14
|
+
*/
|
|
15
|
+
function defaultYamlParser() {
|
|
16
|
+
throw new Error('No YAML parser provided. Please provide a YAML parser function (e.g., from js-yaml package).');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Loads and manages YAML-based rules.
|
|
20
|
+
*/
|
|
21
|
+
export class RuleLoader {
|
|
22
|
+
logger;
|
|
23
|
+
yamlParser = defaultYamlParser;
|
|
24
|
+
loadedRules = {
|
|
25
|
+
ruleSets: [],
|
|
26
|
+
allRules: [],
|
|
27
|
+
rulesByTool: new Map(),
|
|
28
|
+
globalRules: [],
|
|
29
|
+
sourceFiles: [],
|
|
30
|
+
};
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.logger = options.logger;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Set the YAML parser to use for loading rules.
|
|
36
|
+
*
|
|
37
|
+
* @param parser - YAML parsing function
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import yaml from 'js-yaml';
|
|
42
|
+
* loader.setYamlParser(yaml.load);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
setYamlParser(parser) {
|
|
46
|
+
this.yamlParser = parser;
|
|
47
|
+
this.logger.debug('YAML parser configured');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Load rules from a directory containing YAML files.
|
|
51
|
+
*
|
|
52
|
+
* @param dirPath - Path to the directory
|
|
53
|
+
* @param recursive - Whether to search subdirectories
|
|
54
|
+
* @returns Loaded rules
|
|
55
|
+
*/
|
|
56
|
+
loadFromDirectory(dirPath, recursive = true) {
|
|
57
|
+
this.logger.info('Loading rules from directory', { path: dirPath, recursive });
|
|
58
|
+
if (!existsSync(dirPath)) {
|
|
59
|
+
this.logger.warn('Rules directory does not exist', { path: dirPath });
|
|
60
|
+
return this.loadedRules;
|
|
61
|
+
}
|
|
62
|
+
const yamlFiles = this.findYamlFiles(dirPath, recursive);
|
|
63
|
+
this.logger.debug('Found YAML files', { count: yamlFiles.length });
|
|
64
|
+
for (const filePath of yamlFiles) {
|
|
65
|
+
try {
|
|
66
|
+
this.loadFromFile(filePath);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.logger.error('Failed to load rule file', { path: filePath }, error instanceof Error ? error : new Error(String(error)));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this.buildIndex();
|
|
73
|
+
return this.loadedRules;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Load rules from a single YAML file.
|
|
77
|
+
*
|
|
78
|
+
* @param filePath - Path to the YAML file
|
|
79
|
+
*/
|
|
80
|
+
loadFromFile(filePath) {
|
|
81
|
+
this.logger.debug('Loading rules from file', { path: filePath });
|
|
82
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
83
|
+
const parsed = this.yamlParser(content);
|
|
84
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
85
|
+
this.logger.warn('Invalid YAML content', { path: filePath });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const ruleSet = this.parseRuleSet(parsed, filePath);
|
|
89
|
+
if (ruleSet) {
|
|
90
|
+
this.loadedRules.ruleSets.push(ruleSet);
|
|
91
|
+
this.loadedRules.sourceFiles.push(filePath);
|
|
92
|
+
this.logger.info('Loaded rule set', {
|
|
93
|
+
name: ruleSet.name,
|
|
94
|
+
ruleCount: ruleSet.rules.length,
|
|
95
|
+
path: filePath,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Load rules from a YAML string.
|
|
101
|
+
*
|
|
102
|
+
* @param content - YAML content
|
|
103
|
+
* @param sourceName - Name to identify the source
|
|
104
|
+
*/
|
|
105
|
+
loadFromString(content, sourceName = 'inline') {
|
|
106
|
+
this.logger.debug('Loading rules from string', { source: sourceName });
|
|
107
|
+
const parsed = this.yamlParser(content);
|
|
108
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
109
|
+
this.logger.warn('Invalid YAML content', { source: sourceName });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const ruleSet = this.parseRuleSet(parsed, sourceName);
|
|
113
|
+
if (ruleSet) {
|
|
114
|
+
this.loadedRules.ruleSets.push(ruleSet);
|
|
115
|
+
this.loadedRules.sourceFiles.push(sourceName);
|
|
116
|
+
this.buildIndex();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Add rules directly without YAML parsing.
|
|
121
|
+
*
|
|
122
|
+
* @param rules - Rules to add
|
|
123
|
+
* @param setName - Name for the rule set
|
|
124
|
+
*/
|
|
125
|
+
addRules(rules, setName = 'programmatic') {
|
|
126
|
+
const ruleSet = {
|
|
127
|
+
version: '1.0',
|
|
128
|
+
name: setName,
|
|
129
|
+
rules,
|
|
130
|
+
};
|
|
131
|
+
this.loadedRules.ruleSets.push(ruleSet);
|
|
132
|
+
this.buildIndex();
|
|
133
|
+
this.logger.info('Added rules programmatically', {
|
|
134
|
+
name: setName,
|
|
135
|
+
count: rules.length,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get all loaded rules.
|
|
140
|
+
*/
|
|
141
|
+
getRules() {
|
|
142
|
+
return this.loadedRules;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get rules applicable to a specific tool.
|
|
146
|
+
*
|
|
147
|
+
* @param toolName - Name of the tool
|
|
148
|
+
* @returns Rules that apply to the tool
|
|
149
|
+
*/
|
|
150
|
+
getRulesForTool(toolName) {
|
|
151
|
+
const toolSpecific = this.loadedRules.rulesByTool.get(toolName) ?? [];
|
|
152
|
+
return [...this.loadedRules.globalRules, ...toolSpecific].filter((rule) => rule.enabled);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Clear all loaded rules.
|
|
156
|
+
*/
|
|
157
|
+
clear() {
|
|
158
|
+
this.loadedRules = {
|
|
159
|
+
ruleSets: [],
|
|
160
|
+
allRules: [],
|
|
161
|
+
rulesByTool: new Map(),
|
|
162
|
+
globalRules: [],
|
|
163
|
+
sourceFiles: [],
|
|
164
|
+
};
|
|
165
|
+
this.logger.debug('Cleared all rules');
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Reload rules from previously loaded sources.
|
|
169
|
+
*/
|
|
170
|
+
reload() {
|
|
171
|
+
const sources = [...this.loadedRules.sourceFiles];
|
|
172
|
+
this.clear();
|
|
173
|
+
for (const source of sources) {
|
|
174
|
+
if (existsSync(source)) {
|
|
175
|
+
this.loadFromFile(source);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
this.buildIndex();
|
|
179
|
+
this.logger.info('Reloaded rules', { sourceCount: sources.length });
|
|
180
|
+
return this.loadedRules;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Find YAML files in a directory.
|
|
184
|
+
*/
|
|
185
|
+
findYamlFiles(dirPath, recursive) {
|
|
186
|
+
const files = [];
|
|
187
|
+
const entries = readdirSync(dirPath);
|
|
188
|
+
for (const entry of entries) {
|
|
189
|
+
const fullPath = join(dirPath, entry);
|
|
190
|
+
const stat = statSync(fullPath);
|
|
191
|
+
if (stat.isDirectory() && recursive) {
|
|
192
|
+
files.push(...this.findYamlFiles(fullPath, recursive));
|
|
193
|
+
}
|
|
194
|
+
else if (stat.isFile()) {
|
|
195
|
+
const ext = extname(entry).toLowerCase();
|
|
196
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
197
|
+
files.push(fullPath);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return files;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Parse a rule set from parsed YAML.
|
|
205
|
+
*/
|
|
206
|
+
parseRuleSet(data, source) {
|
|
207
|
+
// Check if this is a rule set format or just a list of rules
|
|
208
|
+
if (Array.isArray(data)) {
|
|
209
|
+
// It's just an array of rules
|
|
210
|
+
return {
|
|
211
|
+
version: '1.0',
|
|
212
|
+
name: source,
|
|
213
|
+
rules: data.map((r, i) => this.parseRule(r, `${source}:rule-${i}`)),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
// Check for rules array in the object
|
|
217
|
+
const rules = data.rules;
|
|
218
|
+
if (!rules || !Array.isArray(rules)) {
|
|
219
|
+
// Maybe it's a single rule
|
|
220
|
+
if (data.id && data.name) {
|
|
221
|
+
return {
|
|
222
|
+
version: '1.0',
|
|
223
|
+
name: source,
|
|
224
|
+
rules: [this.parseRule(data, source)],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
this.logger.warn('No rules found in file', { source });
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
version: data.version ?? '1.0',
|
|
232
|
+
name: data.name ?? source,
|
|
233
|
+
description: data.description,
|
|
234
|
+
rules: rules.map((r, i) => this.parseRule(r, `${source}:rule-${i}`)),
|
|
235
|
+
settings: data.settings,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Parse a single rule from YAML data.
|
|
240
|
+
*/
|
|
241
|
+
parseRule(data, source) {
|
|
242
|
+
if (!data || typeof data !== 'object') {
|
|
243
|
+
throw new Error(`Invalid rule at ${source}`);
|
|
244
|
+
}
|
|
245
|
+
const ruleData = data;
|
|
246
|
+
return {
|
|
247
|
+
id: ruleData.id ?? `auto-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
248
|
+
name: ruleData.name ?? 'Unnamed Rule',
|
|
249
|
+
description: ruleData.description,
|
|
250
|
+
enabled: ruleData.enabled !== false, // Default to true
|
|
251
|
+
severity: ruleData.severity ?? 'medium',
|
|
252
|
+
action: ruleData.action ?? 'block',
|
|
253
|
+
tools: ruleData.tools,
|
|
254
|
+
conditions: ruleData.conditions,
|
|
255
|
+
condition_groups: ruleData.condition_groups,
|
|
256
|
+
tags: ruleData.tags,
|
|
257
|
+
metadata: ruleData.metadata,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Build the rule index for efficient lookup.
|
|
262
|
+
*/
|
|
263
|
+
buildIndex() {
|
|
264
|
+
this.loadedRules.allRules = [];
|
|
265
|
+
this.loadedRules.rulesByTool = new Map();
|
|
266
|
+
this.loadedRules.globalRules = [];
|
|
267
|
+
for (const ruleSet of this.loadedRules.ruleSets) {
|
|
268
|
+
for (const rule of ruleSet.rules) {
|
|
269
|
+
this.loadedRules.allRules.push(rule);
|
|
270
|
+
if (!rule.tools || rule.tools.length === 0) {
|
|
271
|
+
// Global rule applies to all tools
|
|
272
|
+
this.loadedRules.globalRules.push(rule);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// Tool-specific rule
|
|
276
|
+
for (const toolName of rule.tools) {
|
|
277
|
+
const existing = this.loadedRules.rulesByTool.get(toolName) ?? [];
|
|
278
|
+
existing.push(rule);
|
|
279
|
+
this.loadedRules.rulesByTool.set(toolName, existing);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
this.logger.debug('Built rule index', {
|
|
285
|
+
totalRules: this.loadedRules.allRules.length,
|
|
286
|
+
globalRules: this.loadedRules.globalRules.length,
|
|
287
|
+
toolsWithRules: this.loadedRules.rulesByTool.size,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Create a new rule loader.
|
|
293
|
+
*
|
|
294
|
+
* @param options - Loader options
|
|
295
|
+
* @returns RuleLoader instance
|
|
296
|
+
*/
|
|
297
|
+
export function createRuleLoader(options) {
|
|
298
|
+
return new RuleLoader(options);
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/rules/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-based validator.
|
|
3
|
+
*
|
|
4
|
+
* This validator loads rules from YAML files and validates tool calls
|
|
5
|
+
* by sending them to an external API.
|
|
6
|
+
*
|
|
7
|
+
* @module rules/rule-validator
|
|
8
|
+
*/
|
|
9
|
+
import type { Logger } from '../utils/logger.js';
|
|
10
|
+
import type { ValidationContext, ValidationResult, NamedValidator } from '../types/config.js';
|
|
11
|
+
import type { Rule } from './types.js';
|
|
12
|
+
import { RuleLoader, type YamlParser } from './loader.js';
|
|
13
|
+
import { ValidationAPIClient, type ValidationAPIConfig } from './api-client.js';
|
|
14
|
+
/**
|
|
15
|
+
* Configuration for the rule-based validator.
|
|
16
|
+
*/
|
|
17
|
+
export interface RuleValidatorConfig {
|
|
18
|
+
/** API configuration */
|
|
19
|
+
api: ValidationAPIConfig;
|
|
20
|
+
/** Path to directory containing rule YAML files */
|
|
21
|
+
rulesDir?: string;
|
|
22
|
+
/** YAML parser function (e.g., from js-yaml) */
|
|
23
|
+
yamlParser?: YamlParser;
|
|
24
|
+
/** Whether to search subdirectories for rules */
|
|
25
|
+
recursiveRuleSearch?: boolean;
|
|
26
|
+
/** Behavior when API is unavailable */
|
|
27
|
+
failMode?: 'open' | 'closed';
|
|
28
|
+
/** Session ID for tracking */
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
/** Agent ID for tracking */
|
|
31
|
+
agentId?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Options for the rule validator.
|
|
35
|
+
*/
|
|
36
|
+
export interface RuleValidatorOptions {
|
|
37
|
+
/** Configuration */
|
|
38
|
+
config: RuleValidatorConfig;
|
|
39
|
+
/** Logger instance */
|
|
40
|
+
logger: Logger;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Rule-based validator that uses an external API for decisions.
|
|
44
|
+
*
|
|
45
|
+
* This validator:
|
|
46
|
+
* 1. Loads rules from YAML files
|
|
47
|
+
* 2. For each tool call, finds applicable rules
|
|
48
|
+
* 3. Sends the context and rules to an API
|
|
49
|
+
* 4. Returns the decision from the API
|
|
50
|
+
*/
|
|
51
|
+
export declare class RuleValidator {
|
|
52
|
+
private readonly logger;
|
|
53
|
+
private readonly config;
|
|
54
|
+
private readonly ruleLoader;
|
|
55
|
+
private readonly apiClient;
|
|
56
|
+
private readonly sessionId?;
|
|
57
|
+
private readonly agentId?;
|
|
58
|
+
private isInitialized;
|
|
59
|
+
constructor(options: RuleValidatorOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the validator by loading rules.
|
|
62
|
+
*
|
|
63
|
+
* Call this before using the validator if rules are loaded from files.
|
|
64
|
+
*/
|
|
65
|
+
initialize(): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Set the YAML parser.
|
|
68
|
+
*/
|
|
69
|
+
setYamlParser(parser: YamlParser): void;
|
|
70
|
+
/**
|
|
71
|
+
* Add rules programmatically.
|
|
72
|
+
*/
|
|
73
|
+
addRules(rules: Rule[], setName?: string): void;
|
|
74
|
+
/**
|
|
75
|
+
* Load rules from a YAML string.
|
|
76
|
+
*/
|
|
77
|
+
loadRulesFromString(yamlContent: string, sourceName?: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Get the rule loader for direct access.
|
|
80
|
+
*/
|
|
81
|
+
getRuleLoader(): RuleLoader;
|
|
82
|
+
/**
|
|
83
|
+
* Get the API client for direct access.
|
|
84
|
+
*/
|
|
85
|
+
getAPIClient(): ValidationAPIClient;
|
|
86
|
+
/**
|
|
87
|
+
* Validate a tool call.
|
|
88
|
+
*
|
|
89
|
+
* @param context - Validation context from Veto
|
|
90
|
+
* @returns Validation result
|
|
91
|
+
*/
|
|
92
|
+
validate(context: ValidationContext): Promise<ValidationResult>;
|
|
93
|
+
/**
|
|
94
|
+
* Create a NamedValidator for use with Veto.
|
|
95
|
+
*
|
|
96
|
+
* @returns Named validator instance
|
|
97
|
+
*/
|
|
98
|
+
toNamedValidator(): NamedValidator;
|
|
99
|
+
/**
|
|
100
|
+
* Build the API context from the validation context.
|
|
101
|
+
*/
|
|
102
|
+
private buildToolCallContext;
|
|
103
|
+
/**
|
|
104
|
+
* Build a summary of call history for the API.
|
|
105
|
+
*/
|
|
106
|
+
private buildHistorySummary;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a rule-based validator.
|
|
110
|
+
*
|
|
111
|
+
* @param options - Validator options
|
|
112
|
+
* @returns RuleValidator instance
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* import yaml from 'js-yaml';
|
|
117
|
+
*
|
|
118
|
+
* const ruleValidator = createRuleValidator({
|
|
119
|
+
* config: {
|
|
120
|
+
* api: { baseUrl: 'http://localhost:8080' },
|
|
121
|
+
* rulesDir: './rules',
|
|
122
|
+
* yamlParser: yaml.load,
|
|
123
|
+
* },
|
|
124
|
+
* logger: createLogger('info'),
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* await ruleValidator.initialize();
|
|
128
|
+
*
|
|
129
|
+
* const veto = new Veto({
|
|
130
|
+
* validators: [ruleValidator.toNamedValidator()],
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function createRuleValidator(options: RuleValidatorOptions): RuleValidator;
|
|
135
|
+
//# sourceMappingURL=rule-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-validator.d.ts","sourceRoot":"","sources":["../../src/rules/rule-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,IAAI,EAA2C,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wBAAwB;IACxB,GAAG,EAAE,mBAAmB,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iDAAiD;IACjD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oBAAoB;IACpB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,aAAa,CAAS;gBAElB,OAAO,EAAE,oBAAoB;IA2BzC;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBjC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIvC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAI/C;;OAEG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAInE;;OAEG;IACH,aAAa,IAAI,UAAU;IAI3B;;OAEG;IACH,YAAY,IAAI,mBAAmB;IAInC;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsErE;;;;OAIG;IACH,gBAAgB,IAAI,cAAc;IASlC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAS5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAEhF"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-based validator.
|
|
3
|
+
*
|
|
4
|
+
* This validator loads rules from YAML files and validates tool calls
|
|
5
|
+
* by sending them to an external API.
|
|
6
|
+
*
|
|
7
|
+
* @module rules/rule-validator
|
|
8
|
+
*/
|
|
9
|
+
import { RuleLoader } from './loader.js';
|
|
10
|
+
import { ValidationAPIClient } from './api-client.js';
|
|
11
|
+
/**
|
|
12
|
+
* Rule-based validator that uses an external API for decisions.
|
|
13
|
+
*
|
|
14
|
+
* This validator:
|
|
15
|
+
* 1. Loads rules from YAML files
|
|
16
|
+
* 2. For each tool call, finds applicable rules
|
|
17
|
+
* 3. Sends the context and rules to an API
|
|
18
|
+
* 4. Returns the decision from the API
|
|
19
|
+
*/
|
|
20
|
+
export class RuleValidator {
|
|
21
|
+
logger;
|
|
22
|
+
config;
|
|
23
|
+
ruleLoader;
|
|
24
|
+
apiClient;
|
|
25
|
+
sessionId;
|
|
26
|
+
agentId;
|
|
27
|
+
isInitialized = false;
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.logger = options.logger;
|
|
30
|
+
this.config = options.config;
|
|
31
|
+
this.sessionId = options.config.sessionId;
|
|
32
|
+
this.agentId = options.config.agentId;
|
|
33
|
+
// Initialize rule loader
|
|
34
|
+
this.ruleLoader = new RuleLoader({ logger: this.logger });
|
|
35
|
+
// Set YAML parser if provided
|
|
36
|
+
if (this.config.yamlParser) {
|
|
37
|
+
this.ruleLoader.setYamlParser(this.config.yamlParser);
|
|
38
|
+
}
|
|
39
|
+
// Initialize API client
|
|
40
|
+
this.apiClient = new ValidationAPIClient({
|
|
41
|
+
config: this.config.api,
|
|
42
|
+
logger: this.logger,
|
|
43
|
+
failMode: this.config.failMode,
|
|
44
|
+
});
|
|
45
|
+
this.logger.info('Rule validator created', {
|
|
46
|
+
rulesDir: this.config.rulesDir,
|
|
47
|
+
apiEndpoint: this.config.api.baseUrl + (this.config.api.endpoint ?? '/tool/call/check'),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the validator by loading rules.
|
|
52
|
+
*
|
|
53
|
+
* Call this before using the validator if rules are loaded from files.
|
|
54
|
+
*/
|
|
55
|
+
async initialize() {
|
|
56
|
+
if (this.isInitialized) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (this.config.rulesDir) {
|
|
60
|
+
if (!this.config.yamlParser) {
|
|
61
|
+
this.logger.warn('Rules directory specified but no YAML parser provided. ' +
|
|
62
|
+
'Call setYamlParser() before initialize() or use addRules().');
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.ruleLoader.loadFromDirectory(this.config.rulesDir, this.config.recursiveRuleSearch ?? true);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
this.isInitialized = true;
|
|
69
|
+
this.logger.info('Rule validator initialized', {
|
|
70
|
+
totalRules: this.ruleLoader.getRules().allRules.length,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Set the YAML parser.
|
|
75
|
+
*/
|
|
76
|
+
setYamlParser(parser) {
|
|
77
|
+
this.ruleLoader.setYamlParser(parser);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Add rules programmatically.
|
|
81
|
+
*/
|
|
82
|
+
addRules(rules, setName) {
|
|
83
|
+
this.ruleLoader.addRules(rules, setName);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Load rules from a YAML string.
|
|
87
|
+
*/
|
|
88
|
+
loadRulesFromString(yamlContent, sourceName) {
|
|
89
|
+
this.ruleLoader.loadFromString(yamlContent, sourceName);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the rule loader for direct access.
|
|
93
|
+
*/
|
|
94
|
+
getRuleLoader() {
|
|
95
|
+
return this.ruleLoader;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the API client for direct access.
|
|
99
|
+
*/
|
|
100
|
+
getAPIClient() {
|
|
101
|
+
return this.apiClient;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate a tool call.
|
|
105
|
+
*
|
|
106
|
+
* @param context - Validation context from Veto
|
|
107
|
+
* @returns Validation result
|
|
108
|
+
*/
|
|
109
|
+
async validate(context) {
|
|
110
|
+
// Auto-initialize if not already done
|
|
111
|
+
if (!this.isInitialized) {
|
|
112
|
+
await this.initialize();
|
|
113
|
+
}
|
|
114
|
+
// Get applicable rules
|
|
115
|
+
const rules = this.ruleLoader.getRulesForTool(context.toolName);
|
|
116
|
+
this.logger.debug('Validating tool call with rules', {
|
|
117
|
+
toolName: context.toolName,
|
|
118
|
+
callId: context.callId,
|
|
119
|
+
applicableRules: rules.length,
|
|
120
|
+
});
|
|
121
|
+
// If no rules, allow by default
|
|
122
|
+
if (rules.length === 0) {
|
|
123
|
+
this.logger.debug('No rules applicable, allowing by default', {
|
|
124
|
+
toolName: context.toolName,
|
|
125
|
+
});
|
|
126
|
+
return { decision: 'allow' };
|
|
127
|
+
}
|
|
128
|
+
// Build API context
|
|
129
|
+
const apiContext = this.buildToolCallContext(context);
|
|
130
|
+
// Call the API
|
|
131
|
+
const response = await this.apiClient.validate(apiContext, rules);
|
|
132
|
+
// Convert API response to ValidationResult
|
|
133
|
+
if (response.decision === 'pass') {
|
|
134
|
+
this.logger.info('Tool call allowed by API', {
|
|
135
|
+
toolName: context.toolName,
|
|
136
|
+
callId: context.callId,
|
|
137
|
+
passWeight: response.should_pass_weight,
|
|
138
|
+
reasoning: response.reasoning,
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
decision: 'allow',
|
|
142
|
+
reason: response.reasoning,
|
|
143
|
+
metadata: {
|
|
144
|
+
should_pass_weight: response.should_pass_weight,
|
|
145
|
+
should_block_weight: response.should_block_weight,
|
|
146
|
+
matched_rules: response.matched_rules,
|
|
147
|
+
...response.metadata,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
this.logger.warn('Tool call blocked by API', {
|
|
153
|
+
toolName: context.toolName,
|
|
154
|
+
callId: context.callId,
|
|
155
|
+
blockWeight: response.should_block_weight,
|
|
156
|
+
reasoning: response.reasoning,
|
|
157
|
+
matchedRules: response.matched_rules,
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
decision: 'deny',
|
|
161
|
+
reason: response.reasoning,
|
|
162
|
+
metadata: {
|
|
163
|
+
should_pass_weight: response.should_pass_weight,
|
|
164
|
+
should_block_weight: response.should_block_weight,
|
|
165
|
+
matched_rules: response.matched_rules,
|
|
166
|
+
...response.metadata,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Create a NamedValidator for use with Veto.
|
|
173
|
+
*
|
|
174
|
+
* @returns Named validator instance
|
|
175
|
+
*/
|
|
176
|
+
toNamedValidator() {
|
|
177
|
+
return {
|
|
178
|
+
name: 'rule-validator',
|
|
179
|
+
description: 'Validates tool calls using YAML rules and external API',
|
|
180
|
+
priority: 50, // Run in the middle
|
|
181
|
+
validate: (context) => this.validate(context),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Build the API context from the validation context.
|
|
186
|
+
*/
|
|
187
|
+
buildToolCallContext(context) {
|
|
188
|
+
return {
|
|
189
|
+
call_id: context.callId,
|
|
190
|
+
tool_name: context.toolName,
|
|
191
|
+
arguments: context.arguments,
|
|
192
|
+
timestamp: context.timestamp.toISOString(),
|
|
193
|
+
session_id: this.sessionId,
|
|
194
|
+
agent_id: this.agentId,
|
|
195
|
+
call_history: this.buildHistorySummary(context.callHistory),
|
|
196
|
+
custom: context.custom,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Build a summary of call history for the API.
|
|
201
|
+
*/
|
|
202
|
+
buildHistorySummary(history) {
|
|
203
|
+
return history.slice(-10).map((entry) => ({
|
|
204
|
+
tool_name: entry.toolName,
|
|
205
|
+
allowed: entry.validationResult.decision !== 'deny',
|
|
206
|
+
timestamp: entry.timestamp.toISOString(),
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Create a rule-based validator.
|
|
212
|
+
*
|
|
213
|
+
* @param options - Validator options
|
|
214
|
+
* @returns RuleValidator instance
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* import yaml from 'js-yaml';
|
|
219
|
+
*
|
|
220
|
+
* const ruleValidator = createRuleValidator({
|
|
221
|
+
* config: {
|
|
222
|
+
* api: { baseUrl: 'http://localhost:8080' },
|
|
223
|
+
* rulesDir: './rules',
|
|
224
|
+
* yamlParser: yaml.load,
|
|
225
|
+
* },
|
|
226
|
+
* logger: createLogger('info'),
|
|
227
|
+
* });
|
|
228
|
+
*
|
|
229
|
+
* await ruleValidator.initialize();
|
|
230
|
+
*
|
|
231
|
+
* const veto = new Veto({
|
|
232
|
+
* validators: [ruleValidator.toNamedValidator()],
|
|
233
|
+
* });
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export function createRuleValidator(options) {
|
|
237
|
+
return new RuleValidator(options);
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=rule-validator.js.map
|