agentlock-shared 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/billing.test.d.ts +2 -0
- package/dist/__tests__/billing.test.d.ts.map +1 -0
- package/dist/__tests__/billing.test.js +31 -0
- package/dist/__tests__/billing.test.js.map +1 -0
- package/dist/__tests__/crypto.test.js +137 -47
- package/dist/__tests__/crypto.test.js.map +1 -1
- package/dist/__tests__/dns-pinning.test.d.ts +2 -0
- package/dist/__tests__/dns-pinning.test.d.ts.map +1 -0
- package/dist/__tests__/dns-pinning.test.js +33 -0
- package/dist/__tests__/dns-pinning.test.js.map +1 -0
- package/dist/__tests__/llm-classifier-cache-store.test.d.ts +2 -0
- package/dist/__tests__/llm-classifier-cache-store.test.d.ts.map +1 -0
- package/dist/__tests__/llm-classifier-cache-store.test.js +65 -0
- package/dist/__tests__/llm-classifier-cache-store.test.js.map +1 -0
- package/dist/__tests__/llm-classifier-cache.test.d.ts +2 -0
- package/dist/__tests__/llm-classifier-cache.test.d.ts.map +1 -0
- package/dist/__tests__/llm-classifier-cache.test.js +44 -0
- package/dist/__tests__/llm-classifier-cache.test.js.map +1 -0
- package/dist/__tests__/llm-classifier.test.d.ts +2 -0
- package/dist/__tests__/llm-classifier.test.d.ts.map +1 -0
- package/dist/__tests__/llm-classifier.test.js +167 -0
- package/dist/__tests__/llm-classifier.test.js.map +1 -0
- package/dist/__tests__/messaging.test.d.ts +2 -0
- package/dist/__tests__/messaging.test.d.ts.map +1 -0
- package/dist/__tests__/messaging.test.js +75 -0
- package/dist/__tests__/messaging.test.js.map +1 -0
- package/dist/__tests__/plans-classifier-limits.test.d.ts +2 -0
- package/dist/__tests__/plans-classifier-limits.test.d.ts.map +1 -0
- package/dist/__tests__/plans-classifier-limits.test.js +22 -0
- package/dist/__tests__/plans-classifier-limits.test.js.map +1 -0
- package/dist/__tests__/policy-category-floor.test.d.ts +2 -0
- package/dist/__tests__/policy-category-floor.test.d.ts.map +1 -0
- package/dist/__tests__/policy-category-floor.test.js +46 -0
- package/dist/__tests__/policy-category-floor.test.js.map +1 -0
- package/dist/__tests__/policy-claude-bash.test.d.ts +2 -0
- package/dist/__tests__/policy-claude-bash.test.d.ts.map +1 -0
- package/dist/__tests__/policy-claude-bash.test.js +401 -0
- package/dist/__tests__/policy-claude-bash.test.js.map +1 -0
- package/dist/__tests__/policy-llm-floor.test.d.ts +2 -0
- package/dist/__tests__/policy-llm-floor.test.d.ts.map +1 -0
- package/dist/__tests__/policy-llm-floor.test.js +107 -0
- package/dist/__tests__/policy-llm-floor.test.js.map +1 -0
- package/dist/__tests__/policy-ssh-e2e.test.d.ts +2 -0
- package/dist/__tests__/policy-ssh-e2e.test.d.ts.map +1 -0
- package/dist/__tests__/policy-ssh-e2e.test.js +89 -0
- package/dist/__tests__/policy-ssh-e2e.test.js.map +1 -0
- package/dist/__tests__/policy-ssh-sessions.test.d.ts +2 -0
- package/dist/__tests__/policy-ssh-sessions.test.d.ts.map +1 -0
- package/dist/__tests__/policy-ssh-sessions.test.js +139 -0
- package/dist/__tests__/policy-ssh-sessions.test.js.map +1 -0
- package/dist/__tests__/policy-ssh.test.d.ts +2 -0
- package/dist/__tests__/policy-ssh.test.d.ts.map +1 -0
- package/dist/__tests__/policy-ssh.test.js +180 -0
- package/dist/__tests__/policy-ssh.test.js.map +1 -0
- package/dist/__tests__/policy.test.js +522 -7
- package/dist/__tests__/policy.test.js.map +1 -1
- package/dist/__tests__/redact.test.js +76 -0
- package/dist/__tests__/redact.test.js.map +1 -1
- package/dist/__tests__/signing.test.js +89 -0
- package/dist/__tests__/signing.test.js.map +1 -1
- package/dist/__tests__/ssh-fingerprint.test.d.ts +2 -0
- package/dist/__tests__/ssh-fingerprint.test.d.ts.map +1 -0
- package/dist/__tests__/ssh-fingerprint.test.js +19 -0
- package/dist/__tests__/ssh-fingerprint.test.js.map +1 -0
- package/dist/__tests__/vpn-route.test.d.ts +2 -0
- package/dist/__tests__/vpn-route.test.d.ts.map +1 -0
- package/dist/__tests__/vpn-route.test.js +72 -0
- package/dist/__tests__/vpn-route.test.js.map +1 -0
- package/dist/__tests__/wireguard.test.d.ts +2 -0
- package/dist/__tests__/wireguard.test.d.ts.map +1 -0
- package/dist/__tests__/wireguard.test.js +114 -0
- package/dist/__tests__/wireguard.test.js.map +1 -0
- package/dist/billing.d.ts +12 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +41 -0
- package/dist/billing.js.map +1 -0
- package/dist/crypto.d.ts +41 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +208 -6
- package/dist/crypto.js.map +1 -1
- package/dist/dns-pinning.d.ts +28 -0
- package/dist/dns-pinning.d.ts.map +1 -0
- package/dist/dns-pinning.js +113 -0
- package/dist/dns-pinning.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/llm-classifier-cache-store.d.ts +49 -0
- package/dist/llm-classifier-cache-store.d.ts.map +1 -0
- package/dist/llm-classifier-cache-store.js +63 -0
- package/dist/llm-classifier-cache-store.js.map +1 -0
- package/dist/llm-classifier-cache.d.ts +6 -0
- package/dist/llm-classifier-cache.d.ts.map +1 -0
- package/dist/llm-classifier-cache.js +52 -0
- package/dist/llm-classifier-cache.js.map +1 -0
- package/dist/llm-classifier.d.ts +29 -0
- package/dist/llm-classifier.d.ts.map +1 -0
- package/dist/llm-classifier.js +191 -0
- package/dist/llm-classifier.js.map +1 -0
- package/dist/observability.d.ts +36 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +75 -0
- package/dist/observability.js.map +1 -0
- package/dist/plans.d.ts +21 -0
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +52 -14
- package/dist/plans.js.map +1 -1
- package/dist/policy.d.ts +173 -3
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +951 -58
- package/dist/policy.js.map +1 -1
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +104 -7
- package/dist/redact.js.map +1 -1
- package/dist/regex-safety.d.ts +21 -0
- package/dist/regex-safety.d.ts.map +1 -0
- package/dist/regex-safety.js +49 -0
- package/dist/regex-safety.js.map +1 -0
- package/dist/sanitize.d.ts +31 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +54 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/schemas.d.ts +267 -14
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +152 -10
- package/dist/schemas.js.map +1 -1
- package/dist/signing.d.ts +15 -0
- package/dist/signing.d.ts.map +1 -1
- package/dist/signing.js +53 -4
- package/dist/signing.js.map +1 -1
- package/dist/ssh-fingerprint.d.ts +10 -0
- package/dist/ssh-fingerprint.d.ts.map +1 -0
- package/dist/ssh-fingerprint.js +52 -0
- package/dist/ssh-fingerprint.js.map +1 -0
- package/dist/ssrf.d.ts +36 -0
- package/dist/ssrf.d.ts.map +1 -0
- package/dist/ssrf.js +140 -0
- package/dist/ssrf.js.map +1 -0
- package/dist/types.d.ts +131 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/wireguard.d.ts +63 -0
- package/dist/wireguard.d.ts.map +1 -0
- package/dist/wireguard.js +226 -0
- package/dist/wireguard.js.map +1 -0
- package/package.json +42 -29
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-test.log +0 -34
- package/dist/__tests__/content-crypto.test.d.ts +0 -2
- package/dist/__tests__/content-crypto.test.d.ts.map +0 -1
- package/dist/__tests__/content-crypto.test.js +0 -117
- package/dist/__tests__/content-crypto.test.js.map +0 -1
- package/dist/content-crypto.d.ts +0 -24
- package/dist/content-crypto.d.ts.map +0 -1
- package/dist/content-crypto.js +0 -58
- package/dist/content-crypto.js.map +0 -1
- package/src/__tests__/policy.test.ts +0 -88
- package/src/__tests__/redact.test.ts +0 -41
- package/src/__tests__/signing.test.ts +0 -55
- package/src/crypto.ts +0 -87
- package/src/index.ts +0 -8
- package/src/mcp-catalog.ts +0 -181
- package/src/plans.ts +0 -96
- package/src/policy.ts +0 -186
- package/src/redact.ts +0 -114
- package/src/schemas.ts +0 -53
- package/src/signing.ts +0 -120
- package/src/types.ts +0 -212
- package/test-gateway.mjs +0 -47
- package/tsconfig.json +0 -10
- package/vitest.config.ts +0 -8
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const policy_js_1 = require("../policy.js");
|
|
5
|
+
(0, vitest_1.describe)('compileClaudeBashPattern (glob semantics, mirrors SSH)', () => {
|
|
6
|
+
(0, vitest_1.it)('exact-matches a literal pattern with no wildcards', () => {
|
|
7
|
+
const re = (0, policy_js_1.compileClaudeBashPattern)('grep');
|
|
8
|
+
(0, vitest_1.expect)(re.test('grep')).toBe(true);
|
|
9
|
+
(0, vitest_1.expect)(re.test('grep foo')).toBe(false);
|
|
10
|
+
(0, vitest_1.expect)(re.test('grepfoo')).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('treats `*` as a glob wildcard for any run of characters', () => {
|
|
13
|
+
const re = (0, policy_js_1.compileClaudeBashPattern)('grep *');
|
|
14
|
+
(0, vitest_1.expect)(re.test('grep')).toBe(false); // pattern requires at least the space
|
|
15
|
+
(0, vitest_1.expect)(re.test('grep foo')).toBe(true);
|
|
16
|
+
(0, vitest_1.expect)(re.test('grep /home/foo')).toBe(true);
|
|
17
|
+
(0, vitest_1.expect)(re.test('grepfoo')).toBe(false); // space is part of the pattern
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.it)('lets you tighten globs to a path prefix', () => {
|
|
20
|
+
const re = (0, policy_js_1.compileClaudeBashPattern)('grep /home/*');
|
|
21
|
+
(0, vitest_1.expect)(re.test('grep /home/foo')).toBe(true);
|
|
22
|
+
(0, vitest_1.expect)(re.test('grep /home/sub/file.txt')).toBe(true);
|
|
23
|
+
(0, vitest_1.expect)(re.test('grep /etc/passwd')).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)('honors the /regex/ escape hatch', () => {
|
|
26
|
+
const re = (0, policy_js_1.compileClaudeBashPattern)('/^(rm|dd)\\s/');
|
|
27
|
+
(0, vitest_1.expect)(re.test('rm foo')).toBe(true);
|
|
28
|
+
(0, vitest_1.expect)(re.test('dd if=/dev/zero')).toBe(true);
|
|
29
|
+
(0, vitest_1.expect)(re.test('npm install')).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('treats regex hint chars (^, $, |, etc) as raw regex', () => {
|
|
32
|
+
const re = (0, policy_js_1.compileClaudeBashPattern)('^git (push|pull)');
|
|
33
|
+
(0, vitest_1.expect)(re.test('git push origin main')).toBe(true);
|
|
34
|
+
(0, vitest_1.expect)(re.test('git pull')).toBe(true);
|
|
35
|
+
(0, vitest_1.expect)(re.test('git status')).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.describe)('evaluateClaudeBashRules', () => {
|
|
39
|
+
const baseRules = {
|
|
40
|
+
rules: [
|
|
41
|
+
{ pattern: 'git status', decision: 'ALLOW' },
|
|
42
|
+
{ pattern: 'grep /home/*', decision: 'ALLOW', description: 'Allow grep on home dir' },
|
|
43
|
+
{ pattern: '/^(rm|dd|mkfs)\\b/', decision: 'BLOCK' },
|
|
44
|
+
{ pattern: 'pnpm install *', decision: 'REQUIRE_APPROVAL' },
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
(0, vitest_1.it)('escalates ${IFS}/$VAR injection past an ALLOW glob to approval (shell-meta gate regression)', () => {
|
|
48
|
+
// `${IFS}` expands to whitespace incl. a newline at runtime, so it acts as a
|
|
49
|
+
// command separator. It (and `$IFS`/`$(...)`/backticks) must NOT ride an
|
|
50
|
+
// ALLOW glob — regression for the SHELL_CONTROL_RE `$` gap.
|
|
51
|
+
const rules = {
|
|
52
|
+
rules: [{ pattern: 'git status *', decision: 'ALLOW' }],
|
|
53
|
+
};
|
|
54
|
+
for (const cmd of [
|
|
55
|
+
'git status ${IFS}rm${IFS}-rf${IFS}/',
|
|
56
|
+
'git status $IFS',
|
|
57
|
+
'git status $(rm -rf /)',
|
|
58
|
+
'git status `id`',
|
|
59
|
+
]) {
|
|
60
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)(cmd, rules)?.decision).toBe('REQUIRE_APPROVAL');
|
|
61
|
+
}
|
|
62
|
+
// legit glob tails with no shell metacharacters still auto-ALLOW
|
|
63
|
+
for (const cmd of ['git status --short', 'git status -uno', 'git status /home/foo']) {
|
|
64
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)(cmd, rules)?.decision).toBe('ALLOW');
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
(0, vitest_1.it)('returns null when rules are undefined or absent', () => {
|
|
68
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status', undefined)).toBeNull();
|
|
69
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status', null)).toBeNull();
|
|
70
|
+
});
|
|
71
|
+
(0, vitest_1.it)('returns null when no rule matches and defaultDecision is unset', () => {
|
|
72
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('curl https://example.com', baseRules)).toBeNull();
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.it)('exact-matches an ALLOW rule with no wildcard', () => {
|
|
75
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status', baseRules);
|
|
76
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
77
|
+
(0, vitest_1.expect)(out?.matchedPattern).toBe('git status');
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)('does NOT match an exact-pattern when the command has args', () => {
|
|
80
|
+
// `git status --short` doesn't equal `git status`, so the rule misses.
|
|
81
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status --short', baseRules)).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.it)('matches a glob ALLOW with args', () => {
|
|
84
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('grep /home/foo', baseRules);
|
|
85
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
86
|
+
(0, vitest_1.expect)(out?.matchedPattern).toBe('grep /home/*');
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)('does not match a glob outside the prefix', () => {
|
|
89
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('grep /etc/passwd', baseRules)).toBeNull();
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)('honors regex-style BLOCK rules', () => {
|
|
92
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('rm -rf foo', baseRules)?.decision).toBe('BLOCK');
|
|
93
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('dd if=/dev/zero of=/dev/sda', baseRules)?.decision).toBe('BLOCK');
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.it)('canonicalizes whitespace before matching', () => {
|
|
96
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)(' git status ', baseRules);
|
|
97
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)('falls back to defaultDecision when set and no rule matched', () => {
|
|
100
|
+
const rules = { ...baseRules, defaultDecision: 'REQUIRE_APPROVAL' };
|
|
101
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('curl https://example.com', rules);
|
|
102
|
+
(0, vitest_1.expect)(out?.decision).toBe('REQUIRE_APPROVAL');
|
|
103
|
+
(0, vitest_1.expect)(out?.matchedPattern).toBe('');
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.it)('first match wins (ordering matters)', () => {
|
|
106
|
+
const rules = {
|
|
107
|
+
rules: [
|
|
108
|
+
{ pattern: 'git *', decision: 'ALLOW' },
|
|
109
|
+
{ pattern: 'git push *', decision: 'BLOCK' },
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
// The broad ALLOW rule shadows the specific BLOCK because it comes first.
|
|
113
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git push origin main', rules)?.decision).toBe('ALLOW');
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)('skips invalid regex patterns rather than throwing', () => {
|
|
116
|
+
const rules = {
|
|
117
|
+
rules: [
|
|
118
|
+
{ pattern: '/[broken/', decision: 'ALLOW' }, // unclosed character class
|
|
119
|
+
{ pattern: 'echo *', decision: 'ALLOW' },
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
// Skipped invalid rule, falls through to next which matches.
|
|
123
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('echo hello', rules)?.decision).toBe('ALLOW');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
(0, vitest_1.describe)('evaluateClaudeBashRules — safety gates', () => {
|
|
127
|
+
const rules = {
|
|
128
|
+
rules: [
|
|
129
|
+
{ pattern: 'git status', decision: 'ALLOW' }, // exact, no glob
|
|
130
|
+
{ pattern: 'git status *', decision: 'ALLOW' }, // glob ALLOW with args
|
|
131
|
+
{ pattern: 'rm *', decision: 'ALLOW' },
|
|
132
|
+
{ pattern: '/^cat .* \\| grep .*$/', decision: 'ALLOW' },
|
|
133
|
+
{ pattern: 'git push *', decision: 'BLOCK' },
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
(0, vitest_1.it)('escalates a glob ALLOW to REQUIRE_APPROVAL when the command contains shell metacharacters', () => {
|
|
137
|
+
// `git status ; rm -rf /` matches `git status *` (glob), but the `;`
|
|
138
|
+
// opens up arbitrary commands — escalate.
|
|
139
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status ; rm -rf /', rules);
|
|
140
|
+
(0, vitest_1.expect)(out?.decision).toBe('REQUIRE_APPROVAL');
|
|
141
|
+
(0, vitest_1.expect)(out?.matchedPattern).toBe('git status *');
|
|
142
|
+
(0, vitest_1.expect)(out?.reason).toMatch(/shell metacharacters/);
|
|
143
|
+
});
|
|
144
|
+
(0, vitest_1.it)('escalates ALLOW for output redirection too', () => {
|
|
145
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status > /tmp/leak', rules)?.decision).toBe('REQUIRE_APPROVAL');
|
|
146
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status | tee /tmp/x', rules)?.decision).toBe('REQUIRE_APPROVAL');
|
|
147
|
+
});
|
|
148
|
+
(0, vitest_1.it)('escalates ALLOW when the command uses a single `&` background separator', () => {
|
|
149
|
+
// `cmd1 & cmd2` in bash runs cmd1 in the background and immediately
|
|
150
|
+
// runs cmd2. Without catching bare `&`, `git status & rm -rf /` would
|
|
151
|
+
// sail past `ALLOW: git status *`.
|
|
152
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status & rm -rf /', rules)?.decision).toBe('REQUIRE_APPROVAL');
|
|
153
|
+
// No-space-after-status variant: a glob `git status *` requires the
|
|
154
|
+
// space, so `git status -p &rm -rf /` is what bash would happily run
|
|
155
|
+
// — `git status -p` plus background-then-rm. The rule still matches
|
|
156
|
+
// and the gate must catch the `&`.
|
|
157
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status -p &rm -rf /', rules)?.decision).toBe('REQUIRE_APPROVAL');
|
|
158
|
+
});
|
|
159
|
+
(0, vitest_1.it)('escalates ALLOW when the command embeds a newline (multi-line bypass)', () => {
|
|
160
|
+
// Real shells treat a literal newline as a command terminator. The
|
|
161
|
+
// canonicalize step in the matcher collapses whitespace, so a
|
|
162
|
+
// glob ALLOW would otherwise match `git status\ncurl evil.com` and
|
|
163
|
+
// the second line would slip through. The safety gate runs against
|
|
164
|
+
// the raw command precisely to catch this.
|
|
165
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status\ncurl https://example.com', rules);
|
|
166
|
+
(0, vitest_1.expect)(out?.decision).toBe('REQUIRE_APPROVAL');
|
|
167
|
+
(0, vitest_1.expect)(out?.reason).toMatch(/shell metacharacters/);
|
|
168
|
+
});
|
|
169
|
+
(0, vitest_1.it)('also catches \\r\\n line endings', () => {
|
|
170
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git status\r\nrm -rf /', rules)?.decision).toBe('REQUIRE_APPROVAL');
|
|
171
|
+
});
|
|
172
|
+
(0, vitest_1.it)('escalates a default-ALLOW outcome the same way as a rule-ALLOW (shell metas)', () => {
|
|
173
|
+
// No rule matches `curl evil.com; rm -rf /`, but the policy's
|
|
174
|
+
// defaultDecision is ALLOW. Without gating the default through the
|
|
175
|
+
// safety check, this would auto-approve a compound command — exact
|
|
176
|
+
// same bypass we're trying to prevent for explicit ALLOW rules.
|
|
177
|
+
const r = {
|
|
178
|
+
rules: [],
|
|
179
|
+
defaultDecision: 'ALLOW',
|
|
180
|
+
};
|
|
181
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('curl https://example.com; rm -rf /', r)?.decision).toBe('REQUIRE_APPROVAL');
|
|
182
|
+
});
|
|
183
|
+
(0, vitest_1.it)('honors default-ALLOW for admin-class commands when no rule matches', () => {
|
|
184
|
+
const r = {
|
|
185
|
+
rules: [],
|
|
186
|
+
defaultDecision: 'ALLOW',
|
|
187
|
+
};
|
|
188
|
+
// No rule matches; default ALLOW applies. The admin-class hint is
|
|
189
|
+
// informational only — the editor's linter is the recommendation
|
|
190
|
+
// surface, runtime honours the explicit policy choice.
|
|
191
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('rm -rf /', r, {
|
|
192
|
+
hardcodedActionType: 'admin',
|
|
193
|
+
});
|
|
194
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
195
|
+
});
|
|
196
|
+
(0, vitest_1.it)('still honors default-ALLOW for clean read-only commands', () => {
|
|
197
|
+
const r = {
|
|
198
|
+
rules: [],
|
|
199
|
+
defaultDecision: 'ALLOW',
|
|
200
|
+
};
|
|
201
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('ls -la', r, { hardcodedActionType: 'read' })?.decision).toBe('ALLOW');
|
|
202
|
+
});
|
|
203
|
+
(0, vitest_1.it)('default-BLOCK and default-REQUIRE_APPROVAL are always honored', () => {
|
|
204
|
+
const block = {
|
|
205
|
+
rules: [],
|
|
206
|
+
defaultDecision: 'BLOCK',
|
|
207
|
+
};
|
|
208
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('ls', block)?.decision).toBe('BLOCK');
|
|
209
|
+
const approve = {
|
|
210
|
+
rules: [],
|
|
211
|
+
defaultDecision: 'REQUIRE_APPROVAL',
|
|
212
|
+
};
|
|
213
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('ls', approve)?.decision).toBe('REQUIRE_APPROVAL');
|
|
214
|
+
});
|
|
215
|
+
(0, vitest_1.it)('does not escalate when the matched pattern is a /regex/ — the user opted in', () => {
|
|
216
|
+
// /^cat .* \| grep .*$/ matches `cat foo | grep bar` and the pattern
|
|
217
|
+
// itself is a regex, so the user clearly meant compound matching.
|
|
218
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('cat foo | grep bar', rules);
|
|
219
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
220
|
+
});
|
|
221
|
+
(0, vitest_1.it)('does not escalate exact-match ALLOWs (they cannot match compound commands anyway)', () => {
|
|
222
|
+
// `git status` exact matches only the bare command — no shell metas
|
|
223
|
+
// possible in the matched portion. Stays ALLOW.
|
|
224
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status', rules);
|
|
225
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
226
|
+
(0, vitest_1.expect)(out?.matchedPattern).toBe('git status');
|
|
227
|
+
});
|
|
228
|
+
(0, vitest_1.it)('honors explicit ALLOW for admin-class commands (no auto-escalation)', () => {
|
|
229
|
+
// `rm *` ALLOW rule matches `rm -rf /tmp`. The routing endpoint may
|
|
230
|
+
// pass hardcodedActionType: 'admin', but an explicit ALLOW is the
|
|
231
|
+
// admin's choice — runtime honours it. The editor's linter surfaces
|
|
232
|
+
// a warning at edit time so admins notice high-risk ALLOWs.
|
|
233
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('rm -rf /tmp', rules, {
|
|
234
|
+
hardcodedActionType: 'admin',
|
|
235
|
+
});
|
|
236
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
237
|
+
});
|
|
238
|
+
(0, vitest_1.it)('the admin-opt-in flag is a no-op now (kept for back-compat with stored policies)', () => {
|
|
239
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('rm -rf /tmp', rules, {
|
|
240
|
+
hardcodedActionType: 'admin',
|
|
241
|
+
allowHighRiskAutoApproval: { admin: true },
|
|
242
|
+
});
|
|
243
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
244
|
+
});
|
|
245
|
+
(0, vitest_1.it)('BLOCK rules are NEVER escalated, even with admin classification', () => {
|
|
246
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git push origin main', rules)?.decision).toBe('BLOCK');
|
|
247
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('git push origin main', rules, {
|
|
248
|
+
hardcodedActionType: 'admin',
|
|
249
|
+
})?.decision).toBe('BLOCK');
|
|
250
|
+
});
|
|
251
|
+
(0, vitest_1.it)('REQUIRE_APPROVAL rules are NEVER escalated either', () => {
|
|
252
|
+
const r = {
|
|
253
|
+
rules: [{ pattern: 'pnpm install *', decision: 'REQUIRE_APPROVAL' }],
|
|
254
|
+
};
|
|
255
|
+
// Compound + admin opts shouldn't change a REQUIRE_APPROVAL outcome.
|
|
256
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluateClaudeBashRules)('pnpm install foo ; ls', r)?.decision).toBe('REQUIRE_APPROVAL');
|
|
257
|
+
});
|
|
258
|
+
(0, vitest_1.it)('honors plain ALLOW when no shell metas and not admin', () => {
|
|
259
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status', rules, {
|
|
260
|
+
hardcodedActionType: 'read',
|
|
261
|
+
});
|
|
262
|
+
(0, vitest_1.expect)(out?.decision).toBe('ALLOW');
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
(0, vitest_1.describe)('suggestClaudeBashPattern', () => {
|
|
266
|
+
(0, vitest_1.it)('returns empty for empty input', () => {
|
|
267
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('')).toBe('');
|
|
268
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)(' ')).toBe('');
|
|
269
|
+
});
|
|
270
|
+
(0, vitest_1.it)('exact-matches a single-token command', () => {
|
|
271
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('ls')).toBe('ls');
|
|
272
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('pwd')).toBe('pwd');
|
|
273
|
+
});
|
|
274
|
+
(0, vitest_1.it)('takes the first two tokens for typical subcommand-style commands', () => {
|
|
275
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('git status --short')).toBe('git status *');
|
|
276
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('git push origin main')).toBe('git push *');
|
|
277
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('kubectl apply -f deploy.yaml')).toBe('kubectl apply *');
|
|
278
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('pnpm install --frozen-lockfile')).toBe('pnpm install *');
|
|
279
|
+
});
|
|
280
|
+
(0, vitest_1.it)('drops to single-token when the second token is a flag', () => {
|
|
281
|
+
// `ls -la /home` shouldn't pin admins to `ls -la *` — the more useful
|
|
282
|
+
// suggestion is `ls *`, which they can tighten if they want.
|
|
283
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('ls -la /home')).toBe('ls *');
|
|
284
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('grep --color foo')).toBe('grep *');
|
|
285
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('curl -X POST http://x')).toBe('curl *');
|
|
286
|
+
});
|
|
287
|
+
(0, vitest_1.it)('drops to single-token when the second token is a path operand', () => {
|
|
288
|
+
// `find . -delete` shouldn't suggest `find . *` (so narrow it's only
|
|
289
|
+
// useful for cwd) — fall back to `find *` which is at least usable.
|
|
290
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('find . -delete')).toBe('find *');
|
|
291
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('cat /etc/passwd')).toBe('cat *');
|
|
292
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('ls ~/Downloads')).toBe('ls *');
|
|
293
|
+
// Backslash for Windows paths.
|
|
294
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('dir \\Users\\foo')).toBe('dir *');
|
|
295
|
+
});
|
|
296
|
+
(0, vitest_1.it)('strips quoted segments before tokenising', () => {
|
|
297
|
+
// The naïve tokeniser would split into `[git, commit, -m, "fix:, bug"]`
|
|
298
|
+
// and pick `commit -m` as a flag → `git *`. With quote stripping we
|
|
299
|
+
// get the more useful `git commit *`.
|
|
300
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('git commit -m "fix: bug"')).toBe('git commit *');
|
|
301
|
+
});
|
|
302
|
+
(0, vitest_1.it)('drops to single-token when the second token contains shell metas', () => {
|
|
303
|
+
// After quote-stripping, a piped command leaves the pipe sitting where
|
|
304
|
+
// the subcommand would otherwise be. Don't suggest `echo | *` — bail
|
|
305
|
+
// to `echo *`.
|
|
306
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)("echo 'hello world' | tee out")).toBe('echo *');
|
|
307
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('curl https://x')).toBe('curl *');
|
|
308
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)('cat foo.txt')).toBe('cat *');
|
|
309
|
+
});
|
|
310
|
+
(0, vitest_1.it)('canonicalizes whitespace', () => {
|
|
311
|
+
(0, vitest_1.expect)((0, policy_js_1.suggestClaudeBashPattern)(' git status --short ')).toBe('git status *');
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
(0, vitest_1.describe)('evaluateClaudeBashRules — per-rule overrides', () => {
|
|
315
|
+
(0, vitest_1.it)('propagates require_two_approvals from a matched REQUIRE_APPROVAL rule', () => {
|
|
316
|
+
const r = {
|
|
317
|
+
rules: [
|
|
318
|
+
{
|
|
319
|
+
pattern: 'kubectl apply *',
|
|
320
|
+
decision: 'REQUIRE_APPROVAL',
|
|
321
|
+
require_two_approvals: true,
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
};
|
|
325
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('kubectl apply -f deploy.yaml', r);
|
|
326
|
+
(0, vitest_1.expect)(out?.decision).toBe('REQUIRE_APPROVAL');
|
|
327
|
+
(0, vitest_1.expect)(out?.require_two_approvals).toBe(true);
|
|
328
|
+
});
|
|
329
|
+
(0, vitest_1.it)('propagates allowed_approvers from a matched rule', () => {
|
|
330
|
+
const uuid1 = '11111111-1111-4111-8111-111111111111';
|
|
331
|
+
const uuid2 = '22222222-2222-4222-8222-222222222222';
|
|
332
|
+
const r = {
|
|
333
|
+
rules: [
|
|
334
|
+
{
|
|
335
|
+
pattern: 'git push *',
|
|
336
|
+
decision: 'REQUIRE_APPROVAL',
|
|
337
|
+
allowed_approvers: [uuid1, uuid2],
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
};
|
|
341
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git push origin main', r);
|
|
342
|
+
(0, vitest_1.expect)(out?.allowed_approvers).toEqual([uuid1, uuid2]);
|
|
343
|
+
});
|
|
344
|
+
(0, vitest_1.it)('propagates require_two_approvals=false to explicitly loosen', () => {
|
|
345
|
+
// A matched rule with require_two_approvals: false should override a
|
|
346
|
+
// surrounding rule's true setting — that's the whole point of the
|
|
347
|
+
// per-rule field.
|
|
348
|
+
const r = {
|
|
349
|
+
rules: [
|
|
350
|
+
{
|
|
351
|
+
pattern: 'pnpm test',
|
|
352
|
+
decision: 'REQUIRE_APPROVAL',
|
|
353
|
+
require_two_approvals: false,
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
};
|
|
357
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('pnpm test', r);
|
|
358
|
+
(0, vitest_1.expect)(out?.require_two_approvals).toBe(false);
|
|
359
|
+
});
|
|
360
|
+
(0, vitest_1.it)('omits override fields when rule does not set them', () => {
|
|
361
|
+
const r = {
|
|
362
|
+
rules: [{ pattern: 'git status', decision: 'ALLOW' }],
|
|
363
|
+
};
|
|
364
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status', r);
|
|
365
|
+
(0, vitest_1.expect)(out?.require_two_approvals).toBeUndefined();
|
|
366
|
+
(0, vitest_1.expect)(out?.allowed_approvers).toBeUndefined();
|
|
367
|
+
});
|
|
368
|
+
(0, vitest_1.it)('omits override fields on a synthesised default-match', () => {
|
|
369
|
+
// The synthesised match for `defaultDecision` has no underlying rule,
|
|
370
|
+
// so there's nothing to copy — caller falls back to surrounding rule.
|
|
371
|
+
const r = {
|
|
372
|
+
rules: [],
|
|
373
|
+
defaultDecision: 'REQUIRE_APPROVAL',
|
|
374
|
+
};
|
|
375
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('curl https://x', r);
|
|
376
|
+
(0, vitest_1.expect)(out?.decision).toBe('REQUIRE_APPROVAL');
|
|
377
|
+
(0, vitest_1.expect)(out?.require_two_approvals).toBeUndefined();
|
|
378
|
+
(0, vitest_1.expect)(out?.allowed_approvers).toBeUndefined();
|
|
379
|
+
});
|
|
380
|
+
(0, vitest_1.it)('keeps overrides when an ALLOW rule is escalated by the shell-meta gate', () => {
|
|
381
|
+
// Even when the safety gate flips ALLOW → REQUIRE_APPROVAL (shell
|
|
382
|
+
// metas in the command), the per-rule overrides still apply.
|
|
383
|
+
// Otherwise an admin's "this rule needs 2-person approval" intent
|
|
384
|
+
// would be silently dropped on escalation.
|
|
385
|
+
const r = {
|
|
386
|
+
rules: [
|
|
387
|
+
{
|
|
388
|
+
pattern: 'git *',
|
|
389
|
+
decision: 'ALLOW',
|
|
390
|
+
require_two_approvals: true,
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
};
|
|
394
|
+
// Canonical form `git status; rm -rf /` matches `git .*`. Raw form
|
|
395
|
+
// contains `;` → safety gate flips to REQUIRE_APPROVAL.
|
|
396
|
+
const out = (0, policy_js_1.evaluateClaudeBashRules)('git status; rm -rf /', r);
|
|
397
|
+
(0, vitest_1.expect)(out?.decision).toBe('REQUIRE_APPROVAL');
|
|
398
|
+
(0, vitest_1.expect)(out?.require_two_approvals).toBe(true);
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
//# sourceMappingURL=policy-claude-bash.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-claude-bash.test.js","sourceRoot":"","sources":["../../src/__tests__/policy-claude-bash.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-llm-floor.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy-llm-floor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const policy_js_1 = require("../policy.js");
|
|
5
|
+
const baseAction = (overrides = {}) => ({
|
|
6
|
+
action_type: 'read',
|
|
7
|
+
tool: 'unknown.tool',
|
|
8
|
+
payload: {},
|
|
9
|
+
...overrides,
|
|
10
|
+
});
|
|
11
|
+
(0, vitest_1.describe)('evaluatePolicy — llmFloor option', () => {
|
|
12
|
+
(0, vitest_1.it)('ignores llmFloor when not provided (existing behavior preserved)', () => {
|
|
13
|
+
// mcp.list_tools has a static floor of `read`, so with no llmFloor the
|
|
14
|
+
// effective type stays `read`. (Unrecognised tools now floor to `write`.)
|
|
15
|
+
const action = baseAction({ tool: 'mcp.list_tools' });
|
|
16
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES);
|
|
17
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('read');
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.it)('upgrades effective_action_type when llmFloor is higher than declared + static', () => {
|
|
20
|
+
// `mcp.list_tools` has static floor = read.
|
|
21
|
+
// Agent declares read. LLM says write → effective should be write.
|
|
22
|
+
const action = baseAction({ action_type: 'read', tool: 'mcp.list_tools' });
|
|
23
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
|
|
24
|
+
llmFloor: 'write',
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('write');
|
|
27
|
+
(0, vitest_1.expect)(result.decision).toBe('REQUIRE_APPROVAL');
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.it)('does NOT downgrade when llmFloor is lower than staticFloor', () => {
|
|
30
|
+
// `stripe.charge` has static floor = financial.
|
|
31
|
+
// LLM says read → effective should still be financial (never downgrade).
|
|
32
|
+
const action = baseAction({
|
|
33
|
+
action_type: 'read',
|
|
34
|
+
tool: 'stripe.charge',
|
|
35
|
+
payload: {},
|
|
36
|
+
});
|
|
37
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
|
|
38
|
+
llmFloor: 'read',
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('financial');
|
|
41
|
+
});
|
|
42
|
+
(0, vitest_1.it)('does NOT downgrade when llmFloor is lower than declared', () => {
|
|
43
|
+
// Agent declares admin, LLM says read → effective should still be admin.
|
|
44
|
+
// DEFAULT_POLICY_RULES maps action_type: 'admin' → BLOCK (see policy.test.ts:420).
|
|
45
|
+
const action = baseAction({ action_type: 'admin', tool: 'unknown.tool' });
|
|
46
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
|
|
47
|
+
llmFloor: 'read',
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('admin');
|
|
50
|
+
(0, vitest_1.expect)(result.decision).toBe('BLOCK');
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.it)('takes max of static and llm when both are higher than declared', () => {
|
|
53
|
+
// stripe.charge → static floor = financial
|
|
54
|
+
// llmFloor = admin
|
|
55
|
+
// max = admin
|
|
56
|
+
const action = baseAction({
|
|
57
|
+
action_type: 'read',
|
|
58
|
+
tool: 'stripe.charge',
|
|
59
|
+
payload: {},
|
|
60
|
+
});
|
|
61
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
|
|
62
|
+
llmFloor: 'admin',
|
|
63
|
+
});
|
|
64
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('admin');
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.it)('skipCategoryFloor overrides both static and llm floors', () => {
|
|
67
|
+
const action = baseAction({
|
|
68
|
+
action_type: 'read',
|
|
69
|
+
tool: 'stripe.charge',
|
|
70
|
+
payload: {},
|
|
71
|
+
});
|
|
72
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
|
|
73
|
+
skipCategoryFloor: true,
|
|
74
|
+
llmFloor: 'admin',
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('read');
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('llmFloor promotes declared read on unknown tool to financial → REQUIRE_APPROVAL', () => {
|
|
79
|
+
// This is the key scenario: unknown tool (static = read), agent said read,
|
|
80
|
+
// LLM identified it as financial. Without LLM, this would auto-allow.
|
|
81
|
+
// With LLM, it gets flagged for approval.
|
|
82
|
+
const action = baseAction({
|
|
83
|
+
action_type: 'read',
|
|
84
|
+
tool: 'custom.transfer_funds',
|
|
85
|
+
payload: {},
|
|
86
|
+
});
|
|
87
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, {
|
|
88
|
+
llmFloor: 'financial',
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('financial');
|
|
91
|
+
(0, vitest_1.expect)(result.decision).toBe('REQUIRE_APPROVAL');
|
|
92
|
+
(0, vitest_1.expect)(result.reason).toContain('category floored');
|
|
93
|
+
});
|
|
94
|
+
(0, vitest_1.it)('llmFloor-only upgrade surfaces the category-floored reason suffix', () => {
|
|
95
|
+
// `mcp.list_tools` has static floor = read. Agent declares read. LLM says
|
|
96
|
+
// write. The upgrade is driven ONLY by llmFloor — the static floor
|
|
97
|
+
// contributes nothing. This test locks in that the reason suffix
|
|
98
|
+
// ("category floored") fires for llmFloor-only upgrades too, not just for
|
|
99
|
+
// static-floor upgrades. Guards against silent regression of test 7 if the
|
|
100
|
+
// static FINANCIAL_PATTERNS list ever changes.
|
|
101
|
+
const action = baseAction({ action_type: 'read', tool: 'mcp.list_tools' });
|
|
102
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES, { llmFloor: 'write' });
|
|
103
|
+
(0, vitest_1.expect)(result.effective_action_type).toBe('write');
|
|
104
|
+
(0, vitest_1.expect)(result.reason).toContain('category floored');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=policy-llm-floor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-llm-floor.test.js","sourceRoot":"","sources":["../../src/__tests__/policy-llm-floor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-ssh-e2e.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy-ssh-e2e.test.ts"],"names":[],"mappings":""}
|