@solongate/policy-engine 0.1.0 → 0.2.1
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/dist/index.d.ts +62 -3
- package/dist/index.js +344 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -212,14 +212,18 @@ declare function matchPathPattern(path: string, pattern: string): boolean;
|
|
|
212
212
|
declare function isPathAllowed(path: string, constraints: PathConstraints): boolean;
|
|
213
213
|
/**
|
|
214
214
|
* Extracts path-like arguments from tool call arguments.
|
|
215
|
-
*
|
|
215
|
+
* Uses multiple heuristics:
|
|
216
|
+
* 1. Known path field names — always extract
|
|
217
|
+
* 2. Strings containing / or \ (original heuristic)
|
|
218
|
+
* 3. Strings starting with . (.env, ./foo)
|
|
216
219
|
*/
|
|
217
220
|
declare function extractPathArguments(args: Readonly<Record<string, unknown>>): string[];
|
|
218
221
|
|
|
219
222
|
type CommandConstraints = NonNullable<PolicyRule['commandConstraints']>;
|
|
220
223
|
/**
|
|
221
224
|
* Extracts command-like arguments from tool call arguments.
|
|
222
|
-
*
|
|
225
|
+
* Uses known field names plus heuristic detection for command-like strings
|
|
226
|
+
* in any field, and recurses into nested objects/arrays.
|
|
223
227
|
*/
|
|
224
228
|
declare function extractCommandArguments(args: Readonly<Record<string, unknown>>): string[];
|
|
225
229
|
/**
|
|
@@ -243,4 +247,59 @@ declare function matchCommandPattern(command: string, pattern: string): boolean;
|
|
|
243
247
|
*/
|
|
244
248
|
declare function isCommandAllowed(command: string, constraints: CommandConstraints): boolean;
|
|
245
249
|
|
|
246
|
-
|
|
250
|
+
type FilenameConstraints = NonNullable<PolicyRule['filenameConstraints']>;
|
|
251
|
+
/**
|
|
252
|
+
* Extracts filenames from ALL string arguments (deep scan).
|
|
253
|
+
* For path-like values, extracts the basename.
|
|
254
|
+
* For non-path values, uses the string itself if it looks like a filename.
|
|
255
|
+
*/
|
|
256
|
+
declare function extractFilenames(args: Readonly<Record<string, unknown>>): string[];
|
|
257
|
+
/**
|
|
258
|
+
* Glob-style filename pattern matching (case-insensitive).
|
|
259
|
+
*
|
|
260
|
+
* Patterns:
|
|
261
|
+
* '.env' → exact match
|
|
262
|
+
* '*.pem' → ends with .pem
|
|
263
|
+
* '.env.*' → starts with .env.
|
|
264
|
+
* '*secret*' → contains "secret"
|
|
265
|
+
*/
|
|
266
|
+
declare function matchFilenamePattern(filename: string, pattern: string): boolean;
|
|
267
|
+
/**
|
|
268
|
+
* Checks if a filename is allowed by the given constraints.
|
|
269
|
+
*
|
|
270
|
+
* Evaluation order:
|
|
271
|
+
* 1. If denied list exists, filename must NOT match any denied pattern
|
|
272
|
+
* 2. If allowed list exists, filename must match at least one allowed pattern
|
|
273
|
+
* 3. If neither list exists, filename is allowed
|
|
274
|
+
*/
|
|
275
|
+
declare function isFilenameAllowed(filename: string, constraints: FilenameConstraints): boolean;
|
|
276
|
+
|
|
277
|
+
type UrlConstraints = NonNullable<PolicyRule['urlConstraints']>;
|
|
278
|
+
/**
|
|
279
|
+
* Extracts URL arguments from tool call arguments.
|
|
280
|
+
* Scans ALL string values — not just known field names.
|
|
281
|
+
* Any string containing http:// or https:// is treated as a URL.
|
|
282
|
+
*/
|
|
283
|
+
declare function extractUrlArguments(args: Readonly<Record<string, unknown>>): string[];
|
|
284
|
+
/**
|
|
285
|
+
* Glob-style URL pattern matching.
|
|
286
|
+
* Normalizes both URL and pattern to lowercase for comparison.
|
|
287
|
+
*
|
|
288
|
+
* Patterns:
|
|
289
|
+
* '*instagram.com*' → URL contains instagram.com
|
|
290
|
+
* 'https://api.example.com/*' → URL starts with prefix
|
|
291
|
+
* '*.onion' → URL ends with .onion
|
|
292
|
+
* '*' → matches everything
|
|
293
|
+
*/
|
|
294
|
+
declare function matchUrlPattern(url: string, pattern: string): boolean;
|
|
295
|
+
/**
|
|
296
|
+
* Checks if a URL is allowed by the given constraints.
|
|
297
|
+
*
|
|
298
|
+
* Evaluation order:
|
|
299
|
+
* 1. If denied list exists, URL must NOT match any denied pattern
|
|
300
|
+
* 2. If allowed list exists, URL must match at least one allowed pattern
|
|
301
|
+
* 3. If neither list exists, URL is allowed
|
|
302
|
+
*/
|
|
303
|
+
declare function isUrlAllowed(url: string, constraints: UrlConstraints): boolean;
|
|
304
|
+
|
|
305
|
+
export { type PolicyDiff, PolicyEngine, PolicyStore, type PolicyVersion, type SecurityWarning, type ValidationResult, analyzeSecurityWarnings, createDefaultDenyPolicySet, createPermissivePolicySet, createReadOnlyPolicySet, createSandboxedPolicySet, evaluatePolicy, extractCommandArguments, extractFilenames, extractPathArguments, extractUrlArguments, isCommandAllowed, isFilenameAllowed, isPathAllowed, isUrlAllowed, isWithinRoot, matchCommandPattern, matchFilenamePattern, matchPathPattern, matchUrlPattern, normalizePath, ruleMatchesRequest, toolPatternMatches, trustLevelMeetsMinimum, validatePolicyRule, validatePolicySet };
|
package/dist/index.js
CHANGED
|
@@ -127,11 +127,48 @@ function matchSegmentGlob(segment, pattern) {
|
|
|
127
127
|
}
|
|
128
128
|
return segment === pattern;
|
|
129
129
|
}
|
|
130
|
+
var PATH_FIELDS = /* @__PURE__ */ new Set([
|
|
131
|
+
"path",
|
|
132
|
+
"file",
|
|
133
|
+
"file_path",
|
|
134
|
+
"filepath",
|
|
135
|
+
"filename",
|
|
136
|
+
"directory",
|
|
137
|
+
"dir",
|
|
138
|
+
"folder",
|
|
139
|
+
"source",
|
|
140
|
+
"destination",
|
|
141
|
+
"dest",
|
|
142
|
+
"target",
|
|
143
|
+
"input",
|
|
144
|
+
"output",
|
|
145
|
+
"cwd",
|
|
146
|
+
"root",
|
|
147
|
+
"notebook_path"
|
|
148
|
+
]);
|
|
130
149
|
function extractPathArguments(args) {
|
|
131
150
|
const paths = [];
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
151
|
+
const seen = /* @__PURE__ */ new Set();
|
|
152
|
+
function addPath(value) {
|
|
153
|
+
const trimmed = value.trim();
|
|
154
|
+
if (trimmed && !seen.has(trimmed)) {
|
|
155
|
+
seen.add(trimmed);
|
|
156
|
+
paths.push(trimmed);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (const [key, value] of Object.entries(args)) {
|
|
160
|
+
if (typeof value !== "string") continue;
|
|
161
|
+
if (PATH_FIELDS.has(key.toLowerCase())) {
|
|
162
|
+
addPath(value);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (value.includes("/") || value.includes("\\")) {
|
|
166
|
+
addPath(value);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (value.startsWith(".")) {
|
|
170
|
+
addPath(value);
|
|
171
|
+
continue;
|
|
135
172
|
}
|
|
136
173
|
}
|
|
137
174
|
return paths;
|
|
@@ -147,16 +184,63 @@ var COMMAND_FIELDS = /* @__PURE__ */ new Set([
|
|
|
147
184
|
"shell",
|
|
148
185
|
"exec",
|
|
149
186
|
"sql",
|
|
150
|
-
"expression"
|
|
187
|
+
"expression",
|
|
188
|
+
"function"
|
|
151
189
|
]);
|
|
190
|
+
var COMMAND_HEURISTICS = [
|
|
191
|
+
/^(sh|bash|cmd|powershell|zsh|fish)\s+-c\s+/i,
|
|
192
|
+
// shell -c "..."
|
|
193
|
+
/^(sudo|doas)\s+/i,
|
|
194
|
+
// privilege escalation
|
|
195
|
+
/^\w+\s+&&\s+/,
|
|
196
|
+
// cmd1 && cmd2
|
|
197
|
+
/^\w+\s*\|\s*\w+/,
|
|
198
|
+
// cmd1 | cmd2
|
|
199
|
+
/^\w+\s*;\s*\w+/,
|
|
200
|
+
// cmd1; cmd2
|
|
201
|
+
/^(curl|wget|nc|ncat)\s+/i,
|
|
202
|
+
// network commands
|
|
203
|
+
/^(rm|del|rmdir)\s+/i,
|
|
204
|
+
// destructive commands
|
|
205
|
+
/^(cat|type|more|less)\s+.*[/\\]/i
|
|
206
|
+
// file read commands with paths
|
|
207
|
+
];
|
|
152
208
|
function extractCommandArguments(args) {
|
|
153
209
|
const commands = [];
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
210
|
+
const seen = /* @__PURE__ */ new Set();
|
|
211
|
+
function addCommand(value) {
|
|
212
|
+
const trimmed = value.trim();
|
|
213
|
+
if (trimmed && !seen.has(trimmed)) {
|
|
214
|
+
seen.add(trimmed);
|
|
215
|
+
commands.push(trimmed);
|
|
158
216
|
}
|
|
159
217
|
}
|
|
218
|
+
function scanValue(key, value) {
|
|
219
|
+
if (typeof value === "string") {
|
|
220
|
+
if (COMMAND_FIELDS.has(key.toLowerCase())) {
|
|
221
|
+
addCommand(value);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
for (const pattern of COMMAND_HEURISTICS) {
|
|
225
|
+
if (pattern.test(value)) {
|
|
226
|
+
addCommand(value);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (Array.isArray(value)) {
|
|
232
|
+
for (const item of value) {
|
|
233
|
+
scanValue(key, item);
|
|
234
|
+
}
|
|
235
|
+
} else if (typeof value === "object" && value !== null) {
|
|
236
|
+
for (const [k, v] of Object.entries(value)) {
|
|
237
|
+
scanValue(k, v);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
for (const [key, value] of Object.entries(args)) {
|
|
242
|
+
scanValue(key, value);
|
|
243
|
+
}
|
|
160
244
|
return commands;
|
|
161
245
|
}
|
|
162
246
|
function matchCommandPattern(command, pattern) {
|
|
@@ -202,10 +286,232 @@ function isCommandAllowed(command, constraints) {
|
|
|
202
286
|
return true;
|
|
203
287
|
}
|
|
204
288
|
|
|
289
|
+
// src/filename-matcher.ts
|
|
290
|
+
function extractFilenames(args) {
|
|
291
|
+
const filenames = [];
|
|
292
|
+
const seen = /* @__PURE__ */ new Set();
|
|
293
|
+
function addFilename(name) {
|
|
294
|
+
const trimmed = name.trim();
|
|
295
|
+
if (trimmed && !seen.has(trimmed)) {
|
|
296
|
+
seen.add(trimmed);
|
|
297
|
+
filenames.push(trimmed);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function scanValue(value) {
|
|
301
|
+
if (typeof value === "string") {
|
|
302
|
+
const trimmed = value.trim();
|
|
303
|
+
if (!trimmed) return;
|
|
304
|
+
if (/^https?:\/\//i.test(trimmed)) return;
|
|
305
|
+
if (trimmed.includes("/") || trimmed.includes("\\")) {
|
|
306
|
+
const normalized = trimmed.replace(/\\/g, "/");
|
|
307
|
+
const parts = normalized.split("/");
|
|
308
|
+
const basename = parts[parts.length - 1];
|
|
309
|
+
if (basename && basename.length > 0) {
|
|
310
|
+
addFilename(basename);
|
|
311
|
+
}
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (trimmed.includes(" ")) {
|
|
315
|
+
for (const token of trimmed.split(/\s+/)) {
|
|
316
|
+
if (token.includes("/") || token.includes("\\")) {
|
|
317
|
+
const parts = token.replace(/\\/g, "/").split("/");
|
|
318
|
+
const basename = parts[parts.length - 1];
|
|
319
|
+
if (basename && looksLikeFilename(basename)) addFilename(basename);
|
|
320
|
+
} else if (looksLikeFilename(token)) {
|
|
321
|
+
addFilename(token);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (looksLikeFilename(trimmed)) {
|
|
327
|
+
addFilename(trimmed);
|
|
328
|
+
}
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (Array.isArray(value)) {
|
|
332
|
+
for (const item of value) {
|
|
333
|
+
scanValue(item);
|
|
334
|
+
}
|
|
335
|
+
} else if (typeof value === "object" && value !== null) {
|
|
336
|
+
for (const v of Object.values(value)) {
|
|
337
|
+
scanValue(v);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
for (const value of Object.values(args)) {
|
|
342
|
+
scanValue(value);
|
|
343
|
+
}
|
|
344
|
+
return filenames;
|
|
345
|
+
}
|
|
346
|
+
function looksLikeFilename(s) {
|
|
347
|
+
if (s.startsWith(".")) return true;
|
|
348
|
+
if (/\.\w+$/.test(s)) return true;
|
|
349
|
+
const knownFiles = /* @__PURE__ */ new Set([
|
|
350
|
+
"id_rsa",
|
|
351
|
+
"id_dsa",
|
|
352
|
+
"id_ecdsa",
|
|
353
|
+
"id_ed25519",
|
|
354
|
+
"authorized_keys",
|
|
355
|
+
"known_hosts",
|
|
356
|
+
"makefile",
|
|
357
|
+
"dockerfile",
|
|
358
|
+
"vagrantfile",
|
|
359
|
+
"gemfile",
|
|
360
|
+
"rakefile",
|
|
361
|
+
"procfile"
|
|
362
|
+
]);
|
|
363
|
+
if (knownFiles.has(s.toLowerCase())) return true;
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
function matchFilenamePattern(filename, pattern) {
|
|
367
|
+
if (pattern === "*") return true;
|
|
368
|
+
const normalizedFilename = filename.toLowerCase();
|
|
369
|
+
const normalizedPattern = pattern.toLowerCase();
|
|
370
|
+
if (normalizedFilename === normalizedPattern) return true;
|
|
371
|
+
const startsWithStar = normalizedPattern.startsWith("*");
|
|
372
|
+
const endsWithStar = normalizedPattern.endsWith("*");
|
|
373
|
+
if (startsWithStar && endsWithStar) {
|
|
374
|
+
const infix = normalizedPattern.slice(1, -1);
|
|
375
|
+
return infix.length > 0 && normalizedFilename.includes(infix);
|
|
376
|
+
}
|
|
377
|
+
if (startsWithStar) {
|
|
378
|
+
const suffix = normalizedPattern.slice(1);
|
|
379
|
+
return normalizedFilename.endsWith(suffix);
|
|
380
|
+
}
|
|
381
|
+
if (endsWithStar) {
|
|
382
|
+
const prefix = normalizedPattern.slice(0, -1);
|
|
383
|
+
return normalizedFilename.startsWith(prefix);
|
|
384
|
+
}
|
|
385
|
+
const starIdx = normalizedPattern.indexOf("*");
|
|
386
|
+
if (starIdx !== -1) {
|
|
387
|
+
const prefix = normalizedPattern.slice(0, starIdx);
|
|
388
|
+
const suffix = normalizedPattern.slice(starIdx + 1);
|
|
389
|
+
return normalizedFilename.startsWith(prefix) && normalizedFilename.endsWith(suffix) && normalizedFilename.length >= prefix.length + suffix.length;
|
|
390
|
+
}
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
function isFilenameAllowed(filename, constraints) {
|
|
394
|
+
if (constraints.denied && constraints.denied.length > 0) {
|
|
395
|
+
for (const pattern of constraints.denied) {
|
|
396
|
+
if (matchFilenamePattern(filename, pattern)) {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (constraints.allowed && constraints.allowed.length > 0) {
|
|
402
|
+
let matchesAllowed = false;
|
|
403
|
+
for (const pattern of constraints.allowed) {
|
|
404
|
+
if (matchFilenamePattern(filename, pattern)) {
|
|
405
|
+
matchesAllowed = true;
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (!matchesAllowed) return false;
|
|
410
|
+
}
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/url-matcher.ts
|
|
415
|
+
var URL_FIELDS = /* @__PURE__ */ new Set([
|
|
416
|
+
"url",
|
|
417
|
+
"href",
|
|
418
|
+
"uri",
|
|
419
|
+
"endpoint",
|
|
420
|
+
"link",
|
|
421
|
+
"src",
|
|
422
|
+
"source",
|
|
423
|
+
"target",
|
|
424
|
+
"redirect",
|
|
425
|
+
"callback",
|
|
426
|
+
"webhook"
|
|
427
|
+
]);
|
|
428
|
+
function extractUrlArguments(args) {
|
|
429
|
+
const urls = [];
|
|
430
|
+
const seen = /* @__PURE__ */ new Set();
|
|
431
|
+
function addUrl(value) {
|
|
432
|
+
const trimmed = value.trim();
|
|
433
|
+
if (trimmed && !seen.has(trimmed)) {
|
|
434
|
+
seen.add(trimmed);
|
|
435
|
+
urls.push(trimmed);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function scanValue(key, value) {
|
|
439
|
+
if (typeof value === "string") {
|
|
440
|
+
const lower = key.toLowerCase();
|
|
441
|
+
if (URL_FIELDS.has(lower)) {
|
|
442
|
+
addUrl(value);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (/https?:\/\//i.test(value)) {
|
|
446
|
+
addUrl(value);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (/^[a-zA-Z0-9]([a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}(\/.*)?$/.test(value)) {
|
|
450
|
+
addUrl(value);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (Array.isArray(value)) {
|
|
455
|
+
for (const item of value) {
|
|
456
|
+
scanValue(key, item);
|
|
457
|
+
}
|
|
458
|
+
} else if (typeof value === "object" && value !== null) {
|
|
459
|
+
for (const [k, v] of Object.entries(value)) {
|
|
460
|
+
scanValue(k, v);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
for (const [key, value] of Object.entries(args)) {
|
|
465
|
+
scanValue(key, value);
|
|
466
|
+
}
|
|
467
|
+
return urls;
|
|
468
|
+
}
|
|
469
|
+
function matchUrlPattern(url, pattern) {
|
|
470
|
+
if (pattern === "*") return true;
|
|
471
|
+
const normalizedUrl = url.trim().toLowerCase();
|
|
472
|
+
const normalizedPattern = pattern.trim().toLowerCase();
|
|
473
|
+
if (normalizedPattern === normalizedUrl) return true;
|
|
474
|
+
const startsWithStar = normalizedPattern.startsWith("*");
|
|
475
|
+
const endsWithStar = normalizedPattern.endsWith("*");
|
|
476
|
+
if (startsWithStar && endsWithStar) {
|
|
477
|
+
const infix = normalizedPattern.slice(1, -1);
|
|
478
|
+
return infix.length > 0 && normalizedUrl.includes(infix);
|
|
479
|
+
}
|
|
480
|
+
if (endsWithStar) {
|
|
481
|
+
const prefix = normalizedPattern.slice(0, -1);
|
|
482
|
+
return normalizedUrl.startsWith(prefix);
|
|
483
|
+
}
|
|
484
|
+
if (startsWithStar) {
|
|
485
|
+
const suffix = normalizedPattern.slice(1);
|
|
486
|
+
return normalizedUrl.endsWith(suffix);
|
|
487
|
+
}
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
function isUrlAllowed(url, constraints) {
|
|
491
|
+
if (constraints.denied && constraints.denied.length > 0) {
|
|
492
|
+
for (const pattern of constraints.denied) {
|
|
493
|
+
if (matchUrlPattern(url, pattern)) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (constraints.allowed && constraints.allowed.length > 0) {
|
|
499
|
+
let matchesAllowed = false;
|
|
500
|
+
for (const pattern of constraints.allowed) {
|
|
501
|
+
if (matchUrlPattern(url, pattern)) {
|
|
502
|
+
matchesAllowed = true;
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (!matchesAllowed) return false;
|
|
507
|
+
}
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
|
|
205
511
|
// src/matcher.ts
|
|
206
512
|
function ruleMatchesRequest(rule, request) {
|
|
207
513
|
if (!rule.enabled) return false;
|
|
208
|
-
if (rule.permission !== request.requiredPermission) return false;
|
|
514
|
+
if (rule.permission && rule.permission !== request.requiredPermission) return false;
|
|
209
515
|
if (!toolPatternMatches(rule.toolPattern, request.toolName)) return false;
|
|
210
516
|
if (!trustLevelMeetsMinimum(request.context.trustLevel, rule.minimumTrustLevel)) {
|
|
211
517
|
return false;
|
|
@@ -231,6 +537,22 @@ function ruleMatchesRequest(rule, request) {
|
|
|
231
537
|
if (!satisfied) return false;
|
|
232
538
|
}
|
|
233
539
|
}
|
|
540
|
+
if (rule.filenameConstraints) {
|
|
541
|
+
const satisfied = filenameConstraintsMatch(rule.filenameConstraints, request.arguments);
|
|
542
|
+
if (rule.effect === "DENY") {
|
|
543
|
+
if (satisfied) return false;
|
|
544
|
+
} else {
|
|
545
|
+
if (!satisfied) return false;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (rule.urlConstraints) {
|
|
549
|
+
const satisfied = urlConstraintsMatch(rule.urlConstraints, request.arguments);
|
|
550
|
+
if (rule.effect === "DENY") {
|
|
551
|
+
if (satisfied) return false;
|
|
552
|
+
} else {
|
|
553
|
+
if (!satisfied) return false;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
234
556
|
return true;
|
|
235
557
|
}
|
|
236
558
|
function toolPatternMatches(pattern, toolName) {
|
|
@@ -321,6 +643,16 @@ function commandConstraintsMatch(constraints, args) {
|
|
|
321
643
|
if (commands.length === 0) return true;
|
|
322
644
|
return commands.every((cmd) => isCommandAllowed(cmd, constraints));
|
|
323
645
|
}
|
|
646
|
+
function filenameConstraintsMatch(constraints, args) {
|
|
647
|
+
const filenames = extractFilenames(args);
|
|
648
|
+
if (filenames.length === 0) return true;
|
|
649
|
+
return filenames.every((name) => isFilenameAllowed(name, constraints));
|
|
650
|
+
}
|
|
651
|
+
function urlConstraintsMatch(constraints, args) {
|
|
652
|
+
const urls = extractUrlArguments(args);
|
|
653
|
+
if (urls.length === 0) return true;
|
|
654
|
+
return urls.every((url) => isUrlAllowed(url, constraints));
|
|
655
|
+
}
|
|
324
656
|
|
|
325
657
|
// src/evaluator.ts
|
|
326
658
|
function evaluatePolicy(policySet, request) {
|
|
@@ -377,7 +709,7 @@ function validatePolicyRule(input) {
|
|
|
377
709
|
if (rule.minimumTrustLevel === "TRUSTED") {
|
|
378
710
|
warnings.push(UNSAFE_CONFIGURATION_WARNINGS.TRUSTED_LEVEL_EXTERNAL);
|
|
379
711
|
}
|
|
380
|
-
if (rule.permission === "EXECUTE") {
|
|
712
|
+
if (!rule.permission || rule.permission === "EXECUTE") {
|
|
381
713
|
warnings.push(UNSAFE_CONFIGURATION_WARNINGS.EXECUTE_WITHOUT_REVIEW);
|
|
382
714
|
}
|
|
383
715
|
return { valid: true, errors, warnings };
|
|
@@ -454,7 +786,7 @@ function analyzeRuleWarnings(rule) {
|
|
|
454
786
|
recommendation: "Set minimumTrustLevel to VERIFIED or higher for ALLOW rules."
|
|
455
787
|
});
|
|
456
788
|
}
|
|
457
|
-
if (rule.effect === "ALLOW" && rule.permission === "EXECUTE") {
|
|
789
|
+
if (rule.effect === "ALLOW" && (!rule.permission || rule.permission === "EXECUTE")) {
|
|
458
790
|
warnings.push({
|
|
459
791
|
level: "WARNING",
|
|
460
792
|
code: "ALLOW_EXECUTE",
|
|
@@ -838,6 +1170,6 @@ var PolicyStore = class {
|
|
|
838
1170
|
}
|
|
839
1171
|
};
|
|
840
1172
|
|
|
841
|
-
export { PolicyEngine, PolicyStore, analyzeSecurityWarnings, createDefaultDenyPolicySet, createPermissivePolicySet, createReadOnlyPolicySet, createSandboxedPolicySet, evaluatePolicy, extractCommandArguments, extractPathArguments, isCommandAllowed, isPathAllowed, isWithinRoot, matchCommandPattern, matchPathPattern, normalizePath, ruleMatchesRequest, toolPatternMatches, trustLevelMeetsMinimum, validatePolicyRule, validatePolicySet };
|
|
1173
|
+
export { PolicyEngine, PolicyStore, analyzeSecurityWarnings, createDefaultDenyPolicySet, createPermissivePolicySet, createReadOnlyPolicySet, createSandboxedPolicySet, evaluatePolicy, extractCommandArguments, extractFilenames, extractPathArguments, extractUrlArguments, isCommandAllowed, isFilenameAllowed, isPathAllowed, isUrlAllowed, isWithinRoot, matchCommandPattern, matchFilenamePattern, matchPathPattern, matchUrlPattern, normalizePath, ruleMatchesRequest, toolPatternMatches, trustLevelMeetsMinimum, validatePolicyRule, validatePolicySet };
|
|
842
1174
|
//# sourceMappingURL=index.js.map
|
|
843
1175
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/path-matcher.ts","../src/command-matcher.ts","../src/matcher.ts","../src/evaluator.ts","../src/validator.ts","../src/warnings.ts","../src/defaults.ts","../src/engine.ts","../src/policy-store.ts"],"names":["endTime","UNSAFE_CONFIGURATION_WARNINGS","TrustLevel"],"mappings":"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","file":"index.js","sourcesContent":["import type { PolicyRule } from '@solongate/core';\n\ntype PathConstraints = NonNullable<PolicyRule['pathConstraints']>;\n\n/**\n * Normalizes a file path for consistent matching.\n * Resolves . and .. segments, normalizes separators.\n */\nexport function normalizePath(path: string): string {\n // Normalize separators to forward slash\n let normalized = path.replace(/\\\\/g, '/');\n\n // Remove trailing slash (except for root)\n if (normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n\n // Resolve . and .. segments\n const parts = normalized.split('/');\n const resolved: string[] = [];\n\n for (const part of parts) {\n if (part === '.' || part === '') {\n if (resolved.length === 0) resolved.push('');\n continue;\n }\n if (part === '..') {\n if (resolved.length > 1) {\n resolved.pop();\n }\n continue;\n }\n resolved.push(part);\n }\n\n return resolved.join('/') || '/';\n}\n\n/**\n * Checks if a path is within a root directory (sandbox boundary).\n * Prevents escaping via .., symlinks, etc.\n */\nexport function isWithinRoot(path: string, root: string): boolean {\n const normalizedPath = normalizePath(path);\n const normalizedRoot = normalizePath(root);\n\n // Path must start with root\n if (normalizedPath === normalizedRoot) return true;\n return normalizedPath.startsWith(normalizedRoot + '/');\n}\n\n/**\n * Glob-style path pattern matching.\n * Supports:\n * - * matches any single path segment (not /)\n * - ** matches any number of path segments\n * - Exact match\n *\n * Does NOT support regex (ReDoS prevention).\n */\nexport function matchPathPattern(path: string, pattern: string): boolean {\n const normalizedPath = normalizePath(path);\n const normalizedPattern = normalizePath(pattern);\n\n if (normalizedPattern === '*') return true;\n if (normalizedPattern === normalizedPath) return true;\n\n const patternParts = normalizedPattern.split('/');\n const pathParts = normalizedPath.split('/');\n\n return matchParts(pathParts, 0, patternParts, 0);\n}\n\nfunction matchParts(\n pathParts: string[],\n pi: number,\n patternParts: string[],\n qi: number,\n): boolean {\n while (pi < pathParts.length && qi < patternParts.length) {\n const pattern = patternParts[qi]!;\n\n if (pattern === '**') {\n // ** can match zero or more path segments\n if (qi === patternParts.length - 1) return true;\n\n // Try matching ** against 0, 1, 2, ... path segments\n for (let i = pi; i <= pathParts.length; i++) {\n if (matchParts(pathParts, i, patternParts, qi + 1)) {\n return true;\n }\n }\n return false;\n }\n\n if (pattern === '*') {\n // * matches exactly one path segment\n pi++;\n qi++;\n continue;\n }\n\n // Support intra-segment globs: *.txt, file.*, test-*-data, etc.\n if (pattern.includes('*')) {\n if (!matchSegmentGlob(pathParts[pi]!, pattern)) {\n return false;\n }\n pi++;\n qi++;\n continue;\n }\n\n if (pattern !== pathParts[pi]) {\n return false;\n }\n\n pi++;\n qi++;\n }\n\n // Skip trailing ** patterns\n while (qi < patternParts.length && patternParts[qi] === '**') {\n qi++;\n }\n\n return pi === pathParts.length && qi === patternParts.length;\n}\n\n/**\n * Checks if a path is allowed by the given constraints.\n *\n * Evaluation order:\n * 1. If rootDirectory is set, path must be within it\n * 2. If denied list exists, path must NOT match any denied pattern\n * 3. If allowed list exists, path must match at least one allowed pattern\n * 4. If neither list exists, path is allowed (constraints are optional)\n */\nexport function isPathAllowed(\n path: string,\n constraints: PathConstraints,\n): boolean {\n // 1. Root directory check (sandbox)\n if (constraints.rootDirectory) {\n if (!isWithinRoot(path, constraints.rootDirectory)) {\n return false;\n }\n }\n\n // 2. Denied list - any match means denied\n if (constraints.denied && constraints.denied.length > 0) {\n for (const pattern of constraints.denied) {\n if (matchPathPattern(path, pattern)) {\n return false;\n }\n }\n }\n\n // 3. Allowed list - must match at least one\n if (constraints.allowed && constraints.allowed.length > 0) {\n let matchesAllowed = false;\n for (const pattern of constraints.allowed) {\n if (matchPathPattern(path, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n }\n\n return true;\n}\n\n/**\n * Matches a single path segment against a glob pattern containing *.\n * Examples: *.txt matches safe.txt, file.* matches file.js, *secret* matches my-secret-key\n */\nfunction matchSegmentGlob(segment: string, pattern: string): boolean {\n const startsWithStar = pattern.startsWith('*');\n const endsWithStar = pattern.endsWith('*');\n\n if (pattern === '*') return true;\n\n if (startsWithStar && endsWithStar) {\n // *infix* — contains\n const infix = pattern.slice(1, -1);\n return segment.toLowerCase().includes(infix.toLowerCase());\n }\n if (startsWithStar) {\n // *suffix — ends with\n const suffix = pattern.slice(1);\n return segment.toLowerCase().endsWith(suffix.toLowerCase());\n }\n if (endsWithStar) {\n // prefix* — starts with\n const prefix = pattern.slice(0, -1);\n return segment.toLowerCase().startsWith(prefix.toLowerCase());\n }\n\n // Single * in middle: split on * and check prefix+suffix\n const starIdx = pattern.indexOf('*');\n if (starIdx !== -1) {\n const prefix = pattern.slice(0, starIdx);\n const suffix = pattern.slice(starIdx + 1);\n const seg = segment.toLowerCase();\n return seg.startsWith(prefix.toLowerCase()) && seg.endsWith(suffix.toLowerCase()) && seg.length >= prefix.length + suffix.length;\n }\n\n return segment === pattern;\n}\n\n/**\n * Extracts path-like arguments from tool call arguments.\n * Heuristic: any string argument containing / or \\ is treated as a path.\n */\nexport function extractPathArguments(\n args: Readonly<Record<string, unknown>>,\n): string[] {\n const paths: string[] = [];\n\n for (const value of Object.values(args)) {\n if (typeof value === 'string' && (value.includes('/') || value.includes('\\\\'))) {\n paths.push(value);\n }\n }\n\n return paths;\n}\n","import type { PolicyRule } from '@solongate/core';\n\ntype CommandConstraints = NonNullable<PolicyRule['commandConstraints']>;\n\n/**\n * Known argument field names that typically contain commands or shell-like content.\n * Used to extract commands from tool call arguments for constraint matching.\n */\nconst COMMAND_FIELDS = new Set([\n 'command',\n 'cmd',\n 'query',\n 'code',\n 'script',\n 'shell',\n 'exec',\n 'sql',\n 'expression',\n]);\n\n/**\n * Extracts command-like arguments from tool call arguments.\n * Looks for known field names and string values that look like commands.\n */\nexport function extractCommandArguments(\n args: Readonly<Record<string, unknown>>,\n): string[] {\n const commands: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n if (typeof value !== 'string') continue;\n\n // Check known command field names\n if (COMMAND_FIELDS.has(key.toLowerCase())) {\n commands.push(value);\n }\n }\n\n return commands;\n}\n\n/**\n * Glob-style command pattern matching.\n * Matches against the command string (first word) or full command line.\n *\n * Patterns:\n * 'ls' → exact match on command name\n * 'git*' → command starts with 'git'\n * '*sql*' → command contains 'sql'\n * 'rm -rf *' → full command line starts with 'rm -rf '\n */\nexport function matchCommandPattern(command: string, pattern: string): boolean {\n if (pattern === '*') return true;\n\n const normalizedCommand = command.trim().toLowerCase();\n const normalizedPattern = pattern.trim().toLowerCase();\n\n if (normalizedPattern === normalizedCommand) return true;\n\n const startsWithStar = normalizedPattern.startsWith('*');\n const endsWithStar = normalizedPattern.endsWith('*');\n\n if (startsWithStar && endsWithStar) {\n const infix = normalizedPattern.slice(1, -1);\n return infix.length > 0 && normalizedCommand.includes(infix);\n }\n if (endsWithStar) {\n const prefix = normalizedPattern.slice(0, -1);\n return normalizedCommand.startsWith(prefix);\n }\n if (startsWithStar) {\n const suffix = normalizedPattern.slice(1);\n return normalizedCommand.endsWith(suffix);\n }\n\n // Also try matching just the command name (first word)\n const commandName = normalizedCommand.split(/\\s+/)[0] ?? '';\n return commandName === normalizedPattern;\n}\n\n/**\n * Checks if a command is allowed by the given constraints.\n *\n * Evaluation order:\n * 1. If denied list exists, command must NOT match any denied pattern\n * 2. If allowed list exists, command must match at least one allowed pattern\n * 3. If neither list exists, command is allowed (constraints are optional)\n */\nexport function isCommandAllowed(\n command: string,\n constraints: CommandConstraints,\n): boolean {\n // 1. Denied list — any match means denied\n if (constraints.denied && constraints.denied.length > 0) {\n for (const pattern of constraints.denied) {\n if (matchCommandPattern(command, pattern)) {\n return false;\n }\n }\n }\n\n // 2. Allowed list — must match at least one\n if (constraints.allowed && constraints.allowed.length > 0) {\n let matchesAllowed = false;\n for (const pattern of constraints.allowed) {\n if (matchCommandPattern(command, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n }\n\n return true;\n}\n","import type { PolicyRule, ExecutionRequest } from '@solongate/core';\nimport { TrustLevel } from '@solongate/core';\nimport { isPathAllowed, extractPathArguments } from './path-matcher.js';\nimport { isCommandAllowed, extractCommandArguments } from './command-matcher.js';\n\n/**\n * Pure function: determines if a policy rule matches an execution request.\n * No side effects. No I/O. Fully deterministic.\n */\nexport function ruleMatchesRequest(\n rule: PolicyRule,\n request: ExecutionRequest,\n): boolean {\n if (!rule.enabled) return false;\n if (rule.permission !== request.requiredPermission) return false;\n if (!toolPatternMatches(rule.toolPattern, request.toolName)) return false;\n if (!trustLevelMeetsMinimum(request.context.trustLevel, rule.minimumTrustLevel)) {\n return false;\n }\n if (rule.argumentConstraints) {\n if (!argumentConstraintsMatch(rule.argumentConstraints, request.arguments)) {\n return false;\n }\n }\n if (rule.pathConstraints) {\n const satisfied = pathConstraintsMatch(rule.pathConstraints, request.arguments);\n // For DENY rules: match when constraints are VIOLATED (path is dangerous)\n // For ALLOW rules: match when constraints are SATISFIED (path is safe)\n if (rule.effect === 'DENY') {\n if (satisfied) return false; // path is safe → don't deny\n } else {\n if (!satisfied) return false; // path is dangerous → don't allow\n }\n }\n if (rule.commandConstraints) {\n const satisfied = commandConstraintsMatch(rule.commandConstraints, request.arguments);\n // For DENY rules: match when constraints are VIOLATED (command is dangerous)\n // For ALLOW rules: match when constraints are SATISFIED (command is safe)\n if (rule.effect === 'DENY') {\n if (satisfied) return false; // command is safe → don't deny\n } else {\n if (!satisfied) return false; // command is dangerous → don't allow\n }\n }\n return true;\n}\n\n/**\n * Glob-style tool name pattern matching.\n * Supports:\n * '*' → match all\n * 'prefix*' → starts with prefix\n * '*suffix' → ends with suffix\n * '*infix*' → contains infix\n * Does NOT support regex (ReDoS prevention).\n */\nexport function toolPatternMatches(pattern: string, toolName: string): boolean {\n if (pattern === '*') return true;\n\n const startsWithStar = pattern.startsWith('*');\n const endsWithStar = pattern.endsWith('*');\n\n if (startsWithStar && endsWithStar) {\n // *infix* → contains\n const infix = pattern.slice(1, -1);\n return infix.length > 0 && toolName.includes(infix);\n }\n if (endsWithStar) {\n // prefix* → starts with\n const prefix = pattern.slice(0, -1);\n return toolName.startsWith(prefix);\n }\n if (startsWithStar) {\n // *suffix → ends with\n const suffix = pattern.slice(1);\n return toolName.endsWith(suffix);\n }\n\n return pattern === toolName;\n}\n\nconst TRUST_LEVEL_ORDER: Record<string, number> = {\n [TrustLevel.UNTRUSTED]: 0,\n [TrustLevel.VERIFIED]: 1,\n [TrustLevel.TRUSTED]: 2,\n};\n\nexport function trustLevelMeetsMinimum(\n actual: TrustLevel,\n minimum: TrustLevel,\n): boolean {\n return (TRUST_LEVEL_ORDER[actual] ?? -1) >= (TRUST_LEVEL_ORDER[minimum] ?? Infinity);\n}\n\n/**\n * Condition operators for argument constraints.\n * When constraint value is a plain string → exact match (or '*' for any).\n * When constraint value is an object → operator-based matching:\n * { $contains: \"str\" } — value includes substring\n * { $notContains: \"str\" } — value does NOT include substring\n * { $startsWith: \"str\" } — value starts with prefix\n * { $endsWith: \"str\" } — value ends with suffix\n * { $in: [\"a\",\"b\"] } — value is one of the listed values\n * { $notIn: [\"a\",\"b\"] } — value is NOT one of the listed values\n * { $gt: 5 } — numeric greater than\n * { $lt: 5 } — numeric less than\n * { $gte: 5 } — numeric greater than or equal\n * { $lte: 5 } — numeric less than or equal\n */\nfunction argumentConstraintsMatch(\n constraints: Record<string, unknown>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n for (const [key, constraint] of Object.entries(constraints)) {\n if (!(key in args)) return false;\n const argValue = args[key];\n\n // Plain string: exact match (backward compatible)\n if (typeof constraint === 'string') {\n if (constraint === '*') continue;\n if (typeof argValue === 'string') {\n if (argValue !== constraint) return false;\n } else {\n return false;\n }\n continue;\n }\n\n // Object with operators\n if (typeof constraint === 'object' && constraint !== null && !Array.isArray(constraint)) {\n const ops = constraint as Record<string, unknown>;\n const strValue = typeof argValue === 'string' ? argValue : undefined;\n const numValue = typeof argValue === 'number' ? argValue : undefined;\n\n if ('$contains' in ops && typeof ops.$contains === 'string') {\n if (!strValue || !strValue.includes(ops.$contains)) return false;\n }\n if ('$notContains' in ops && typeof ops.$notContains === 'string') {\n if (strValue && strValue.includes(ops.$notContains)) return false;\n }\n if ('$startsWith' in ops && typeof ops.$startsWith === 'string') {\n if (!strValue || !strValue.startsWith(ops.$startsWith)) return false;\n }\n if ('$endsWith' in ops && typeof ops.$endsWith === 'string') {\n if (!strValue || !strValue.endsWith(ops.$endsWith)) return false;\n }\n if ('$in' in ops && Array.isArray(ops.$in)) {\n if (!ops.$in.includes(argValue)) return false;\n }\n if ('$notIn' in ops && Array.isArray(ops.$notIn)) {\n if (ops.$notIn.includes(argValue)) return false;\n }\n if ('$gt' in ops && typeof ops.$gt === 'number') {\n if (numValue === undefined || numValue <= ops.$gt) return false;\n }\n if ('$lt' in ops && typeof ops.$lt === 'number') {\n if (numValue === undefined || numValue >= ops.$lt) return false;\n }\n if ('$gte' in ops && typeof ops.$gte === 'number') {\n if (numValue === undefined || numValue < ops.$gte) return false;\n }\n if ('$lte' in ops && typeof ops.$lte === 'number') {\n if (numValue === undefined || numValue > ops.$lte) return false;\n }\n\n continue;\n }\n }\n return true;\n}\n\nfunction pathConstraintsMatch(\n constraints: NonNullable<PolicyRule['pathConstraints']>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n const paths = extractPathArguments(args);\n\n // If no path arguments found, constraints don't apply\n if (paths.length === 0) return true;\n\n // ALL path arguments must satisfy constraints\n return paths.every((path) => isPathAllowed(path, constraints));\n}\n\nfunction commandConstraintsMatch(\n constraints: NonNullable<PolicyRule['commandConstraints']>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n const commands = extractCommandArguments(args);\n\n // If no command arguments found, constraints don't apply\n if (commands.length === 0) return true;\n\n // ALL command arguments must satisfy constraints\n return commands.every((cmd) => isCommandAllowed(cmd, constraints));\n}\n","import type {\n PolicySet,\n PolicyDecision,\n ExecutionRequest,\n PolicyEffect,\n} from '@solongate/core';\nimport { DEFAULT_POLICY_EFFECT } from '@solongate/core';\nimport { ruleMatchesRequest } from './matcher.js';\n\n/**\n * Evaluates a policy set against an execution request.\n *\n * Pure function: no side effects, no I/O, fully deterministic.\n *\n * Algorithm:\n * 1. Sort rules by priority (ascending - lower number = higher priority)\n * 2. Find the first matching rule\n * 3. If a rule matches, return its effect\n * 4. If no rule matches, return DENY (default-deny)\n */\nexport function evaluatePolicy(\n policySet: PolicySet,\n request: ExecutionRequest,\n): PolicyDecision {\n const startTime = performance.now();\n\n const sortedRules = [...policySet.rules].sort(\n (a, b) => a.priority - b.priority,\n );\n\n for (const rule of sortedRules) {\n if (ruleMatchesRequest(rule, request)) {\n const endTime = performance.now();\n return {\n effect: rule.effect,\n matchedRule: rule,\n reason: `Matched rule \"${rule.id}\": ${rule.description}`,\n timestamp: new Date().toISOString(),\n evaluationTimeMs: endTime - startTime,\n };\n }\n }\n\n const endTime = performance.now();\n return {\n effect: DEFAULT_POLICY_EFFECT as PolicyEffect,\n matchedRule: null,\n reason: 'No matching policy rule found. Default action: DENY.',\n timestamp: new Date().toISOString(),\n evaluationTimeMs: endTime - startTime,\n metadata: {\n evaluatedRules: sortedRules.length,\n ruleIds: sortedRules.map((r) => r.id),\n requestContext: {\n tool: request.toolName,\n arguments: Object.keys(request.arguments ?? {}),\n },\n },\n };\n}\n","import { PolicyRuleSchema, PolicySetSchema } from '@solongate/core';\nimport {\n MAX_RULES_PER_POLICY_SET,\n UNSAFE_CONFIGURATION_WARNINGS,\n} from '@solongate/core';\n\nexport interface ValidationResult {\n readonly valid: boolean;\n readonly errors: readonly string[];\n readonly warnings: readonly string[];\n}\n\nexport function validatePolicyRule(input: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const result = PolicyRuleSchema.safeParse(input);\n if (!result.success) {\n return {\n valid: false,\n errors: result.error.errors.map(\n (e) => `${e.path.join('.')}: ${e.message}`,\n ),\n warnings: [],\n };\n }\n\n const rule = result.data;\n\n if (rule.toolPattern === '*' && rule.effect === 'ALLOW') {\n warnings.push(UNSAFE_CONFIGURATION_WARNINGS.WILDCARD_ALLOW);\n }\n\n if (rule.minimumTrustLevel === 'TRUSTED') {\n warnings.push(UNSAFE_CONFIGURATION_WARNINGS.TRUSTED_LEVEL_EXTERNAL);\n }\n\n if (rule.permission === 'EXECUTE') {\n warnings.push(UNSAFE_CONFIGURATION_WARNINGS.EXECUTE_WITHOUT_REVIEW);\n }\n\n return { valid: true, errors, warnings };\n}\n\nexport function validatePolicySet(input: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const result = PolicySetSchema.safeParse(input);\n if (!result.success) {\n return {\n valid: false,\n errors: result.error.errors.map(\n (e) => `${e.path.join('.')}: ${e.message}`,\n ),\n warnings: [],\n };\n }\n\n const policySet = result.data;\n\n if (policySet.rules.length > MAX_RULES_PER_POLICY_SET) {\n errors.push(\n `Policy set exceeds maximum of ${MAX_RULES_PER_POLICY_SET} rules`,\n );\n }\n\n const ruleIds = new Set<string>();\n for (const rule of policySet.rules) {\n if (ruleIds.has(rule.id)) {\n errors.push(`Duplicate rule ID: \"${rule.id}\"`);\n }\n ruleIds.add(rule.id);\n }\n\n for (const rule of policySet.rules) {\n const ruleResult = validatePolicyRule(rule);\n warnings.push(...ruleResult.warnings);\n }\n\n const hasDenyRule = policySet.rules.some((r) => r.effect === 'DENY');\n if (!hasDenyRule && policySet.rules.length > 0) {\n warnings.push(\n 'Policy set contains only ALLOW rules. The default-deny fallback is the only protection.',\n );\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","import type { PolicyRule, PolicySet } from '@solongate/core';\nimport { UNSAFE_CONFIGURATION_WARNINGS } from '@solongate/core';\n\nexport interface SecurityWarning {\n readonly level: 'WARNING' | 'CRITICAL';\n readonly code: string;\n readonly message: string;\n readonly ruleId?: string;\n readonly recommendation: string;\n}\n\n/** Analyzes a policy set and returns security warnings. Pure function. */\nexport function analyzeSecurityWarnings(\n policySet: PolicySet,\n): readonly SecurityWarning[] {\n const warnings: SecurityWarning[] = [];\n\n for (const rule of policySet.rules) {\n warnings.push(...analyzeRuleWarnings(rule));\n }\n\n const allowRules = policySet.rules.filter(\n (r) => r.effect === 'ALLOW' && r.enabled,\n );\n const wildcardAllows = allowRules.filter((r) => r.toolPattern === '*');\n\n if (wildcardAllows.length > 0) {\n warnings.push({\n level: 'CRITICAL',\n code: 'WILDCARD_ALLOW',\n message: UNSAFE_CONFIGURATION_WARNINGS.WILDCARD_ALLOW,\n recommendation:\n 'Replace wildcard ALLOW rules with specific tool patterns.',\n });\n }\n\n return warnings;\n}\n\nfunction analyzeRuleWarnings(rule: PolicyRule): SecurityWarning[] {\n const warnings: SecurityWarning[] = [];\n\n if (rule.effect === 'ALLOW' && rule.minimumTrustLevel === 'UNTRUSTED') {\n warnings.push({\n level: 'CRITICAL',\n code: 'ALLOW_UNTRUSTED',\n message: `Rule \"${rule.id}\" allows execution for UNTRUSTED requests. Unverified LLM requests can execute tools.`,\n ruleId: rule.id,\n recommendation:\n 'Set minimumTrustLevel to VERIFIED or higher for ALLOW rules.',\n });\n }\n\n if (rule.effect === 'ALLOW' && rule.permission === 'EXECUTE') {\n warnings.push({\n level: 'WARNING',\n code: 'ALLOW_EXECUTE',\n message: UNSAFE_CONFIGURATION_WARNINGS.EXECUTE_WITHOUT_REVIEW,\n ruleId: rule.id,\n recommendation:\n 'Ensure EXECUTE permissions are intentional and scoped to specific tools.',\n });\n }\n\n return warnings;\n}\n","import type { PolicySet } from '@solongate/core';\nimport { PolicyEffect, Permission, TrustLevel } from '@solongate/core';\n\n/**\n * Creates the default \"deny all\" policy set.\n * This is the starting policy for any new SolonGate deployment.\n */\nexport function createDefaultDenyPolicySet(): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: 'default-deny',\n name: 'Default Deny All',\n description:\n 'Denies all tool executions. Add explicit ALLOW rules to grant access to specific tools.',\n version: 1,\n rules: [\n {\n id: 'deny-all-execute',\n description: 'Explicitly deny all tool executions',\n effect: PolicyEffect.DENY,\n priority: 10000,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'deny-all-write',\n description: 'Explicitly deny all write operations',\n effect: PolicyEffect.DENY,\n priority: 10000,\n toolPattern: '*',\n permission: Permission.WRITE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'deny-all-read',\n description: 'Explicitly deny all read operations',\n effect: PolicyEffect.DENY,\n priority: 10000,\n toolPattern: '*',\n permission: Permission.READ,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n\n/**\n * Creates a permissive \"allow all\" policy set.\n * Allows all tool executions — useful for development or when\n * using SolonGate only for monitoring and audit logging.\n */\nexport function createPermissivePolicySet(): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: 'permissive',\n name: 'Permissive (Allow All)',\n description: 'Allows all tool executions. SolonGate still provides input validation, rate limiting, and audit logging.',\n version: 1,\n rules: [\n {\n id: 'allow-all-execute',\n description: 'Allow all tool executions',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-all-read',\n description: 'Allow all read operations',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.READ,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-all-write',\n description: 'Allow all write operations',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.WRITE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n\n/**\n * Creates a read-only policy set for a specific tool pattern.\n * Allows reads for VERIFIED requests only.\n */\nexport function createReadOnlyPolicySet(toolPattern: string): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: `read-only-${toolPattern}`,\n name: `Read-Only: ${toolPattern}`,\n description: `Allows read access to tools matching \"${toolPattern}\". Denies write and execute.`,\n version: 1,\n rules: [\n {\n id: `allow-read-${toolPattern}`,\n description: `Allow read access to ${toolPattern}`,\n effect: PolicyEffect.ALLOW,\n priority: 100,\n toolPattern,\n permission: Permission.READ,\n minimumTrustLevel: TrustLevel.VERIFIED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n\n/**\n * Creates a sandboxed policy set for a given root directory.\n * Allows file operations within rootDir, blocks dangerous commands,\n * denies access to sensitive files.\n */\nexport function createSandboxedPolicySet(rootDir: string): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: `sandbox-${rootDir.replace(/\\//g, '-')}`,\n name: `Sandbox: ${rootDir}`,\n description: `Allows operations within ${rootDir}. Blocks dangerous commands and sensitive file access.`,\n version: 1,\n rules: [\n {\n id: 'deny-dangerous-commands',\n description: 'Block dangerous shell commands',\n effect: PolicyEffect.DENY,\n priority: 50,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n commandConstraints: {\n denied: [\n 'rm -rf *', 'rm -r /*', 'mkfs*', 'dd if=*',\n 'curl*|*bash*', 'wget*|*sh*',\n 'shutdown*', 'reboot*', 'chmod*777*',\n ],\n },\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'deny-sensitive-paths',\n description: 'Block access to sensitive files',\n effect: PolicyEffect.DENY,\n priority: 51,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n pathConstraints: {\n denied: [\n '**/.env*', '**/.ssh/**', '**/.aws/**',\n '**/credentials*', '**/*.pem', '**/*.key',\n ],\n },\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-sandboxed-files',\n description: `Allow file operations within ${rootDir}`,\n effect: PolicyEffect.ALLOW,\n priority: 100,\n toolPattern: 'file_*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n pathConstraints: {\n rootDirectory: rootDir,\n allowed: [`${rootDir}/**`],\n },\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-all-execute',\n description: 'Allow all other tool executions',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n","import type {\n PolicySet,\n PolicyDecision,\n ExecutionRequest,\n} from '@solongate/core';\nimport { POLICY_EVALUATION_TIMEOUT_MS } from '@solongate/core';\nimport { evaluatePolicy } from './evaluator.js';\nimport { validatePolicySet, type ValidationResult } from './validator.js';\nimport { analyzeSecurityWarnings, type SecurityWarning } from './warnings.js';\nimport { createDefaultDenyPolicySet } from './defaults.js';\nimport { PolicyStore, type PolicyVersion } from './policy-store.js';\n\n/**\n * PolicyEngine is the primary interface for policy evaluation.\n *\n * Wraps pure evaluation functions with:\n * - Policy set management (load, validate, swap)\n * - Timeout protection\n * - Warning aggregation\n * - Optional versioned policy store\n */\nexport class PolicyEngine {\n private policySet: PolicySet;\n private readonly timeoutMs: number;\n private readonly store: PolicyStore | null;\n\n constructor(options?: {\n policySet?: PolicySet;\n timeoutMs?: number;\n store?: PolicyStore;\n }) {\n this.policySet = options?.policySet ?? createDefaultDenyPolicySet();\n this.timeoutMs = options?.timeoutMs ?? POLICY_EVALUATION_TIMEOUT_MS;\n this.store = options?.store ?? null;\n }\n\n /**\n * Evaluates an execution request against the current policy set.\n * Never throws for denials - denial is a normal outcome, not an error.\n */\n evaluate(request: ExecutionRequest): PolicyDecision {\n const startTime = performance.now();\n const decision = evaluatePolicy(this.policySet, request);\n const elapsed = performance.now() - startTime;\n\n if (elapsed > this.timeoutMs) {\n console.warn(\n `[SolonGate] Policy evaluation took ${elapsed.toFixed(1)}ms ` +\n `(limit: ${this.timeoutMs}ms) for tool \"${request.toolName}\"`,\n );\n }\n\n return decision;\n }\n\n /**\n * Loads a new policy set, replacing the current one.\n * Validates before accepting. Auto-saves version when store is present.\n */\n loadPolicySet(\n policySet: PolicySet,\n options?: { reason?: string; createdBy?: string },\n ): ValidationResult {\n const validation = validatePolicySet(policySet);\n if (!validation.valid) {\n return validation;\n }\n this.policySet = policySet;\n\n if (this.store) {\n this.store.saveVersion(\n policySet,\n options?.reason ?? 'Policy updated',\n options?.createdBy ?? 'system',\n );\n }\n\n return validation;\n }\n\n /**\n * Rolls back to a previous policy version.\n * Only available when a PolicyStore is configured.\n */\n rollback(version: number): PolicyVersion {\n if (!this.store) {\n throw new Error('PolicyStore not configured - cannot rollback');\n }\n\n const policyVersion = this.store.rollback(this.policySet.id, version);\n this.policySet = policyVersion.policySet;\n return policyVersion;\n }\n\n getPolicySet(): Readonly<PolicySet> {\n return this.policySet;\n }\n\n getSecurityWarnings(): readonly SecurityWarning[] {\n return analyzeSecurityWarnings(this.policySet);\n }\n\n getStore(): PolicyStore | null {\n return this.store;\n }\n\n reset(): void {\n this.policySet = createDefaultDenyPolicySet();\n }\n}\n","import type { PolicySet, PolicyRule } from '@solongate/core';\nimport { createHash } from 'node:crypto';\n\n/**\n * A versioned snapshot of a policy set.\n * Immutable once created - modifications create new versions.\n */\nexport interface PolicyVersion {\n readonly version: number;\n readonly policySet: PolicySet;\n readonly hash: string;\n readonly reason: string;\n readonly createdBy: string;\n readonly createdAt: string;\n}\n\n/**\n * Diff between two policy versions.\n */\nexport interface PolicyDiff {\n readonly added: readonly PolicyRule[];\n readonly removed: readonly PolicyRule[];\n readonly modified: readonly { readonly old: PolicyRule; readonly new: PolicyRule }[];\n}\n\n/**\n * In-memory versioned policy store.\n * Stores complete history of policy changes with cryptographic hashes.\n *\n * Security properties:\n * - Immutable versions: once saved, a version cannot be modified\n * - Hash chain: each version includes SHA256 of the policy content\n * - Full history: no version is ever deleted\n */\nexport class PolicyStore {\n private readonly versions = new Map<string, PolicyVersion[]>();\n\n /**\n * Saves a new version of a policy set.\n * The version number auto-increments.\n */\n saveVersion(\n policySet: PolicySet,\n reason: string,\n createdBy: string,\n ): PolicyVersion {\n const id = policySet.id;\n const history = this.versions.get(id) ?? [];\n\n const latestVersion = history.length > 0 ? history[history.length - 1]!.version : 0;\n\n const version: PolicyVersion = {\n version: latestVersion + 1,\n policySet: Object.freeze({ ...policySet }),\n hash: this.computeHash(policySet),\n reason,\n createdBy,\n createdAt: new Date().toISOString(),\n };\n\n const newHistory = [...history, version];\n this.versions.set(id, newHistory);\n\n return version;\n }\n\n /**\n * Gets a specific version of a policy set.\n */\n getVersion(id: string, version: number): PolicyVersion | null {\n const history = this.versions.get(id);\n if (!history) return null;\n return history.find((v) => v.version === version) ?? null;\n }\n\n /**\n * Gets the latest version of a policy set.\n */\n getLatest(id: string): PolicyVersion | null {\n const history = this.versions.get(id);\n if (!history || history.length === 0) return null;\n return history[history.length - 1]!;\n }\n\n /**\n * Gets the full version history of a policy set.\n */\n getHistory(id: string): readonly PolicyVersion[] {\n return this.versions.get(id) ?? [];\n }\n\n /**\n * Rolls back to a previous version by creating a new version\n * with the same content as the target version.\n */\n rollback(id: string, toVersion: number): PolicyVersion {\n const target = this.getVersion(id, toVersion);\n if (!target) {\n throw new Error(`Version ${toVersion} not found for policy \"${id}\"`);\n }\n\n return this.saveVersion(\n target.policySet,\n `Rollback to version ${toVersion}`,\n 'system',\n );\n }\n\n /**\n * Computes a diff between two policy versions.\n */\n diff(v1: PolicyVersion, v2: PolicyVersion): PolicyDiff {\n const oldRulesMap = new Map(v1.policySet.rules.map((r) => [r.id, r]));\n const newRulesMap = new Map(v2.policySet.rules.map((r) => [r.id, r]));\n\n const added: PolicyRule[] = [];\n const removed: PolicyRule[] = [];\n const modified: { old: PolicyRule; new: PolicyRule }[] = [];\n\n // Find added and modified rules\n for (const [id, newRule] of newRulesMap) {\n const oldRule = oldRulesMap.get(id);\n if (!oldRule) {\n added.push(newRule);\n } else if (JSON.stringify(oldRule) !== JSON.stringify(newRule)) {\n modified.push({ old: oldRule, new: newRule });\n }\n }\n\n // Find removed rules\n for (const [id, oldRule] of oldRulesMap) {\n if (!newRulesMap.has(id)) {\n removed.push(oldRule);\n }\n }\n\n return { added, removed, modified };\n }\n\n /**\n * Computes SHA256 hash of a policy set for integrity verification.\n */\n computeHash(policySet: PolicySet): string {\n const serialized = JSON.stringify(policySet, Object.keys(policySet).sort());\n return createHash('sha256').update(serialized).digest('hex');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/path-matcher.ts","../src/command-matcher.ts","../src/filename-matcher.ts","../src/url-matcher.ts","../src/matcher.ts","../src/evaluator.ts","../src/validator.ts","../src/warnings.ts","../src/defaults.ts","../src/engine.ts","../src/policy-store.ts"],"names":["endTime","UNSAFE_CONFIGURATION_WARNINGS","TrustLevel"],"mappings":"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","file":"index.js","sourcesContent":["import type { PolicyRule } from '@solongate/core';\n\ntype PathConstraints = NonNullable<PolicyRule['pathConstraints']>;\n\n/**\n * Normalizes a file path for consistent matching.\n * Resolves . and .. segments, normalizes separators.\n */\nexport function normalizePath(path: string): string {\n // Normalize separators to forward slash\n let normalized = path.replace(/\\\\/g, '/');\n\n // Remove trailing slash (except for root)\n if (normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n\n // Resolve . and .. segments\n const parts = normalized.split('/');\n const resolved: string[] = [];\n\n for (const part of parts) {\n if (part === '.' || part === '') {\n if (resolved.length === 0) resolved.push('');\n continue;\n }\n if (part === '..') {\n if (resolved.length > 1) {\n resolved.pop();\n }\n continue;\n }\n resolved.push(part);\n }\n\n return resolved.join('/') || '/';\n}\n\n/**\n * Checks if a path is within a root directory (sandbox boundary).\n * Prevents escaping via .., symlinks, etc.\n */\nexport function isWithinRoot(path: string, root: string): boolean {\n const normalizedPath = normalizePath(path);\n const normalizedRoot = normalizePath(root);\n\n // Path must start with root\n if (normalizedPath === normalizedRoot) return true;\n return normalizedPath.startsWith(normalizedRoot + '/');\n}\n\n/**\n * Glob-style path pattern matching.\n * Supports:\n * - * matches any single path segment (not /)\n * - ** matches any number of path segments\n * - Exact match\n *\n * Does NOT support regex (ReDoS prevention).\n */\nexport function matchPathPattern(path: string, pattern: string): boolean {\n const normalizedPath = normalizePath(path);\n const normalizedPattern = normalizePath(pattern);\n\n if (normalizedPattern === '*') return true;\n if (normalizedPattern === normalizedPath) return true;\n\n const patternParts = normalizedPattern.split('/');\n const pathParts = normalizedPath.split('/');\n\n return matchParts(pathParts, 0, patternParts, 0);\n}\n\nfunction matchParts(\n pathParts: string[],\n pi: number,\n patternParts: string[],\n qi: number,\n): boolean {\n while (pi < pathParts.length && qi < patternParts.length) {\n const pattern = patternParts[qi]!;\n\n if (pattern === '**') {\n // ** can match zero or more path segments\n if (qi === patternParts.length - 1) return true;\n\n // Try matching ** against 0, 1, 2, ... path segments\n for (let i = pi; i <= pathParts.length; i++) {\n if (matchParts(pathParts, i, patternParts, qi + 1)) {\n return true;\n }\n }\n return false;\n }\n\n if (pattern === '*') {\n // * matches exactly one path segment\n pi++;\n qi++;\n continue;\n }\n\n // Support intra-segment globs: *.txt, file.*, test-*-data, etc.\n if (pattern.includes('*')) {\n if (!matchSegmentGlob(pathParts[pi]!, pattern)) {\n return false;\n }\n pi++;\n qi++;\n continue;\n }\n\n if (pattern !== pathParts[pi]) {\n return false;\n }\n\n pi++;\n qi++;\n }\n\n // Skip trailing ** patterns\n while (qi < patternParts.length && patternParts[qi] === '**') {\n qi++;\n }\n\n return pi === pathParts.length && qi === patternParts.length;\n}\n\n/**\n * Checks if a path is allowed by the given constraints.\n *\n * Evaluation order:\n * 1. If rootDirectory is set, path must be within it\n * 2. If denied list exists, path must NOT match any denied pattern\n * 3. If allowed list exists, path must match at least one allowed pattern\n * 4. If neither list exists, path is allowed (constraints are optional)\n */\nexport function isPathAllowed(\n path: string,\n constraints: PathConstraints,\n): boolean {\n // 1. Root directory check (sandbox)\n if (constraints.rootDirectory) {\n if (!isWithinRoot(path, constraints.rootDirectory)) {\n return false;\n }\n }\n\n // 2. Denied list - any match means denied\n if (constraints.denied && constraints.denied.length > 0) {\n for (const pattern of constraints.denied) {\n if (matchPathPattern(path, pattern)) {\n return false;\n }\n }\n }\n\n // 3. Allowed list - must match at least one\n if (constraints.allowed && constraints.allowed.length > 0) {\n let matchesAllowed = false;\n for (const pattern of constraints.allowed) {\n if (matchPathPattern(path, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n }\n\n return true;\n}\n\n/**\n * Matches a single path segment against a glob pattern containing *.\n * Examples: *.txt matches safe.txt, file.* matches file.js, *secret* matches my-secret-key\n */\nfunction matchSegmentGlob(segment: string, pattern: string): boolean {\n const startsWithStar = pattern.startsWith('*');\n const endsWithStar = pattern.endsWith('*');\n\n if (pattern === '*') return true;\n\n if (startsWithStar && endsWithStar) {\n // *infix* — contains\n const infix = pattern.slice(1, -1);\n return segment.toLowerCase().includes(infix.toLowerCase());\n }\n if (startsWithStar) {\n // *suffix — ends with\n const suffix = pattern.slice(1);\n return segment.toLowerCase().endsWith(suffix.toLowerCase());\n }\n if (endsWithStar) {\n // prefix* — starts with\n const prefix = pattern.slice(0, -1);\n return segment.toLowerCase().startsWith(prefix.toLowerCase());\n }\n\n // Single * in middle: split on * and check prefix+suffix\n const starIdx = pattern.indexOf('*');\n if (starIdx !== -1) {\n const prefix = pattern.slice(0, starIdx);\n const suffix = pattern.slice(starIdx + 1);\n const seg = segment.toLowerCase();\n return seg.startsWith(prefix.toLowerCase()) && seg.endsWith(suffix.toLowerCase()) && seg.length >= prefix.length + suffix.length;\n }\n\n return segment === pattern;\n}\n\n/**\n * Known argument field names that typically contain file paths.\n */\nconst PATH_FIELDS = new Set([\n 'path',\n 'file',\n 'file_path',\n 'filepath',\n 'filename',\n 'directory',\n 'dir',\n 'folder',\n 'source',\n 'destination',\n 'dest',\n 'target',\n 'input',\n 'output',\n 'cwd',\n 'root',\n 'notebook_path',\n]);\n\n/**\n * Extracts path-like arguments from tool call arguments.\n * Uses multiple heuristics:\n * 1. Known path field names — always extract\n * 2. Strings containing / or \\ (original heuristic)\n * 3. Strings starting with . (.env, ./foo)\n */\nexport function extractPathArguments(\n args: Readonly<Record<string, unknown>>,\n): string[] {\n const paths: string[] = [];\n const seen = new Set<string>();\n\n function addPath(value: string): void {\n const trimmed = value.trim();\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed);\n paths.push(trimmed);\n }\n }\n\n for (const [key, value] of Object.entries(args)) {\n if (typeof value !== 'string') continue;\n\n // Known path field names\n if (PATH_FIELDS.has(key.toLowerCase())) {\n addPath(value);\n continue;\n }\n\n // Contains path separators\n if (value.includes('/') || value.includes('\\\\')) {\n addPath(value);\n continue;\n }\n\n // Starts with . (.env, ./config, ../secret)\n if (value.startsWith('.')) {\n addPath(value);\n continue;\n }\n }\n\n return paths;\n}\n","import type { PolicyRule } from '@solongate/core';\n\ntype CommandConstraints = NonNullable<PolicyRule['commandConstraints']>;\n\n/**\n * Known argument field names that typically contain commands or shell-like content.\n * Used to extract commands from tool call arguments for constraint matching.\n */\nconst COMMAND_FIELDS = new Set([\n 'command',\n 'cmd',\n 'query',\n 'code',\n 'script',\n 'shell',\n 'exec',\n 'sql',\n 'expression',\n 'function',\n]);\n\n/**\n * Heuristic patterns that indicate a string value is likely a command/shell expression,\n * even when the field name is not in COMMAND_FIELDS.\n */\nconst COMMAND_HEURISTICS = [\n /^(sh|bash|cmd|powershell|zsh|fish)\\s+-c\\s+/i, // shell -c \"...\"\n /^(sudo|doas)\\s+/i, // privilege escalation\n /^\\w+\\s+&&\\s+/, // cmd1 && cmd2\n /^\\w+\\s*\\|\\s*\\w+/, // cmd1 | cmd2\n /^\\w+\\s*;\\s*\\w+/, // cmd1; cmd2\n /^(curl|wget|nc|ncat)\\s+/i, // network commands\n /^(rm|del|rmdir)\\s+/i, // destructive commands\n /^(cat|type|more|less)\\s+.*[/\\\\]/i, // file read commands with paths\n];\n\n/**\n * Extracts command-like arguments from tool call arguments.\n * Uses known field names plus heuristic detection for command-like strings\n * in any field, and recurses into nested objects/arrays.\n */\nexport function extractCommandArguments(\n args: Readonly<Record<string, unknown>>,\n): string[] {\n const commands: string[] = [];\n const seen = new Set<string>();\n\n function addCommand(value: string): void {\n const trimmed = value.trim();\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed);\n commands.push(trimmed);\n }\n }\n\n function scanValue(key: string, value: unknown): void {\n if (typeof value === 'string') {\n // Known command field names — always extract\n if (COMMAND_FIELDS.has(key.toLowerCase())) {\n addCommand(value);\n return;\n }\n // Deep scan: heuristic detection of command-like strings\n for (const pattern of COMMAND_HEURISTICS) {\n if (pattern.test(value)) {\n addCommand(value);\n return;\n }\n }\n }\n // Recurse into arrays and objects\n if (Array.isArray(value)) {\n for (const item of value) {\n scanValue(key, item);\n }\n } else if (typeof value === 'object' && value !== null) {\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n scanValue(k, v);\n }\n }\n }\n\n for (const [key, value] of Object.entries(args)) {\n scanValue(key, value);\n }\n\n return commands;\n}\n\n/**\n * Glob-style command pattern matching.\n * Matches against the command string (first word) or full command line.\n *\n * Patterns:\n * 'ls' → exact match on command name\n * 'git*' → command starts with 'git'\n * '*sql*' → command contains 'sql'\n * 'rm -rf *' → full command line starts with 'rm -rf '\n */\nexport function matchCommandPattern(command: string, pattern: string): boolean {\n if (pattern === '*') return true;\n\n const normalizedCommand = command.trim().toLowerCase();\n const normalizedPattern = pattern.trim().toLowerCase();\n\n if (normalizedPattern === normalizedCommand) return true;\n\n const startsWithStar = normalizedPattern.startsWith('*');\n const endsWithStar = normalizedPattern.endsWith('*');\n\n if (startsWithStar && endsWithStar) {\n const infix = normalizedPattern.slice(1, -1);\n return infix.length > 0 && normalizedCommand.includes(infix);\n }\n if (endsWithStar) {\n const prefix = normalizedPattern.slice(0, -1);\n return normalizedCommand.startsWith(prefix);\n }\n if (startsWithStar) {\n const suffix = normalizedPattern.slice(1);\n return normalizedCommand.endsWith(suffix);\n }\n\n // Also try matching just the command name (first word)\n const commandName = normalizedCommand.split(/\\s+/)[0] ?? '';\n return commandName === normalizedPattern;\n}\n\n/**\n * Checks if a command is allowed by the given constraints.\n *\n * Evaluation order:\n * 1. If denied list exists, command must NOT match any denied pattern\n * 2. If allowed list exists, command must match at least one allowed pattern\n * 3. If neither list exists, command is allowed (constraints are optional)\n */\nexport function isCommandAllowed(\n command: string,\n constraints: CommandConstraints,\n): boolean {\n // 1. Denied list — any match means denied\n if (constraints.denied && constraints.denied.length > 0) {\n for (const pattern of constraints.denied) {\n if (matchCommandPattern(command, pattern)) {\n return false;\n }\n }\n }\n\n // 2. Allowed list — must match at least one\n if (constraints.allowed && constraints.allowed.length > 0) {\n let matchesAllowed = false;\n for (const pattern of constraints.allowed) {\n if (matchCommandPattern(command, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n }\n\n return true;\n}\n","import type { PolicyRule } from '@solongate/core';\n\ntype FilenameConstraints = NonNullable<PolicyRule['filenameConstraints']>;\n\n/**\n * Extracts filenames from ALL string arguments (deep scan).\n * For path-like values, extracts the basename.\n * For non-path values, uses the string itself if it looks like a filename.\n */\nexport function extractFilenames(\n args: Readonly<Record<string, unknown>>,\n): string[] {\n const filenames: string[] = [];\n const seen = new Set<string>();\n\n function addFilename(name: string): void {\n const trimmed = name.trim();\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed);\n filenames.push(trimmed);\n }\n }\n\n function scanValue(value: unknown): void {\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (!trimmed) return;\n\n // Skip URLs\n if (/^https?:\\/\\//i.test(trimmed)) return;\n\n // If it contains a path separator, extract the basename\n if (trimmed.includes('/') || trimmed.includes('\\\\')) {\n const normalized = trimmed.replace(/\\\\/g, '/');\n const parts = normalized.split('/');\n const basename = parts[parts.length - 1];\n if (basename && basename.length > 0) {\n addFilename(basename);\n }\n return;\n }\n\n // Multi-word strings: split by whitespace and check each token\n // Catches: \"SELECT * FROM .env\", \"echo .env.local\", etc.\n if (trimmed.includes(' ')) {\n for (const token of trimmed.split(/\\s+/)) {\n if (token.includes('/') || token.includes('\\\\')) {\n const parts = token.replace(/\\\\/g, '/').split('/');\n const basename = parts[parts.length - 1];\n if (basename && looksLikeFilename(basename)) addFilename(basename);\n } else if (looksLikeFilename(token)) {\n addFilename(token);\n }\n }\n return;\n }\n\n // Single token: if it looks like a filename (has a dot extension or starts with dot)\n if (looksLikeFilename(trimmed)) {\n addFilename(trimmed);\n }\n return;\n }\n // Recurse into arrays and objects\n if (Array.isArray(value)) {\n for (const item of value) {\n scanValue(item);\n }\n } else if (typeof value === 'object' && value !== null) {\n for (const v of Object.values(value)) {\n scanValue(v);\n }\n }\n }\n\n for (const value of Object.values(args)) {\n scanValue(value);\n }\n\n return filenames;\n}\n\n/**\n * Checks if a string looks like a filename.\n * Matches: .env, .env.local, config.json, id_rsa, Makefile, etc.\n */\nfunction looksLikeFilename(s: string): boolean {\n // Starts with dot (.env, .gitignore, .env.local)\n if (s.startsWith('.')) return true;\n // Has a file extension (foo.txt, package.json)\n if (/\\.\\w+$/.test(s)) return true;\n // Known extensionless filenames\n const knownFiles = new Set([\n 'id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519',\n 'authorized_keys', 'known_hosts',\n 'makefile', 'dockerfile', 'vagrantfile',\n 'gemfile', 'rakefile', 'procfile',\n ]);\n if (knownFiles.has(s.toLowerCase())) return true;\n return false;\n}\n\n/**\n * Glob-style filename pattern matching (case-insensitive).\n *\n * Patterns:\n * '.env' → exact match\n * '*.pem' → ends with .pem\n * '.env.*' → starts with .env.\n * '*secret*' → contains \"secret\"\n */\nexport function matchFilenamePattern(filename: string, pattern: string): boolean {\n if (pattern === '*') return true;\n\n const normalizedFilename = filename.toLowerCase();\n const normalizedPattern = pattern.toLowerCase();\n\n if (normalizedFilename === normalizedPattern) return true;\n\n const startsWithStar = normalizedPattern.startsWith('*');\n const endsWithStar = normalizedPattern.endsWith('*');\n\n if (startsWithStar && endsWithStar) {\n const infix = normalizedPattern.slice(1, -1);\n return infix.length > 0 && normalizedFilename.includes(infix);\n }\n if (startsWithStar) {\n const suffix = normalizedPattern.slice(1);\n return normalizedFilename.endsWith(suffix);\n }\n if (endsWithStar) {\n const prefix = normalizedPattern.slice(0, -1);\n return normalizedFilename.startsWith(prefix);\n }\n\n // Single * in middle: .env.* → split on * and check prefix+suffix\n const starIdx = normalizedPattern.indexOf('*');\n if (starIdx !== -1) {\n const prefix = normalizedPattern.slice(0, starIdx);\n const suffix = normalizedPattern.slice(starIdx + 1);\n return (\n normalizedFilename.startsWith(prefix) &&\n normalizedFilename.endsWith(suffix) &&\n normalizedFilename.length >= prefix.length + suffix.length\n );\n }\n\n return false;\n}\n\n/**\n * Checks if a filename is allowed by the given constraints.\n *\n * Evaluation order:\n * 1. If denied list exists, filename must NOT match any denied pattern\n * 2. If allowed list exists, filename must match at least one allowed pattern\n * 3. If neither list exists, filename is allowed\n */\nexport function isFilenameAllowed(\n filename: string,\n constraints: FilenameConstraints,\n): boolean {\n // 1. Denied list — any match means denied\n if (constraints.denied && constraints.denied.length > 0) {\n for (const pattern of constraints.denied) {\n if (matchFilenamePattern(filename, pattern)) {\n return false;\n }\n }\n }\n\n // 2. Allowed list — must match at least one\n if (constraints.allowed && constraints.allowed.length > 0) {\n let matchesAllowed = false;\n for (const pattern of constraints.allowed) {\n if (matchFilenamePattern(filename, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n }\n\n return true;\n}\n","import type { PolicyRule } from '@solongate/core';\n\ntype UrlConstraints = NonNullable<PolicyRule['urlConstraints']>;\n\n/**\n * Known argument field names that typically contain URLs.\n */\nconst URL_FIELDS = new Set([\n 'url',\n 'href',\n 'uri',\n 'endpoint',\n 'link',\n 'src',\n 'source',\n 'target',\n 'redirect',\n 'callback',\n 'webhook',\n]);\n\n/**\n * Extracts URL arguments from tool call arguments.\n * Scans ALL string values — not just known field names.\n * Any string containing http:// or https:// is treated as a URL.\n */\nexport function extractUrlArguments(\n args: Readonly<Record<string, unknown>>,\n): string[] {\n const urls: string[] = [];\n const seen = new Set<string>();\n\n function addUrl(value: string): void {\n const trimmed = value.trim();\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed);\n urls.push(trimmed);\n }\n }\n\n function scanValue(key: string, value: unknown): void {\n if (typeof value === 'string') {\n const lower = key.toLowerCase();\n // Known URL fields — always extract\n if (URL_FIELDS.has(lower)) {\n addUrl(value);\n return;\n }\n // Deep scan: any string containing a URL protocol\n if (/https?:\\/\\//i.test(value)) {\n addUrl(value);\n return;\n }\n // Bare domain patterns (e.g. \"instagram.com\", \"foo.onion\")\n if (/^[a-zA-Z0-9]([a-zA-Z0-9-]*\\.)+[a-zA-Z]{2,}(\\/.*)?$/.test(value)) {\n addUrl(value);\n return;\n }\n }\n // Recurse into arrays and objects\n if (Array.isArray(value)) {\n for (const item of value) {\n scanValue(key, item);\n }\n } else if (typeof value === 'object' && value !== null) {\n for (const [k, v] of Object.entries(value)) {\n scanValue(k, v);\n }\n }\n }\n\n for (const [key, value] of Object.entries(args)) {\n scanValue(key, value);\n }\n\n return urls;\n}\n\n/**\n * Glob-style URL pattern matching.\n * Normalizes both URL and pattern to lowercase for comparison.\n *\n * Patterns:\n * '*instagram.com*' → URL contains instagram.com\n * 'https://api.example.com/*' → URL starts with prefix\n * '*.onion' → URL ends with .onion\n * '*' → matches everything\n */\nexport function matchUrlPattern(url: string, pattern: string): boolean {\n if (pattern === '*') return true;\n\n const normalizedUrl = url.trim().toLowerCase();\n const normalizedPattern = pattern.trim().toLowerCase();\n\n if (normalizedPattern === normalizedUrl) return true;\n\n const startsWithStar = normalizedPattern.startsWith('*');\n const endsWithStar = normalizedPattern.endsWith('*');\n\n if (startsWithStar && endsWithStar) {\n const infix = normalizedPattern.slice(1, -1);\n return infix.length > 0 && normalizedUrl.includes(infix);\n }\n if (endsWithStar) {\n const prefix = normalizedPattern.slice(0, -1);\n return normalizedUrl.startsWith(prefix);\n }\n if (startsWithStar) {\n const suffix = normalizedPattern.slice(1);\n return normalizedUrl.endsWith(suffix);\n }\n\n return false;\n}\n\n/**\n * Checks if a URL is allowed by the given constraints.\n *\n * Evaluation order:\n * 1. If denied list exists, URL must NOT match any denied pattern\n * 2. If allowed list exists, URL must match at least one allowed pattern\n * 3. If neither list exists, URL is allowed\n */\nexport function isUrlAllowed(\n url: string,\n constraints: UrlConstraints,\n): boolean {\n // 1. Denied list — any match means denied\n if (constraints.denied && constraints.denied.length > 0) {\n for (const pattern of constraints.denied) {\n if (matchUrlPattern(url, pattern)) {\n return false;\n }\n }\n }\n\n // 2. Allowed list — must match at least one\n if (constraints.allowed && constraints.allowed.length > 0) {\n let matchesAllowed = false;\n for (const pattern of constraints.allowed) {\n if (matchUrlPattern(url, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n }\n\n return true;\n}\n","import type { PolicyRule, ExecutionRequest } from '@solongate/core';\nimport { TrustLevel } from '@solongate/core';\nimport { isPathAllowed, extractPathArguments } from './path-matcher.js';\nimport { isCommandAllowed, extractCommandArguments } from './command-matcher.js';\nimport { isFilenameAllowed, extractFilenames } from './filename-matcher.js';\nimport { isUrlAllowed, extractUrlArguments } from './url-matcher.js';\n\n/**\n * Pure function: determines if a policy rule matches an execution request.\n * No side effects. No I/O. Fully deterministic.\n */\nexport function ruleMatchesRequest(\n rule: PolicyRule,\n request: ExecutionRequest,\n): boolean {\n if (!rule.enabled) return false;\n if (rule.permission && rule.permission !== request.requiredPermission) return false;\n if (!toolPatternMatches(rule.toolPattern, request.toolName)) return false;\n if (!trustLevelMeetsMinimum(request.context.trustLevel, rule.minimumTrustLevel)) {\n return false;\n }\n if (rule.argumentConstraints) {\n if (!argumentConstraintsMatch(rule.argumentConstraints, request.arguments)) {\n return false;\n }\n }\n if (rule.pathConstraints) {\n const satisfied = pathConstraintsMatch(rule.pathConstraints, request.arguments);\n // For DENY rules: match when constraints are VIOLATED (path is dangerous)\n // For ALLOW rules: match when constraints are SATISFIED (path is safe)\n if (rule.effect === 'DENY') {\n if (satisfied) return false; // path is safe → don't deny\n } else {\n if (!satisfied) return false; // path is dangerous → don't allow\n }\n }\n if (rule.commandConstraints) {\n const satisfied = commandConstraintsMatch(rule.commandConstraints, request.arguments);\n if (rule.effect === 'DENY') {\n if (satisfied) return false;\n } else {\n if (!satisfied) return false;\n }\n }\n if (rule.filenameConstraints) {\n const satisfied = filenameConstraintsMatch(rule.filenameConstraints, request.arguments);\n if (rule.effect === 'DENY') {\n if (satisfied) return false; // filename is safe → don't deny\n } else {\n if (!satisfied) return false; // filename is dangerous → don't allow\n }\n }\n if (rule.urlConstraints) {\n const satisfied = urlConstraintsMatch(rule.urlConstraints, request.arguments);\n if (rule.effect === 'DENY') {\n if (satisfied) return false; // URL is safe → don't deny\n } else {\n if (!satisfied) return false; // URL is dangerous → don't allow\n }\n }\n return true;\n}\n\n/**\n * Glob-style tool name pattern matching.\n * Supports:\n * '*' → match all\n * 'prefix*' → starts with prefix\n * '*suffix' → ends with suffix\n * '*infix*' → contains infix\n * Does NOT support regex (ReDoS prevention).\n */\nexport function toolPatternMatches(pattern: string, toolName: string): boolean {\n if (pattern === '*') return true;\n\n const startsWithStar = pattern.startsWith('*');\n const endsWithStar = pattern.endsWith('*');\n\n if (startsWithStar && endsWithStar) {\n // *infix* → contains\n const infix = pattern.slice(1, -1);\n return infix.length > 0 && toolName.includes(infix);\n }\n if (endsWithStar) {\n // prefix* → starts with\n const prefix = pattern.slice(0, -1);\n return toolName.startsWith(prefix);\n }\n if (startsWithStar) {\n // *suffix → ends with\n const suffix = pattern.slice(1);\n return toolName.endsWith(suffix);\n }\n\n return pattern === toolName;\n}\n\nconst TRUST_LEVEL_ORDER: Record<string, number> = {\n [TrustLevel.UNTRUSTED]: 0,\n [TrustLevel.VERIFIED]: 1,\n [TrustLevel.TRUSTED]: 2,\n};\n\nexport function trustLevelMeetsMinimum(\n actual: TrustLevel,\n minimum: TrustLevel,\n): boolean {\n return (TRUST_LEVEL_ORDER[actual] ?? -1) >= (TRUST_LEVEL_ORDER[minimum] ?? Infinity);\n}\n\n/**\n * Condition operators for argument constraints.\n * When constraint value is a plain string → exact match (or '*' for any).\n * When constraint value is an object → operator-based matching:\n * { $contains: \"str\" } — value includes substring\n * { $notContains: \"str\" } — value does NOT include substring\n * { $startsWith: \"str\" } — value starts with prefix\n * { $endsWith: \"str\" } — value ends with suffix\n * { $in: [\"a\",\"b\"] } — value is one of the listed values\n * { $notIn: [\"a\",\"b\"] } — value is NOT one of the listed values\n * { $gt: 5 } — numeric greater than\n * { $lt: 5 } — numeric less than\n * { $gte: 5 } — numeric greater than or equal\n * { $lte: 5 } — numeric less than or equal\n */\nfunction argumentConstraintsMatch(\n constraints: Record<string, unknown>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n for (const [key, constraint] of Object.entries(constraints)) {\n if (!(key in args)) return false;\n const argValue = args[key];\n\n // Plain string: exact match (backward compatible)\n if (typeof constraint === 'string') {\n if (constraint === '*') continue;\n if (typeof argValue === 'string') {\n if (argValue !== constraint) return false;\n } else {\n return false;\n }\n continue;\n }\n\n // Object with operators\n if (typeof constraint === 'object' && constraint !== null && !Array.isArray(constraint)) {\n const ops = constraint as Record<string, unknown>;\n const strValue = typeof argValue === 'string' ? argValue : undefined;\n const numValue = typeof argValue === 'number' ? argValue : undefined;\n\n if ('$contains' in ops && typeof ops.$contains === 'string') {\n if (!strValue || !strValue.includes(ops.$contains)) return false;\n }\n if ('$notContains' in ops && typeof ops.$notContains === 'string') {\n if (strValue && strValue.includes(ops.$notContains)) return false;\n }\n if ('$startsWith' in ops && typeof ops.$startsWith === 'string') {\n if (!strValue || !strValue.startsWith(ops.$startsWith)) return false;\n }\n if ('$endsWith' in ops && typeof ops.$endsWith === 'string') {\n if (!strValue || !strValue.endsWith(ops.$endsWith)) return false;\n }\n if ('$in' in ops && Array.isArray(ops.$in)) {\n if (!ops.$in.includes(argValue)) return false;\n }\n if ('$notIn' in ops && Array.isArray(ops.$notIn)) {\n if (ops.$notIn.includes(argValue)) return false;\n }\n if ('$gt' in ops && typeof ops.$gt === 'number') {\n if (numValue === undefined || numValue <= ops.$gt) return false;\n }\n if ('$lt' in ops && typeof ops.$lt === 'number') {\n if (numValue === undefined || numValue >= ops.$lt) return false;\n }\n if ('$gte' in ops && typeof ops.$gte === 'number') {\n if (numValue === undefined || numValue < ops.$gte) return false;\n }\n if ('$lte' in ops && typeof ops.$lte === 'number') {\n if (numValue === undefined || numValue > ops.$lte) return false;\n }\n\n continue;\n }\n }\n return true;\n}\n\nfunction pathConstraintsMatch(\n constraints: NonNullable<PolicyRule['pathConstraints']>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n const paths = extractPathArguments(args);\n\n // If no path arguments found, constraints don't apply\n if (paths.length === 0) return true;\n\n // ALL path arguments must satisfy constraints\n return paths.every((path) => isPathAllowed(path, constraints));\n}\n\nfunction commandConstraintsMatch(\n constraints: NonNullable<PolicyRule['commandConstraints']>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n const commands = extractCommandArguments(args);\n\n // If no command arguments found, constraints don't apply\n if (commands.length === 0) return true;\n\n // ALL command arguments must satisfy constraints\n return commands.every((cmd) => isCommandAllowed(cmd, constraints));\n}\n\nfunction filenameConstraintsMatch(\n constraints: NonNullable<PolicyRule['filenameConstraints']>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n const filenames = extractFilenames(args);\n\n // If no filename arguments found, constraints don't apply\n if (filenames.length === 0) return true;\n\n // ALL filenames must satisfy constraints\n return filenames.every((name) => isFilenameAllowed(name, constraints));\n}\n\nfunction urlConstraintsMatch(\n constraints: NonNullable<PolicyRule['urlConstraints']>,\n args: Readonly<Record<string, unknown>>,\n): boolean {\n const urls = extractUrlArguments(args);\n\n // If no URL arguments found, constraints don't apply\n if (urls.length === 0) return true;\n\n // ALL URLs must satisfy constraints\n return urls.every((url) => isUrlAllowed(url, constraints));\n}\n","import type {\n PolicySet,\n PolicyDecision,\n ExecutionRequest,\n PolicyEffect,\n} from '@solongate/core';\nimport { DEFAULT_POLICY_EFFECT } from '@solongate/core';\nimport { ruleMatchesRequest } from './matcher.js';\n\n/**\n * Evaluates a policy set against an execution request.\n *\n * Pure function: no side effects, no I/O, fully deterministic.\n *\n * Algorithm:\n * 1. Sort rules by priority (ascending - lower number = higher priority)\n * 2. Find the first matching rule\n * 3. If a rule matches, return its effect\n * 4. If no rule matches, return DENY (default-deny)\n */\nexport function evaluatePolicy(\n policySet: PolicySet,\n request: ExecutionRequest,\n): PolicyDecision {\n const startTime = performance.now();\n\n const sortedRules = [...policySet.rules].sort(\n (a, b) => a.priority - b.priority,\n );\n\n for (const rule of sortedRules) {\n if (ruleMatchesRequest(rule, request)) {\n const endTime = performance.now();\n return {\n effect: rule.effect,\n matchedRule: rule,\n reason: `Matched rule \"${rule.id}\": ${rule.description}`,\n timestamp: new Date().toISOString(),\n evaluationTimeMs: endTime - startTime,\n };\n }\n }\n\n const endTime = performance.now();\n return {\n effect: DEFAULT_POLICY_EFFECT as PolicyEffect,\n matchedRule: null,\n reason: 'No matching policy rule found. Default action: DENY.',\n timestamp: new Date().toISOString(),\n evaluationTimeMs: endTime - startTime,\n metadata: {\n evaluatedRules: sortedRules.length,\n ruleIds: sortedRules.map((r) => r.id),\n requestContext: {\n tool: request.toolName,\n arguments: Object.keys(request.arguments ?? {}),\n },\n },\n };\n}\n","import { PolicyRuleSchema, PolicySetSchema } from '@solongate/core';\nimport {\n MAX_RULES_PER_POLICY_SET,\n UNSAFE_CONFIGURATION_WARNINGS,\n} from '@solongate/core';\n\nexport interface ValidationResult {\n readonly valid: boolean;\n readonly errors: readonly string[];\n readonly warnings: readonly string[];\n}\n\nexport function validatePolicyRule(input: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const result = PolicyRuleSchema.safeParse(input);\n if (!result.success) {\n return {\n valid: false,\n errors: result.error.errors.map(\n (e) => `${e.path.join('.')}: ${e.message}`,\n ),\n warnings: [],\n };\n }\n\n const rule = result.data;\n\n if (rule.toolPattern === '*' && rule.effect === 'ALLOW') {\n warnings.push(UNSAFE_CONFIGURATION_WARNINGS.WILDCARD_ALLOW);\n }\n\n if (rule.minimumTrustLevel === 'TRUSTED') {\n warnings.push(UNSAFE_CONFIGURATION_WARNINGS.TRUSTED_LEVEL_EXTERNAL);\n }\n\n if (!rule.permission || rule.permission === 'EXECUTE') {\n warnings.push(UNSAFE_CONFIGURATION_WARNINGS.EXECUTE_WITHOUT_REVIEW);\n }\n\n return { valid: true, errors, warnings };\n}\n\nexport function validatePolicySet(input: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const result = PolicySetSchema.safeParse(input);\n if (!result.success) {\n return {\n valid: false,\n errors: result.error.errors.map(\n (e) => `${e.path.join('.')}: ${e.message}`,\n ),\n warnings: [],\n };\n }\n\n const policySet = result.data;\n\n if (policySet.rules.length > MAX_RULES_PER_POLICY_SET) {\n errors.push(\n `Policy set exceeds maximum of ${MAX_RULES_PER_POLICY_SET} rules`,\n );\n }\n\n const ruleIds = new Set<string>();\n for (const rule of policySet.rules) {\n if (ruleIds.has(rule.id)) {\n errors.push(`Duplicate rule ID: \"${rule.id}\"`);\n }\n ruleIds.add(rule.id);\n }\n\n for (const rule of policySet.rules) {\n const ruleResult = validatePolicyRule(rule);\n warnings.push(...ruleResult.warnings);\n }\n\n const hasDenyRule = policySet.rules.some((r) => r.effect === 'DENY');\n if (!hasDenyRule && policySet.rules.length > 0) {\n warnings.push(\n 'Policy set contains only ALLOW rules. The default-deny fallback is the only protection.',\n );\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","import type { PolicyRule, PolicySet } from '@solongate/core';\nimport { UNSAFE_CONFIGURATION_WARNINGS } from '@solongate/core';\n\nexport interface SecurityWarning {\n readonly level: 'WARNING' | 'CRITICAL';\n readonly code: string;\n readonly message: string;\n readonly ruleId?: string;\n readonly recommendation: string;\n}\n\n/** Analyzes a policy set and returns security warnings. Pure function. */\nexport function analyzeSecurityWarnings(\n policySet: PolicySet,\n): readonly SecurityWarning[] {\n const warnings: SecurityWarning[] = [];\n\n for (const rule of policySet.rules) {\n warnings.push(...analyzeRuleWarnings(rule));\n }\n\n const allowRules = policySet.rules.filter(\n (r) => r.effect === 'ALLOW' && r.enabled,\n );\n const wildcardAllows = allowRules.filter((r) => r.toolPattern === '*');\n\n if (wildcardAllows.length > 0) {\n warnings.push({\n level: 'CRITICAL',\n code: 'WILDCARD_ALLOW',\n message: UNSAFE_CONFIGURATION_WARNINGS.WILDCARD_ALLOW,\n recommendation:\n 'Replace wildcard ALLOW rules with specific tool patterns.',\n });\n }\n\n return warnings;\n}\n\nfunction analyzeRuleWarnings(rule: PolicyRule): SecurityWarning[] {\n const warnings: SecurityWarning[] = [];\n\n if (rule.effect === 'ALLOW' && rule.minimumTrustLevel === 'UNTRUSTED') {\n warnings.push({\n level: 'CRITICAL',\n code: 'ALLOW_UNTRUSTED',\n message: `Rule \"${rule.id}\" allows execution for UNTRUSTED requests. Unverified LLM requests can execute tools.`,\n ruleId: rule.id,\n recommendation:\n 'Set minimumTrustLevel to VERIFIED or higher for ALLOW rules.',\n });\n }\n\n if (rule.effect === 'ALLOW' && (!rule.permission || rule.permission === 'EXECUTE')) {\n warnings.push({\n level: 'WARNING',\n code: 'ALLOW_EXECUTE',\n message: UNSAFE_CONFIGURATION_WARNINGS.EXECUTE_WITHOUT_REVIEW,\n ruleId: rule.id,\n recommendation:\n 'Ensure EXECUTE permissions are intentional and scoped to specific tools.',\n });\n }\n\n return warnings;\n}\n","import type { PolicySet } from '@solongate/core';\nimport { PolicyEffect, Permission, TrustLevel } from '@solongate/core';\n\n/**\n * Creates the default \"deny all\" policy set.\n * This is the starting policy for any new SolonGate deployment.\n */\nexport function createDefaultDenyPolicySet(): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: 'default-deny',\n name: 'Default Deny All',\n description:\n 'Denies all tool executions. Add explicit ALLOW rules to grant access to specific tools.',\n version: 1,\n rules: [\n {\n id: 'deny-all-execute',\n description: 'Explicitly deny all tool executions',\n effect: PolicyEffect.DENY,\n priority: 10000,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'deny-all-write',\n description: 'Explicitly deny all write operations',\n effect: PolicyEffect.DENY,\n priority: 10000,\n toolPattern: '*',\n permission: Permission.WRITE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'deny-all-read',\n description: 'Explicitly deny all read operations',\n effect: PolicyEffect.DENY,\n priority: 10000,\n toolPattern: '*',\n permission: Permission.READ,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n\n/**\n * Creates a permissive \"allow all\" policy set.\n * Allows all tool executions — useful for development or when\n * using SolonGate only for monitoring and audit logging.\n */\nexport function createPermissivePolicySet(): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: 'permissive',\n name: 'Permissive (Allow All)',\n description: 'Allows all tool executions. SolonGate still provides input validation, rate limiting, and audit logging.',\n version: 1,\n rules: [\n {\n id: 'allow-all-execute',\n description: 'Allow all tool executions',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-all-read',\n description: 'Allow all read operations',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.READ,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-all-write',\n description: 'Allow all write operations',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.WRITE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n\n/**\n * Creates a read-only policy set for a specific tool pattern.\n * Allows reads for VERIFIED requests only.\n */\nexport function createReadOnlyPolicySet(toolPattern: string): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: `read-only-${toolPattern}`,\n name: `Read-Only: ${toolPattern}`,\n description: `Allows read access to tools matching \"${toolPattern}\". Denies write and execute.`,\n version: 1,\n rules: [\n {\n id: `allow-read-${toolPattern}`,\n description: `Allow read access to ${toolPattern}`,\n effect: PolicyEffect.ALLOW,\n priority: 100,\n toolPattern,\n permission: Permission.READ,\n minimumTrustLevel: TrustLevel.VERIFIED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n\n/**\n * Creates a sandboxed policy set for a given root directory.\n * Allows file operations within rootDir, blocks dangerous commands,\n * denies access to sensitive files.\n */\nexport function createSandboxedPolicySet(rootDir: string): PolicySet {\n const now = new Date().toISOString();\n\n return {\n id: `sandbox-${rootDir.replace(/\\//g, '-')}`,\n name: `Sandbox: ${rootDir}`,\n description: `Allows operations within ${rootDir}. Blocks dangerous commands and sensitive file access.`,\n version: 1,\n rules: [\n {\n id: 'deny-dangerous-commands',\n description: 'Block dangerous shell commands',\n effect: PolicyEffect.DENY,\n priority: 50,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n commandConstraints: {\n denied: [\n 'rm -rf *', 'rm -r /*', 'mkfs*', 'dd if=*',\n 'curl*|*bash*', 'wget*|*sh*',\n 'shutdown*', 'reboot*', 'chmod*777*',\n ],\n },\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'deny-sensitive-paths',\n description: 'Block access to sensitive files',\n effect: PolicyEffect.DENY,\n priority: 51,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n pathConstraints: {\n denied: [\n '**/.env*', '**/.ssh/**', '**/.aws/**',\n '**/credentials*', '**/*.pem', '**/*.key',\n ],\n },\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-sandboxed-files',\n description: `Allow file operations within ${rootDir}`,\n effect: PolicyEffect.ALLOW,\n priority: 100,\n toolPattern: 'file_*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n pathConstraints: {\n rootDirectory: rootDir,\n allowed: [`${rootDir}/**`],\n },\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n {\n id: 'allow-all-execute',\n description: 'Allow all other tool executions',\n effect: PolicyEffect.ALLOW,\n priority: 1000,\n toolPattern: '*',\n permission: Permission.EXECUTE,\n minimumTrustLevel: TrustLevel.UNTRUSTED,\n enabled: true,\n createdAt: now,\n updatedAt: now,\n },\n ],\n createdAt: now,\n updatedAt: now,\n };\n}\n","import type {\n PolicySet,\n PolicyDecision,\n ExecutionRequest,\n} from '@solongate/core';\nimport { POLICY_EVALUATION_TIMEOUT_MS } from '@solongate/core';\nimport { evaluatePolicy } from './evaluator.js';\nimport { validatePolicySet, type ValidationResult } from './validator.js';\nimport { analyzeSecurityWarnings, type SecurityWarning } from './warnings.js';\nimport { createDefaultDenyPolicySet } from './defaults.js';\nimport { PolicyStore, type PolicyVersion } from './policy-store.js';\n\n/**\n * PolicyEngine is the primary interface for policy evaluation.\n *\n * Wraps pure evaluation functions with:\n * - Policy set management (load, validate, swap)\n * - Timeout protection\n * - Warning aggregation\n * - Optional versioned policy store\n */\nexport class PolicyEngine {\n private policySet: PolicySet;\n private readonly timeoutMs: number;\n private readonly store: PolicyStore | null;\n\n constructor(options?: {\n policySet?: PolicySet;\n timeoutMs?: number;\n store?: PolicyStore;\n }) {\n this.policySet = options?.policySet ?? createDefaultDenyPolicySet();\n this.timeoutMs = options?.timeoutMs ?? POLICY_EVALUATION_TIMEOUT_MS;\n this.store = options?.store ?? null;\n }\n\n /**\n * Evaluates an execution request against the current policy set.\n * Never throws for denials - denial is a normal outcome, not an error.\n */\n evaluate(request: ExecutionRequest): PolicyDecision {\n const startTime = performance.now();\n const decision = evaluatePolicy(this.policySet, request);\n const elapsed = performance.now() - startTime;\n\n if (elapsed > this.timeoutMs) {\n console.warn(\n `[SolonGate] Policy evaluation took ${elapsed.toFixed(1)}ms ` +\n `(limit: ${this.timeoutMs}ms) for tool \"${request.toolName}\"`,\n );\n }\n\n return decision;\n }\n\n /**\n * Loads a new policy set, replacing the current one.\n * Validates before accepting. Auto-saves version when store is present.\n */\n loadPolicySet(\n policySet: PolicySet,\n options?: { reason?: string; createdBy?: string },\n ): ValidationResult {\n const validation = validatePolicySet(policySet);\n if (!validation.valid) {\n return validation;\n }\n this.policySet = policySet;\n\n if (this.store) {\n this.store.saveVersion(\n policySet,\n options?.reason ?? 'Policy updated',\n options?.createdBy ?? 'system',\n );\n }\n\n return validation;\n }\n\n /**\n * Rolls back to a previous policy version.\n * Only available when a PolicyStore is configured.\n */\n rollback(version: number): PolicyVersion {\n if (!this.store) {\n throw new Error('PolicyStore not configured - cannot rollback');\n }\n\n const policyVersion = this.store.rollback(this.policySet.id, version);\n this.policySet = policyVersion.policySet;\n return policyVersion;\n }\n\n getPolicySet(): Readonly<PolicySet> {\n return this.policySet;\n }\n\n getSecurityWarnings(): readonly SecurityWarning[] {\n return analyzeSecurityWarnings(this.policySet);\n }\n\n getStore(): PolicyStore | null {\n return this.store;\n }\n\n reset(): void {\n this.policySet = createDefaultDenyPolicySet();\n }\n}\n","import type { PolicySet, PolicyRule } from '@solongate/core';\nimport { createHash } from 'node:crypto';\n\n/**\n * A versioned snapshot of a policy set.\n * Immutable once created - modifications create new versions.\n */\nexport interface PolicyVersion {\n readonly version: number;\n readonly policySet: PolicySet;\n readonly hash: string;\n readonly reason: string;\n readonly createdBy: string;\n readonly createdAt: string;\n}\n\n/**\n * Diff between two policy versions.\n */\nexport interface PolicyDiff {\n readonly added: readonly PolicyRule[];\n readonly removed: readonly PolicyRule[];\n readonly modified: readonly { readonly old: PolicyRule; readonly new: PolicyRule }[];\n}\n\n/**\n * In-memory versioned policy store.\n * Stores complete history of policy changes with cryptographic hashes.\n *\n * Security properties:\n * - Immutable versions: once saved, a version cannot be modified\n * - Hash chain: each version includes SHA256 of the policy content\n * - Full history: no version is ever deleted\n */\nexport class PolicyStore {\n private readonly versions = new Map<string, PolicyVersion[]>();\n\n /**\n * Saves a new version of a policy set.\n * The version number auto-increments.\n */\n saveVersion(\n policySet: PolicySet,\n reason: string,\n createdBy: string,\n ): PolicyVersion {\n const id = policySet.id;\n const history = this.versions.get(id) ?? [];\n\n const latestVersion = history.length > 0 ? history[history.length - 1]!.version : 0;\n\n const version: PolicyVersion = {\n version: latestVersion + 1,\n policySet: Object.freeze({ ...policySet }),\n hash: this.computeHash(policySet),\n reason,\n createdBy,\n createdAt: new Date().toISOString(),\n };\n\n const newHistory = [...history, version];\n this.versions.set(id, newHistory);\n\n return version;\n }\n\n /**\n * Gets a specific version of a policy set.\n */\n getVersion(id: string, version: number): PolicyVersion | null {\n const history = this.versions.get(id);\n if (!history) return null;\n return history.find((v) => v.version === version) ?? null;\n }\n\n /**\n * Gets the latest version of a policy set.\n */\n getLatest(id: string): PolicyVersion | null {\n const history = this.versions.get(id);\n if (!history || history.length === 0) return null;\n return history[history.length - 1]!;\n }\n\n /**\n * Gets the full version history of a policy set.\n */\n getHistory(id: string): readonly PolicyVersion[] {\n return this.versions.get(id) ?? [];\n }\n\n /**\n * Rolls back to a previous version by creating a new version\n * with the same content as the target version.\n */\n rollback(id: string, toVersion: number): PolicyVersion {\n const target = this.getVersion(id, toVersion);\n if (!target) {\n throw new Error(`Version ${toVersion} not found for policy \"${id}\"`);\n }\n\n return this.saveVersion(\n target.policySet,\n `Rollback to version ${toVersion}`,\n 'system',\n );\n }\n\n /**\n * Computes a diff between two policy versions.\n */\n diff(v1: PolicyVersion, v2: PolicyVersion): PolicyDiff {\n const oldRulesMap = new Map(v1.policySet.rules.map((r) => [r.id, r]));\n const newRulesMap = new Map(v2.policySet.rules.map((r) => [r.id, r]));\n\n const added: PolicyRule[] = [];\n const removed: PolicyRule[] = [];\n const modified: { old: PolicyRule; new: PolicyRule }[] = [];\n\n // Find added and modified rules\n for (const [id, newRule] of newRulesMap) {\n const oldRule = oldRulesMap.get(id);\n if (!oldRule) {\n added.push(newRule);\n } else if (JSON.stringify(oldRule) !== JSON.stringify(newRule)) {\n modified.push({ old: oldRule, new: newRule });\n }\n }\n\n // Find removed rules\n for (const [id, oldRule] of oldRulesMap) {\n if (!newRulesMap.has(id)) {\n removed.push(oldRule);\n }\n }\n\n return { added, removed, modified };\n }\n\n /**\n * Computes SHA256 hash of a policy set for integrity verification.\n */\n computeHash(policySet: PolicySet): string {\n const serialized = JSON.stringify(policySet, Object.keys(policySet).sort());\n return createHash('sha256').update(serialized).digest('hex');\n }\n}\n"]}
|