@gotgenes/pi-permission-system 18.1.0 → 18.1.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 +23 -0
- package/docs/assets/logo.png +0 -0
- package/docs/assets/logo.svg +213 -0
- package/docs/configuration.md +700 -0
- package/docs/cross-extension-api.md +525 -0
- package/docs/guides/permission-frontmatter-for-subagent-extensions.md +201 -0
- package/docs/guides/upstream-issue-template.md +113 -0
- package/docs/migration/legacy-to-flat.md +365 -0
- package/docs/opencode-compatibility.md +213 -0
- package/docs/session-approvals.md +68 -0
- package/docs/subagent-integration.md +102 -0
- package/docs/troubleshooting.md +53 -0
- package/package.json +5 -2
- package/src/access-intent/access-path.ts +29 -4
- package/src/access-intent/bash/bash-path-resolver.ts +39 -18
- package/src/access-intent/bash/msys-bash-tokens.ts +64 -0
- package/src/path-normalizer.ts +105 -2
- package/test/access-intent/access-path.test.ts +0 -277
- package/test/access-intent/bash/node-text.test.ts +0 -148
- package/test/access-intent/bash/parser.test.ts +0 -19
- package/test/access-intent/bash/program.test.ts +0 -673
- package/test/access-intent/bash/token-classification.test.ts +0 -363
- package/test/access-intent/bash/token-collection.test.ts +0 -300
- package/test/active-agent.test.ts +0 -155
- package/test/async-cache.test.ts +0 -48
- package/test/bash-arity.test.ts +0 -144
- package/test/bash-external-directory.test.ts +0 -1022
- package/test/builtin-tool-input-formatters.test.ts +0 -109
- package/test/canonicalize-path.test.ts +0 -119
- package/test/composition-root.test.ts +0 -698
- package/test/config-loader.test.ts +0 -740
- package/test/config-modal.test.ts +0 -320
- package/test/config-paths.test.ts +0 -83
- package/test/config-pipeline.test.ts +0 -90
- package/test/config-reporter.test.ts +0 -147
- package/test/config-store.test.ts +0 -466
- package/test/decision-audit.test.ts +0 -72
- package/test/decision-reporter.test.ts +0 -112
- package/test/denial-messages.test.ts +0 -714
- package/test/detect-permissive-bash-fallback.test.ts +0 -56
- package/test/expand-home.test.ts +0 -93
- package/test/extension-config.test.ts +0 -129
- package/test/extension-paths.test.ts +0 -108
- package/test/forwarded-permissions/io.test.ts +0 -251
- package/test/forwarding-manager.test.ts +0 -200
- package/test/handlers/before-agent-start.test.ts +0 -314
- package/test/handlers/external-directory-integration.test.ts +0 -515
- package/test/handlers/external-directory-session-dedup.test.ts +0 -175
- package/test/handlers/external-directory-symlink-acceptance.test.ts +0 -167
- package/test/handlers/gates/bash-command-metamorphic.test.ts +0 -88
- package/test/handlers/gates/bash-command.test.ts +0 -257
- package/test/handlers/gates/bash-external-directory.test.ts +0 -268
- package/test/handlers/gates/bash-path.test.ts +0 -346
- package/test/handlers/gates/candidate-check.test.ts +0 -52
- package/test/handlers/gates/external-directory-messages.test.ts +0 -85
- package/test/handlers/gates/external-directory-policy.test.ts +0 -134
- package/test/handlers/gates/external-directory.test.ts +0 -267
- package/test/handlers/gates/helpers.test.ts +0 -165
- package/test/handlers/gates/path.test.ts +0 -369
- package/test/handlers/gates/runner.test.ts +0 -408
- package/test/handlers/gates/skill-input-gate-pipeline.test.ts +0 -176
- package/test/handlers/gates/skill-input.test.ts +0 -128
- package/test/handlers/gates/skill-read.test.ts +0 -161
- package/test/handlers/gates/tool-call-gate-pipeline.test.ts +0 -356
- package/test/handlers/gates/tool.test.ts +0 -244
- package/test/handlers/input-events.test.ts +0 -168
- package/test/handlers/input.test.ts +0 -199
- package/test/handlers/lifecycle.test.ts +0 -221
- package/test/handlers/tool-call-boundary.test.ts +0 -145
- package/test/handlers/tool-call-events.test.ts +0 -277
- package/test/handlers/tool-call.test.ts +0 -395
- package/test/handlers/validate-requested-tool.test.ts +0 -92
- package/test/helpers/external-directory-fixtures.ts +0 -269
- package/test/helpers/gate-fixtures.ts +0 -316
- package/test/helpers/handler-fixtures.ts +0 -335
- package/test/helpers/make-fake-pi.ts +0 -100
- package/test/helpers/manager-harness.ts +0 -112
- package/test/helpers/session-fixtures.ts +0 -199
- package/test/input-normalizer.test.ts +0 -325
- package/test/logging.test.ts +0 -51
- package/test/mcp-targets.test.ts +0 -233
- package/test/node-modules-discovery.test.ts +0 -97
- package/test/normalize.test.ts +0 -247
- package/test/path-containment.test.ts +0 -161
- package/test/path-normalization.test.ts +0 -233
- package/test/path-normalizer.test.ts +0 -196
- package/test/path-surfaces.test.ts +0 -55
- package/test/pattern-suggest.test.ts +0 -248
- package/test/permission-dialog.test.ts +0 -205
- package/test/permission-event-rpc.test.ts +0 -560
- package/test/permission-events.test.ts +0 -400
- package/test/permission-forwarder.test.ts +0 -370
- package/test/permission-forwarding.test.ts +0 -315
- package/test/permission-gate.test.ts +0 -269
- package/test/permission-manager-unified.test.ts +0 -3714
- package/test/permission-merge.test.ts +0 -61
- package/test/permission-prompter.test.ts +0 -518
- package/test/permission-prompts.test.ts +0 -363
- package/test/permission-resolver.test.ts +0 -277
- package/test/permission-session.test.ts +0 -404
- package/test/permission-ui-prompt.test.ts +0 -146
- package/test/permissions-service.test.ts +0 -192
- package/test/pi-infrastructure-read.test.ts +0 -432
- package/test/policy-loader.test.ts +0 -561
- package/test/prompting-gateway.test.ts +0 -231
- package/test/rule.test.ts +0 -650
- package/test/safe-system-paths.test.ts +0 -46
- package/test/scope-merge.test.ts +0 -116
- package/test/service-lifecycle.test.ts +0 -163
- package/test/service.test.ts +0 -261
- package/test/session-approval.test.ts +0 -75
- package/test/session-logger.test.ts +0 -200
- package/test/session-rules.test.ts +0 -321
- package/test/session-start.test.ts +0 -112
- package/test/skill-prompt-sanitizer.test.ts +0 -418
- package/test/status.test.ts +0 -10
- package/test/subagent-context.test.ts +0 -372
- package/test/subagent-lifecycle-events.test.ts +0 -132
- package/test/subagent-registry.test.ts +0 -145
- package/test/synthesize.test.ts +0 -302
- package/test/system-prompt-sanitizer.test.ts +0 -382
- package/test/tool-access-extractor-registry.test.ts +0 -77
- package/test/tool-input-formatter-registry.test.ts +0 -75
- package/test/tool-input-path.test.ts +0 -84
- package/test/tool-input-preview.test.ts +0 -129
- package/test/tool-input-prompt-formatters.test.ts +0 -115
- package/test/tool-preview-formatter.test.ts +0 -458
- package/test/tool-registry.test.ts +0 -197
- package/test/value-guards.test.ts +0 -193
- package/test/wildcard-matcher.test.ts +0 -424
- package/test/yaml-frontmatter.test.ts +0 -91
- package/test/yolo-mode.test.ts +0 -188
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
// Mock node:fs so realpathSync (used by canonicalizePath) is controllable.
|
|
4
|
-
// Default implementation is identity — lexical tests are unaffected.
|
|
5
|
-
const realpathSync = vi.hoisted(() =>
|
|
6
|
-
vi.fn<(path: string) => string>((p) => p),
|
|
7
|
-
);
|
|
8
|
-
vi.mock("node:fs", () => ({
|
|
9
|
-
realpathSync,
|
|
10
|
-
default: { realpathSync },
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
import { AccessPath } from "#src/access-intent/access-path";
|
|
14
|
-
import type { GateDescriptor } from "#src/handlers/gates/descriptor";
|
|
15
|
-
import { isGateDescriptor } from "#src/handlers/gates/descriptor";
|
|
16
|
-
import { describePathGate } from "#src/handlers/gates/path";
|
|
17
|
-
import type { ToolCallContext } from "#src/handlers/gates/types";
|
|
18
|
-
import { PathNormalizer } from "#src/path-normalizer";
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
makeGateCheckResult as makeCheckResult,
|
|
22
|
-
makeResolver,
|
|
23
|
-
} from "#test/helpers/gate-fixtures";
|
|
24
|
-
|
|
25
|
-
// ── helpers ────────────────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
// path.test.ts uses read-tool defaults; the shared makeTcc uses bash defaults.
|
|
28
|
-
function makeTcc(overrides: Partial<ToolCallContext> = {}): ToolCallContext {
|
|
29
|
-
return {
|
|
30
|
-
toolName: "read",
|
|
31
|
-
agentName: null,
|
|
32
|
-
input: { path: ".env" },
|
|
33
|
-
toolCallId: "tc-1",
|
|
34
|
-
cwd: "/test/project",
|
|
35
|
-
...overrides,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// The gate reads the path normalizer (platform + cwd baked in) from the
|
|
40
|
-
// session; here it is bound to the makeTcc default cwd.
|
|
41
|
-
const normalizer = new PathNormalizer(process.platform, "/test/project");
|
|
42
|
-
|
|
43
|
-
// ── tests ──────────────────────────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
describe("describePathGate", () => {
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
realpathSync.mockReset();
|
|
48
|
-
realpathSync.mockImplementation((p: string) => p);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("returns null for non-path-bearing tools", () => {
|
|
52
|
-
const resolver = makeResolver();
|
|
53
|
-
const result = describePathGate(
|
|
54
|
-
makeTcc({ toolName: "bash", input: { command: "ls" } }),
|
|
55
|
-
resolver,
|
|
56
|
-
normalizer,
|
|
57
|
-
);
|
|
58
|
-
expect(result).toBeNull();
|
|
59
|
-
expect(resolver.resolve).not.toHaveBeenCalled();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("returns null when tool has no extractable path", () => {
|
|
63
|
-
const resolver = makeResolver();
|
|
64
|
-
const result = describePathGate(
|
|
65
|
-
makeTcc({ toolName: "read", input: {} }),
|
|
66
|
-
resolver,
|
|
67
|
-
normalizer,
|
|
68
|
-
);
|
|
69
|
-
expect(result).toBeNull();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("returns null when path check result is allow", () => {
|
|
73
|
-
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
74
|
-
const result = describePathGate(makeTcc(), resolver, normalizer);
|
|
75
|
-
expect(result).toBeNull();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("returns null when matchedPattern is undefined (universal default)", () => {
|
|
79
|
-
const resolver = makeResolver(
|
|
80
|
-
makeCheckResult({
|
|
81
|
-
state: "ask",
|
|
82
|
-
matchedPattern: undefined,
|
|
83
|
-
source: "special",
|
|
84
|
-
origin: "builtin",
|
|
85
|
-
}),
|
|
86
|
-
);
|
|
87
|
-
const result = describePathGate(makeTcc(), resolver, normalizer);
|
|
88
|
-
expect(result).toBeNull();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("returns GateDescriptor when matchedPattern is defined (explicit path rule)", () => {
|
|
92
|
-
const resolver = makeResolver(
|
|
93
|
-
makeCheckResult({
|
|
94
|
-
state: "ask",
|
|
95
|
-
matchedPattern: "*.env",
|
|
96
|
-
source: "special",
|
|
97
|
-
origin: "global",
|
|
98
|
-
}),
|
|
99
|
-
);
|
|
100
|
-
const result = describePathGate(makeTcc(), resolver, normalizer);
|
|
101
|
-
expect(result).not.toBeNull();
|
|
102
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("returns GateDescriptor when path check result is deny", () => {
|
|
106
|
-
const resolver = makeResolver(
|
|
107
|
-
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
108
|
-
);
|
|
109
|
-
const result = describePathGate(makeTcc(), resolver, normalizer);
|
|
110
|
-
expect(result).not.toBeNull();
|
|
111
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
112
|
-
const desc = result as GateDescriptor;
|
|
113
|
-
expect(desc.surface).toBe("path");
|
|
114
|
-
expect(desc.preCheck?.state).toBe("deny");
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("returns GateDescriptor when path check result is ask", () => {
|
|
118
|
-
const resolver = makeResolver(
|
|
119
|
-
makeCheckResult({ state: "ask", matchedPattern: "*.env" }),
|
|
120
|
-
);
|
|
121
|
-
const result = describePathGate(makeTcc(), resolver, normalizer);
|
|
122
|
-
expect(result).not.toBeNull();
|
|
123
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
124
|
-
const desc = result as GateDescriptor;
|
|
125
|
-
expect(desc.surface).toBe("path");
|
|
126
|
-
expect(desc.preCheck?.state).toBe("ask");
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("descriptor has correct session approval surface and pattern", () => {
|
|
130
|
-
const resolver = makeResolver(
|
|
131
|
-
makeCheckResult({ state: "ask", matchedPattern: "*" }),
|
|
132
|
-
);
|
|
133
|
-
const result = describePathGate(
|
|
134
|
-
makeTcc({ input: { path: "/test/project/src/.env" } }),
|
|
135
|
-
resolver,
|
|
136
|
-
normalizer,
|
|
137
|
-
) as GateDescriptor;
|
|
138
|
-
expect(result.sessionApproval).toBeDefined();
|
|
139
|
-
expect(result.sessionApproval?.surface).toBe("path");
|
|
140
|
-
expect(result.sessionApproval?.representativePattern).toBeDefined();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("binds a current-directory file's session approval to the cwd subtree", () => {
|
|
144
|
-
const resolver = makeResolver(
|
|
145
|
-
makeCheckResult({ state: "ask", matchedPattern: "*" }),
|
|
146
|
-
);
|
|
147
|
-
const result = describePathGate(
|
|
148
|
-
makeTcc({ input: { path: "index.html" }, cwd: "/test/project" }),
|
|
149
|
-
resolver,
|
|
150
|
-
normalizer,
|
|
151
|
-
) as GateDescriptor;
|
|
152
|
-
expect(result.sessionApproval?.surface).toBe("path");
|
|
153
|
-
expect(result.sessionApproval?.representativePattern).toBe(
|
|
154
|
-
"/test/project/*",
|
|
155
|
-
);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("descriptor denialContext references the file path and tool name", () => {
|
|
159
|
-
const resolver = makeResolver(
|
|
160
|
-
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
161
|
-
);
|
|
162
|
-
const result = describePathGate(
|
|
163
|
-
makeTcc(),
|
|
164
|
-
resolver,
|
|
165
|
-
normalizer,
|
|
166
|
-
) as GateDescriptor;
|
|
167
|
-
expect(result.denialContext).toEqual({
|
|
168
|
-
kind: "path",
|
|
169
|
-
toolName: "read",
|
|
170
|
-
pathValue: ".env",
|
|
171
|
-
agentName: undefined,
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it("descriptor decision uses surface 'path' and the file path as value", () => {
|
|
176
|
-
const resolver = makeResolver(
|
|
177
|
-
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
178
|
-
);
|
|
179
|
-
const result = describePathGate(
|
|
180
|
-
makeTcc(),
|
|
181
|
-
resolver,
|
|
182
|
-
normalizer,
|
|
183
|
-
) as GateDescriptor;
|
|
184
|
-
expect(result.decision.surface).toBe("path");
|
|
185
|
-
expect(result.decision.value).toBe(".env");
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it("resolves the path surface with an access-path intent and agent name", () => {
|
|
189
|
-
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
190
|
-
describePathGate(makeTcc({ agentName: "my-agent" }), resolver, normalizer);
|
|
191
|
-
expect(resolver.resolve).toHaveBeenCalledWith({
|
|
192
|
-
kind: "access-path",
|
|
193
|
-
surface: "path",
|
|
194
|
-
path: AccessPath.forPath(".env", {
|
|
195
|
-
cwd: "/test/project",
|
|
196
|
-
platform: "linux",
|
|
197
|
-
}),
|
|
198
|
-
agentName: "my-agent",
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it("emits an access-path whose matchValues include the symlink-resolved form (#486)", () => {
|
|
203
|
-
// /test/project/.env is a symlink to /vault/secret.env.
|
|
204
|
-
realpathSync.mockImplementation((p: string) =>
|
|
205
|
-
p === "/test/project/.env" ? "/vault/secret.env" : p,
|
|
206
|
-
);
|
|
207
|
-
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
208
|
-
describePathGate(makeTcc(), resolver, normalizer);
|
|
209
|
-
|
|
210
|
-
const intent = resolver.resolve.mock.lastCall?.[0];
|
|
211
|
-
expect(intent?.kind).toBe("access-path");
|
|
212
|
-
expect(intent?.kind === "access-path" && intent.path.matchValues()).toEqual(
|
|
213
|
-
["/test/project/.env", ".env", "/vault/secret.env"],
|
|
214
|
-
);
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// Home-relative path characterization (#350) ──────────────────────────────
|
|
219
|
-
//
|
|
220
|
-
// The gate passes the raw path to the resolver; home expansion is handled
|
|
221
|
-
// downstream by normalizeInput. These tests lock in that the gate works
|
|
222
|
-
// correctly when the tool input contains a ~/... or $HOME/... path.
|
|
223
|
-
|
|
224
|
-
describe("describePathGate — home-relative paths", () => {
|
|
225
|
-
it("passes raw ~/... path to resolver and builds descriptor on deny", () => {
|
|
226
|
-
const resolver = makeResolver(
|
|
227
|
-
makeCheckResult({ state: "deny", matchedPattern: "~/.ssh/*" }),
|
|
228
|
-
);
|
|
229
|
-
const result = describePathGate(
|
|
230
|
-
makeTcc({ input: { path: "~/.ssh/config" } }),
|
|
231
|
-
resolver,
|
|
232
|
-
normalizer,
|
|
233
|
-
) as GateDescriptor;
|
|
234
|
-
|
|
235
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
236
|
-
expect(result.preCheck?.state).toBe("deny");
|
|
237
|
-
// Raw path preserved in denial context for display.
|
|
238
|
-
expect(result.denialContext).toMatchObject({
|
|
239
|
-
kind: "path",
|
|
240
|
-
toolName: "read",
|
|
241
|
-
pathValue: "~/.ssh/config",
|
|
242
|
-
});
|
|
243
|
-
expect(resolver.resolve).toHaveBeenCalledWith({
|
|
244
|
-
kind: "access-path",
|
|
245
|
-
surface: "path",
|
|
246
|
-
path: AccessPath.forPath("~/.ssh/config", {
|
|
247
|
-
cwd: "/test/project",
|
|
248
|
-
platform: "linux",
|
|
249
|
-
}),
|
|
250
|
-
agentName: undefined,
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it("passes raw $HOME/... path to resolver and builds descriptor on deny", () => {
|
|
255
|
-
const resolver = makeResolver(
|
|
256
|
-
makeCheckResult({ state: "deny", matchedPattern: "$HOME/.ssh/*" }),
|
|
257
|
-
);
|
|
258
|
-
const result = describePathGate(
|
|
259
|
-
makeTcc({ input: { path: "$HOME/.ssh/config" } }),
|
|
260
|
-
resolver,
|
|
261
|
-
normalizer,
|
|
262
|
-
) as GateDescriptor;
|
|
263
|
-
|
|
264
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
265
|
-
expect(result.preCheck?.state).toBe("deny");
|
|
266
|
-
expect(result.denialContext).toMatchObject({
|
|
267
|
-
kind: "path",
|
|
268
|
-
pathValue: "$HOME/.ssh/config",
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it("returns null when home-relative path resolves to allow", () => {
|
|
273
|
-
const resolver = makeResolver(makeCheckResult({ state: "allow" }));
|
|
274
|
-
const result = describePathGate(
|
|
275
|
-
makeTcc({ input: { path: "~/.ssh/config" } }),
|
|
276
|
-
resolver,
|
|
277
|
-
normalizer,
|
|
278
|
-
);
|
|
279
|
-
expect(result).toBeNull();
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// Extension and MCP tools are now path-gated (#352) ──────────────────────────
|
|
284
|
-
|
|
285
|
-
describe("describePathGate — extension and MCP tools (#352)", () => {
|
|
286
|
-
function extractorLookup(toolName: string, key: string) {
|
|
287
|
-
return {
|
|
288
|
-
get: (name: string) =>
|
|
289
|
-
name === toolName
|
|
290
|
-
? (input: Record<string, unknown>) =>
|
|
291
|
-
typeof input[key] === "string" ? input[key] : undefined
|
|
292
|
-
: undefined,
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
it("gates an extension tool that exposes input.path", () => {
|
|
297
|
-
const resolver = makeResolver(
|
|
298
|
-
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
299
|
-
);
|
|
300
|
-
const result = describePathGate(
|
|
301
|
-
makeTcc({ toolName: "my-ext", input: { path: ".env" } }),
|
|
302
|
-
resolver,
|
|
303
|
-
normalizer,
|
|
304
|
-
);
|
|
305
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
306
|
-
expect(resolver.resolve).toHaveBeenCalledWith({
|
|
307
|
-
kind: "access-path",
|
|
308
|
-
surface: "path",
|
|
309
|
-
path: AccessPath.forPath(".env", {
|
|
310
|
-
cwd: "/test/project",
|
|
311
|
-
platform: "linux",
|
|
312
|
-
}),
|
|
313
|
-
agentName: undefined,
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it("gates an MCP tool via arguments.path", () => {
|
|
318
|
-
const resolver = makeResolver(
|
|
319
|
-
makeCheckResult({ state: "deny", matchedPattern: "*.env" }),
|
|
320
|
-
);
|
|
321
|
-
const result = describePathGate(
|
|
322
|
-
makeTcc({ toolName: "mcp", input: { arguments: { path: ".env" } } }),
|
|
323
|
-
resolver,
|
|
324
|
-
normalizer,
|
|
325
|
-
);
|
|
326
|
-
expect(isGateDescriptor(result)).toBe(true);
|
|
327
|
-
expect(resolver.resolve).toHaveBeenCalledWith({
|
|
328
|
-
kind: "access-path",
|
|
329
|
-
surface: "path",
|
|
330
|
-
path: AccessPath.forPath(".env", {
|
|
331
|
-
cwd: "/test/project",
|
|
332
|
-
platform: "linux",
|
|
333
|
-
}),
|
|
334
|
-
agentName: undefined,
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it("uses a registered extractor's path for a custom-shaped tool", () => {
|
|
339
|
-
const resolver = makeResolver(
|
|
340
|
-
makeCheckResult({ state: "deny", matchedPattern: "*" }),
|
|
341
|
-
);
|
|
342
|
-
describePathGate(
|
|
343
|
-
makeTcc({ toolName: "ffgrep", input: { target: "/etc/passwd" } }),
|
|
344
|
-
resolver,
|
|
345
|
-
normalizer,
|
|
346
|
-
extractorLookup("ffgrep", "target"),
|
|
347
|
-
);
|
|
348
|
-
expect(resolver.resolve).toHaveBeenCalledWith({
|
|
349
|
-
kind: "access-path",
|
|
350
|
-
surface: "path",
|
|
351
|
-
path: AccessPath.forPath("/etc/passwd", {
|
|
352
|
-
cwd: "/test/project",
|
|
353
|
-
platform: "linux",
|
|
354
|
-
}),
|
|
355
|
-
agentName: undefined,
|
|
356
|
-
});
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it("returns null for an extension tool without a path", () => {
|
|
360
|
-
const resolver = makeResolver();
|
|
361
|
-
const result = describePathGate(
|
|
362
|
-
makeTcc({ toolName: "my-ext", input: { other: true } }),
|
|
363
|
-
resolver,
|
|
364
|
-
normalizer,
|
|
365
|
-
);
|
|
366
|
-
expect(result).toBeNull();
|
|
367
|
-
expect(resolver.resolve).not.toHaveBeenCalled();
|
|
368
|
-
});
|
|
369
|
-
});
|