@komarspn/pi-permission-system 16.0.2
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/CHANGELOG.md +2234 -0
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/config/config.example.json +39 -0
- package/package.json +82 -0
- package/schemas/permissions.schema.json +158 -0
- package/src/active-agent.ts +72 -0
- package/src/async-cache.ts +21 -0
- package/src/bash-arity.ts +210 -0
- package/src/builtin-tool-input-formatters.ts +82 -0
- package/src/canonicalize-path.ts +30 -0
- package/src/common.ts +121 -0
- package/src/config-loader.ts +432 -0
- package/src/config-modal.ts +259 -0
- package/src/config-paths.ts +47 -0
- package/src/config-reporter.ts +34 -0
- package/src/config-store.ts +222 -0
- package/src/decision-audit.ts +75 -0
- package/src/decision-reporter.ts +41 -0
- package/src/denial-messages.ts +232 -0
- package/src/expand-home.ts +28 -0
- package/src/extension-config.ts +79 -0
- package/src/extension-paths.ts +66 -0
- package/src/forwarded-permissions/io.ts +404 -0
- package/src/forwarded-permissions/permission-forwarder.ts +580 -0
- package/src/forwarding-manager.ts +74 -0
- package/src/gate-prompter.ts +12 -0
- package/src/handlers/before-agent-start.ts +94 -0
- package/src/handlers/gates/bash-command.ts +75 -0
- package/src/handlers/gates/bash-external-directory.ts +127 -0
- package/src/handlers/gates/bash-path-extractor.ts +15 -0
- package/src/handlers/gates/bash-path.ts +152 -0
- package/src/handlers/gates/bash-program.ts +1143 -0
- package/src/handlers/gates/bash-token-classification.ts +105 -0
- package/src/handlers/gates/candidate-check.ts +32 -0
- package/src/handlers/gates/descriptor.ts +81 -0
- package/src/handlers/gates/external-directory-messages.ts +20 -0
- package/src/handlers/gates/external-directory.ts +133 -0
- package/src/handlers/gates/helpers.ts +76 -0
- package/src/handlers/gates/path.ts +91 -0
- package/src/handlers/gates/runner.ts +186 -0
- package/src/handlers/gates/skill-input-gate-pipeline.ts +104 -0
- package/src/handlers/gates/skill-input.ts +46 -0
- package/src/handlers/gates/skill-read.ts +87 -0
- package/src/handlers/gates/tool-call-gate-pipeline.ts +129 -0
- package/src/handlers/gates/tool.ts +102 -0
- package/src/handlers/gates/types.ts +13 -0
- package/src/handlers/index.ts +3 -0
- package/src/handlers/lifecycle.ts +95 -0
- package/src/handlers/permission-gate-handler.ts +190 -0
- package/src/handlers/tool-call-boundary.ts +91 -0
- package/src/index.ts +225 -0
- package/src/input-normalizer.ts +157 -0
- package/src/logging.ts +113 -0
- package/src/mcp-targets.ts +170 -0
- package/src/node-modules-discovery.ts +76 -0
- package/src/normalize.ts +43 -0
- package/src/path-utils.ts +355 -0
- package/src/pattern-suggest.ts +132 -0
- package/src/permission-dialog.ts +138 -0
- package/src/permission-event-rpc.ts +223 -0
- package/src/permission-events.ts +266 -0
- package/src/permission-forwarding.ts +188 -0
- package/src/permission-gate.ts +94 -0
- package/src/permission-manager.ts +392 -0
- package/src/permission-merge.ts +32 -0
- package/src/permission-prompter.ts +142 -0
- package/src/permission-prompts.ts +93 -0
- package/src/permission-resolver.ts +109 -0
- package/src/permission-session.ts +189 -0
- package/src/permission-ui-prompt.ts +127 -0
- package/src/permissions-service.ts +63 -0
- package/src/persistent-approval-recorder.ts +139 -0
- package/src/policy-loader.ts +350 -0
- package/src/prompting-gateway.ts +104 -0
- package/src/rule.ts +188 -0
- package/src/scope-merge.ts +72 -0
- package/src/service-lifecycle.ts +49 -0
- package/src/service.ts +163 -0
- package/src/session-approval-recorder.ts +6 -0
- package/src/session-approval.ts +43 -0
- package/src/session-logger.ts +91 -0
- package/src/session-rules.ts +79 -0
- package/src/skill-prompt-sanitizer.ts +292 -0
- package/src/status.ts +35 -0
- package/src/subagent-context.ts +104 -0
- package/src/subagent-lifecycle-events.ts +72 -0
- package/src/subagent-registry.ts +105 -0
- package/src/synthesize.ts +92 -0
- package/src/system-prompt-sanitizer.ts +274 -0
- package/src/tool-access-extractor-registry.ts +68 -0
- package/src/tool-input-formatter-registry.ts +67 -0
- package/src/tool-input-preview.ts +34 -0
- package/src/tool-input-prompt-formatters.ts +63 -0
- package/src/tool-preview-formatter.ts +207 -0
- package/src/tool-registry.ts +148 -0
- package/src/types.ts +64 -0
- package/src/wildcard-matcher.ts +120 -0
- package/src/yolo-mode.ts +30 -0
- package/test/active-agent.test.ts +155 -0
- package/test/async-cache.test.ts +48 -0
- package/test/bash-arity.test.ts +144 -0
- package/test/bash-external-directory.test.ts +956 -0
- package/test/builtin-tool-input-formatters.test.ts +109 -0
- package/test/canonicalize-path.test.ts +93 -0
- package/test/common.test.ts +287 -0
- package/test/composition-root.test.ts +603 -0
- package/test/config-loader.test.ts +740 -0
- package/test/config-modal.test.ts +320 -0
- package/test/config-paths.test.ts +83 -0
- package/test/config-pipeline.test.ts +90 -0
- package/test/config-reporter.test.ts +147 -0
- package/test/config-store.test.ts +466 -0
- package/test/decision-audit.test.ts +72 -0
- package/test/decision-reporter.test.ts +112 -0
- package/test/denial-messages.test.ts +656 -0
- package/test/detect-permissive-bash-fallback.test.ts +56 -0
- package/test/expand-home.test.ts +93 -0
- package/test/extension-config.test.ts +129 -0
- package/test/extension-paths.test.ts +108 -0
- package/test/forwarded-permissions/io.test.ts +251 -0
- package/test/forwarding-manager.test.ts +194 -0
- package/test/handlers/before-agent-start.test.ts +317 -0
- package/test/handlers/external-directory-integration.test.ts +623 -0
- package/test/handlers/external-directory-session-dedup.test.ts +430 -0
- package/test/handlers/external-directory-symlink-acceptance.test.ts +149 -0
- package/test/handlers/gates/bash-command-metamorphic.test.ts +83 -0
- package/test/handlers/gates/bash-command.test.ts +191 -0
- package/test/handlers/gates/bash-external-directory.test.ts +269 -0
- package/test/handlers/gates/bash-path.test.ts +337 -0
- package/test/handlers/gates/bash-program.test.ts +410 -0
- package/test/handlers/gates/bash-token-classification.test.ts +241 -0
- package/test/handlers/gates/candidate-check.test.ts +52 -0
- package/test/handlers/gates/external-directory-messages.test.ts +61 -0
- package/test/handlers/gates/external-directory.test.ts +259 -0
- package/test/handlers/gates/helpers.test.ts +177 -0
- package/test/handlers/gates/path.test.ts +294 -0
- package/test/handlers/gates/runner.test.ts +447 -0
- package/test/handlers/gates/skill-input-gate-pipeline.test.ts +176 -0
- package/test/handlers/gates/skill-input.test.ts +131 -0
- package/test/handlers/gates/skill-read.test.ts +158 -0
- package/test/handlers/gates/tool-call-gate-pipeline.test.ts +252 -0
- package/test/handlers/gates/tool.test.ts +223 -0
- package/test/handlers/input-events.test.ts +168 -0
- package/test/handlers/input.test.ts +199 -0
- package/test/handlers/lifecycle.test.ts +221 -0
- package/test/handlers/tool-call-boundary.test.ts +145 -0
- package/test/handlers/tool-call-events.test.ts +277 -0
- package/test/handlers/tool-call.test.ts +395 -0
- package/test/handlers/validate-requested-tool.test.ts +92 -0
- package/test/helpers/gate-fixtures.ts +323 -0
- package/test/helpers/handler-fixtures.ts +335 -0
- package/test/helpers/make-fake-pi.ts +100 -0
- package/test/helpers/manager-harness.ts +112 -0
- package/test/helpers/session-fixtures.ts +204 -0
- package/test/input-normalizer.test.ts +367 -0
- package/test/logging.test.ts +51 -0
- package/test/mcp-targets.test.ts +233 -0
- package/test/node-modules-discovery.test.ts +97 -0
- package/test/normalize.test.ts +247 -0
- package/test/path-utils.test.ts +650 -0
- package/test/pattern-suggest.test.ts +248 -0
- package/test/permission-dialog.test.ts +241 -0
- package/test/permission-event-rpc.test.ts +541 -0
- package/test/permission-events.test.ts +402 -0
- package/test/permission-forwarder.test.ts +369 -0
- package/test/permission-forwarding.test.ts +315 -0
- package/test/permission-gate.test.ts +305 -0
- package/test/permission-manager-unified.test.ts +3368 -0
- package/test/permission-merge.test.ts +61 -0
- package/test/permission-prompter.test.ts +518 -0
- package/test/permission-prompts.test.ts +363 -0
- package/test/permission-resolver.test.ts +265 -0
- package/test/permission-session.test.ts +363 -0
- package/test/permission-ui-prompt.test.ts +146 -0
- package/test/permissions-service.test.ts +177 -0
- package/test/persistent-approval-recorder.test.ts +133 -0
- package/test/pi-infrastructure-read.test.ts +369 -0
- package/test/policy-loader.test.ts +561 -0
- package/test/prompting-gateway.test.ts +230 -0
- package/test/rule.test.ts +604 -0
- package/test/scope-merge.test.ts +116 -0
- package/test/service-lifecycle.test.ts +163 -0
- package/test/service.test.ts +308 -0
- package/test/session-approval.test.ts +75 -0
- package/test/session-logger.test.ts +200 -0
- package/test/session-rules.test.ts +304 -0
- package/test/session-start.test.ts +112 -0
- package/test/skill-prompt-sanitizer.test.ts +374 -0
- package/test/status.test.ts +10 -0
- package/test/subagent-context.test.ts +326 -0
- package/test/subagent-lifecycle-events.test.ts +132 -0
- package/test/subagent-registry.test.ts +145 -0
- package/test/synthesize.test.ts +300 -0
- package/test/system-prompt-sanitizer.test.ts +382 -0
- package/test/tool-access-extractor-registry.test.ts +77 -0
- package/test/tool-input-formatter-registry.test.ts +75 -0
- package/test/tool-input-preview.test.ts +129 -0
- package/test/tool-input-prompt-formatters.test.ts +115 -0
- package/test/tool-preview-formatter.test.ts +458 -0
- package/test/tool-registry.test.ts +197 -0
- package/test/wildcard-matcher.test.ts +424 -0
- package/test/yolo-mode.test.ts +188 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import type { GateDescriptor } from "#src/handlers/gates/descriptor";
|
|
4
|
+
import { isGateDescriptor } from "#src/handlers/gates/descriptor";
|
|
5
|
+
import { describePathGate } from "#src/handlers/gates/path";
|
|
6
|
+
import type { ToolCallContext } from "#src/handlers/gates/types";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
makeGateCheckResult as makeCheckResult,
|
|
10
|
+
makeResolver,
|
|
11
|
+
} from "#test/helpers/gate-fixtures";
|
|
12
|
+
|
|
13
|
+
// ── helpers ────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
// path.test.ts uses read-tool defaults; the shared makeTcc uses bash defaults.
|
|
16
|
+
function makeTcc(overrides: Partial<ToolCallContext> = {}): ToolCallContext {
|
|
17
|
+
return {
|
|
18
|
+
toolName: "read",
|
|
19
|
+
agentName: null,
|
|
20
|
+
input: { path: ".env" },
|
|
21
|
+
toolCallId: "tc-1",
|
|
22
|
+
cwd: "/test/project",
|
|
23
|
+
...overrides,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ── tests ──────────────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
describe("describePathGate", () => {
|
|
30
|
+
it("returns null for non-path-bearing tools", () => {
|
|
31
|
+
const resolver = makeResolver();
|
|
32
|
+
const result = describePathGate(
|
|
33
|
+
makeTcc({ toolName: "bash", input: { command: "ls" } }),
|
|
34
|
+
resolver,
|
|
35
|
+
);
|
|
36
|
+
expect(result).toBeNull();
|
|
37
|
+
expect(resolver.resolve).not.toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("returns null when tool has no extractable path", () => {
|
|
41
|
+
const resolver = makeResolver();
|
|
42
|
+
const result = describePathGate(
|
|
43
|
+
makeTcc({ toolName: "read", input: {} }),
|
|
44
|
+
resolver,
|
|
45
|
+
);
|
|
46
|
+
expect(result).toBeNull();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("returns null when path check result is allow", () => {
|
|
50
|
+
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
51
|
+
const result = describePathGate(makeTcc(), resolver);
|
|
52
|
+
expect(result).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns null when matchedPattern is undefined (universal default)", () => {
|
|
56
|
+
const resolver = makeResolver(
|
|
57
|
+
makeCheckResult({
|
|
58
|
+
state: "ask",
|
|
59
|
+
matchedPattern: undefined,
|
|
60
|
+
source: "special",
|
|
61
|
+
origin: "builtin",
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
const result = describePathGate(makeTcc(), resolver);
|
|
65
|
+
expect(result).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("returns GateDescriptor when matchedPattern is defined (explicit path rule)", () => {
|
|
69
|
+
const resolver = makeResolver(
|
|
70
|
+
makeCheckResult({
|
|
71
|
+
state: "ask",
|
|
72
|
+
matchedPattern: "*.env",
|
|
73
|
+
source: "special",
|
|
74
|
+
origin: "global",
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
const result = describePathGate(makeTcc(), resolver);
|
|
78
|
+
expect(result).not.toBeNull();
|
|
79
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("returns GateDescriptor when path check result is deny", () => {
|
|
83
|
+
const resolver = makeResolver(
|
|
84
|
+
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
85
|
+
);
|
|
86
|
+
const result = describePathGate(makeTcc(), resolver);
|
|
87
|
+
expect(result).not.toBeNull();
|
|
88
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
89
|
+
const desc = result as GateDescriptor;
|
|
90
|
+
expect(desc.surface).toBe("path");
|
|
91
|
+
expect(desc.preCheck?.state).toBe("deny");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("returns GateDescriptor when path check result is ask", () => {
|
|
95
|
+
const resolver = makeResolver(
|
|
96
|
+
makeCheckResult({ state: "ask", matchedPattern: "*.env" }),
|
|
97
|
+
);
|
|
98
|
+
const result = describePathGate(makeTcc(), resolver);
|
|
99
|
+
expect(result).not.toBeNull();
|
|
100
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
101
|
+
const desc = result as GateDescriptor;
|
|
102
|
+
expect(desc.surface).toBe("path");
|
|
103
|
+
expect(desc.preCheck?.state).toBe("ask");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("descriptor has correct session approval surface and pattern", () => {
|
|
107
|
+
const resolver = makeResolver(
|
|
108
|
+
makeCheckResult({ state: "ask", matchedPattern: "*" }),
|
|
109
|
+
);
|
|
110
|
+
const result = describePathGate(
|
|
111
|
+
makeTcc({ input: { path: "/test/project/src/.env" } }),
|
|
112
|
+
resolver,
|
|
113
|
+
) as GateDescriptor;
|
|
114
|
+
expect(result.sessionApproval).toBeDefined();
|
|
115
|
+
expect(result.sessionApproval?.surface).toBe("path");
|
|
116
|
+
expect(result.sessionApproval?.representativePattern).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("binds a current-directory file's session approval to the cwd subtree", () => {
|
|
120
|
+
const resolver = makeResolver(
|
|
121
|
+
makeCheckResult({ state: "ask", matchedPattern: "*" }),
|
|
122
|
+
);
|
|
123
|
+
const result = describePathGate(
|
|
124
|
+
makeTcc({ input: { path: "index.html" }, cwd: "/test/project" }),
|
|
125
|
+
resolver,
|
|
126
|
+
) as GateDescriptor;
|
|
127
|
+
expect(result.sessionApproval?.surface).toBe("path");
|
|
128
|
+
expect(result.sessionApproval?.representativePattern).toBe(
|
|
129
|
+
"/test/project/*",
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("descriptor denialContext references the file path and tool name", () => {
|
|
134
|
+
const resolver = makeResolver(
|
|
135
|
+
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
136
|
+
);
|
|
137
|
+
const result = describePathGate(makeTcc(), resolver) as GateDescriptor;
|
|
138
|
+
expect(result.denialContext).toEqual({
|
|
139
|
+
kind: "path",
|
|
140
|
+
toolName: "read",
|
|
141
|
+
pathValue: ".env",
|
|
142
|
+
agentName: undefined,
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("descriptor decision uses surface 'path' and the file path as value", () => {
|
|
147
|
+
const resolver = makeResolver(
|
|
148
|
+
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
149
|
+
);
|
|
150
|
+
const result = describePathGate(makeTcc(), resolver) as GateDescriptor;
|
|
151
|
+
expect(result.decision.surface).toBe("path");
|
|
152
|
+
expect(result.decision.value).toBe(".env");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("resolves the path surface with the file path and agent name", () => {
|
|
156
|
+
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
157
|
+
describePathGate(makeTcc({ agentName: "my-agent" }), resolver);
|
|
158
|
+
expect(resolver.resolve).toHaveBeenCalledWith(
|
|
159
|
+
"path",
|
|
160
|
+
{ path: ".env" },
|
|
161
|
+
"my-agent",
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Home-relative path characterization (#350) ──────────────────────────────
|
|
167
|
+
//
|
|
168
|
+
// The gate passes the raw path to the resolver; home expansion is handled
|
|
169
|
+
// downstream by normalizeInput. These tests lock in that the gate works
|
|
170
|
+
// correctly when the tool input contains a ~/... or $HOME/... path.
|
|
171
|
+
|
|
172
|
+
describe("describePathGate — home-relative paths", () => {
|
|
173
|
+
it("passes raw ~/... path to resolver and builds descriptor on deny", () => {
|
|
174
|
+
const resolver = makeResolver(
|
|
175
|
+
makeCheckResult({ state: "deny", matchedPattern: "~/.ssh/*" }),
|
|
176
|
+
);
|
|
177
|
+
const result = describePathGate(
|
|
178
|
+
makeTcc({ input: { path: "~/.ssh/config" } }),
|
|
179
|
+
resolver,
|
|
180
|
+
) as GateDescriptor;
|
|
181
|
+
|
|
182
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
183
|
+
expect(result.preCheck?.state).toBe("deny");
|
|
184
|
+
// Raw path preserved in denial context for display.
|
|
185
|
+
expect(result.denialContext).toMatchObject({
|
|
186
|
+
kind: "path",
|
|
187
|
+
toolName: "read",
|
|
188
|
+
pathValue: "~/.ssh/config",
|
|
189
|
+
});
|
|
190
|
+
expect(resolver.resolve).toHaveBeenCalledWith(
|
|
191
|
+
"path",
|
|
192
|
+
{ path: "~/.ssh/config" },
|
|
193
|
+
undefined,
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("passes raw $HOME/... path to resolver and builds descriptor on deny", () => {
|
|
198
|
+
const resolver = makeResolver(
|
|
199
|
+
makeCheckResult({ state: "deny", matchedPattern: "$HOME/.ssh/*" }),
|
|
200
|
+
);
|
|
201
|
+
const result = describePathGate(
|
|
202
|
+
makeTcc({ input: { path: "$HOME/.ssh/config" } }),
|
|
203
|
+
resolver,
|
|
204
|
+
) as GateDescriptor;
|
|
205
|
+
|
|
206
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
207
|
+
expect(result.preCheck?.state).toBe("deny");
|
|
208
|
+
expect(result.denialContext).toMatchObject({
|
|
209
|
+
kind: "path",
|
|
210
|
+
pathValue: "$HOME/.ssh/config",
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("returns null when home-relative path resolves to allow", () => {
|
|
215
|
+
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
216
|
+
const result = describePathGate(
|
|
217
|
+
makeTcc({ input: { path: "~/.ssh/config" } }),
|
|
218
|
+
resolver,
|
|
219
|
+
);
|
|
220
|
+
expect(result).toBeNull();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Extension and MCP tools are now path-gated (#352) ──────────────────────────
|
|
225
|
+
|
|
226
|
+
describe("describePathGate — extension and MCP tools (#352)", () => {
|
|
227
|
+
function extractorLookup(toolName: string, key: string) {
|
|
228
|
+
return {
|
|
229
|
+
get: (name: string) =>
|
|
230
|
+
name === toolName
|
|
231
|
+
? (input: Record<string, unknown>) =>
|
|
232
|
+
typeof input[key] === "string" ? input[key] : undefined
|
|
233
|
+
: undefined,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
it("gates an extension tool that exposes input.path", () => {
|
|
238
|
+
const resolver = makeResolver(
|
|
239
|
+
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
240
|
+
);
|
|
241
|
+
const result = describePathGate(
|
|
242
|
+
makeTcc({ toolName: "my-ext", input: { path: ".env" } }),
|
|
243
|
+
resolver,
|
|
244
|
+
);
|
|
245
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
246
|
+
expect(resolver.resolve).toHaveBeenCalledWith(
|
|
247
|
+
"path",
|
|
248
|
+
{ path: ".env" },
|
|
249
|
+
undefined,
|
|
250
|
+
);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("gates an MCP tool via arguments.path", () => {
|
|
254
|
+
const resolver = makeResolver(
|
|
255
|
+
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
256
|
+
);
|
|
257
|
+
const result = describePathGate(
|
|
258
|
+
makeTcc({ toolName: "mcp", input: { arguments: { path: ".env" } } }),
|
|
259
|
+
resolver,
|
|
260
|
+
);
|
|
261
|
+
expect(isGateDescriptor(result)).toBe(true);
|
|
262
|
+
expect(resolver.resolve).toHaveBeenCalledWith(
|
|
263
|
+
"path",
|
|
264
|
+
{ path: ".env" },
|
|
265
|
+
undefined,
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("uses a registered extractor's path for a custom-shaped tool", () => {
|
|
270
|
+
const resolver = makeResolver(
|
|
271
|
+
makeCheckResult({ state: "deny", matchedPattern: "*" }),
|
|
272
|
+
);
|
|
273
|
+
describePathGate(
|
|
274
|
+
makeTcc({ toolName: "ffgrep", input: { target: "/etc/passwd" } }),
|
|
275
|
+
resolver,
|
|
276
|
+
extractorLookup("ffgrep", "target"),
|
|
277
|
+
);
|
|
278
|
+
expect(resolver.resolve).toHaveBeenCalledWith(
|
|
279
|
+
"path",
|
|
280
|
+
{ path: "/etc/passwd" },
|
|
281
|
+
undefined,
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("returns null for an extension tool without a path", () => {
|
|
286
|
+
const resolver = makeResolver();
|
|
287
|
+
const result = describePathGate(
|
|
288
|
+
makeTcc({ toolName: "my-ext", input: { other: true } }),
|
|
289
|
+
resolver,
|
|
290
|
+
);
|
|
291
|
+
expect(result).toBeNull();
|
|
292
|
+
expect(resolver.resolve).not.toHaveBeenCalled();
|
|
293
|
+
});
|
|
294
|
+
});
|