spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / mods / sec-default / tests / register.test.ts
475 lines · 12.9 KBRaw
1import { describe, expect, test, tier } from 'claude-code/testing'
2
3import Hooks from '../hooks'
4import Fixtures from './fixtures'
5
6tier('prepend')
7
8describe('register', () => {
9 test(
10 'under an MCP allowlist a plugin the person installed may not add a tool',
11 {
12 plugins: [
13 Fixtures.registering('suite', 'prepend'),
14 Fixtures.registering('mine'),
15 Fixtures.registering('bundled', 'builtin'),
16 ],
17 },
18 async ($, on) => {
19 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
20
21 const registered = Fixtures.toolsRegistered(on)
22
23 await $.session.start(Fixtures.SESSION)
24
25 expect(registered).toEqual(['suite', 'bundled'])
26 },
27 )
28
29 test(
30 'with no allowlist, a plugin the person installed adds its tool',
31 { plugins: [Fixtures.registering('mine')] },
32 async ($, on) => {
33 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
34
35 const registered = Fixtures.toolsRegistered(on)
36
37 await $.session.start(Fixtures.SESSION)
38
39 expect(registered).toEqual(['mine'])
40 },
41 )
42
43 test(
44 "an organization's registration passes over a refusing user plugin",
45 {
46 plugins: [
47 Fixtures.registering('suite', 'prepend'),
48 Fixtures.denying,
49 Fixtures.registering('bundled', 'builtin'),
50 ],
51 },
52 async ($, on) => {
53 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
54
55 const registered = Fixtures.toolsRegistered(on)
56
57 await $.session.start(Fixtures.SESSION)
58
59 expect(
60 registered,
61 "a built-in's registration still meets the user's deny",
62 ).toEqual(['suite'])
63 },
64 )
65
66 test(
67 'a policy that cannot be read counts as one in force',
68 { plugins: [Fixtures.registering('mine')] },
69 async ($, on) => {
70 const stopPolicy = Fixtures.policyUntilStopped(
71 on,
72 Fixtures.NO_ALLOWLIST,
73 'managed settings unreadable',
74 )
75
76 const registered = Fixtures.toolsRegistered(on)
77
78 on('prompt.section', ($, e) => ({ text: e.text }))
79
80 await $.prompt.section(Fixtures.MEMORY)
81 stopPolicy()
82 await $.session.start(Fixtures.SESSION)
83
84 expect(registered).toEqual([])
85 },
86 )
87
88 test(
89 'the organization tools are listed as its tiers listed them',
90 { plugins: [Fixtures.relabeling, Fixtures.listing] },
91 async ($, on) => {
92 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
93 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
94
95 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
96
97 expect(text?.split('\n')).toEqual([
98 'mcp__corp__search: Searches the corp wiki.',
99 'Bash: relabeled',
100 ])
101 },
102 )
103
104 test(
105 'a server policy delivers itself counts as a tool policy, unlisted',
106 { plugins: [Fixtures.relabeling, Fixtures.listing] },
107 async ($, on) => {
108 on('settings.read', () => ({ value: Fixtures.SERVER_POLICY }))
109 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
110
111 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
112
113 expect(text?.split('\n')).toEqual([
114 'mcp__corp__search: Searches the corp wiki.',
115 'Bash: relabeled',
116 ])
117 },
118 )
119
120 test(
121 "with no policy to read the organization's listing stands whole",
122 { plugins: [Fixtures.relabeling, Fixtures.listing] },
123 async ($, on) => {
124 const stopPolicy = Fixtures.policyUntilStopped(
125 on,
126 Fixtures.ALLOWLIST,
127 'settings unreadable',
128 )
129
130 on('prompt.section', ($, e) => ({ text: e.text }))
131 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
132
133 await $.prompt.section(Fixtures.MEMORY)
134 stopPolicy()
135
136 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
137
138 expect(text?.split('\n')).toEqual([
139 'mcp__corp__search: Searches the corp wiki.',
140 'Bash: Runs a command.',
141 ])
142 },
143 )
144
145 test(
146 'a prompt section passes over the plugins the person installed',
147 { plugins: [Fixtures.dropping, Fixtures.signing] },
148 async ($, on) => {
149 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
150 on('prompt.section', ($, e) => ({ text: e.text }))
151
152 expect(await $.prompt.section(Fixtures.MEMORY)).toEqual({
153 text: 'the org says hi (signed)',
154 })
155 },
156 )
157
158 test(
159 "the system prompt's sections pass over the plugins the person installed",
160 { plugins: [Fixtures.emptying, Fixtures.heading] },
161 async ($, on) => {
162 on('prompt.compose', () => ({
163 sections: [{ id: 'body', text: 'the body', scope: 'shared' }],
164 }))
165
166 expect(await $.prompt.compose(Fixtures.COMPOSED)).toEqual({
167 sections: [
168 { id: 'heading:org', text: 'the org says hi', scope: 'shared' },
169 { id: 'body', text: 'the body', scope: 'shared' },
170 ],
171 })
172 },
173 )
174
175 test(
176 "a user plugin's rewrite of policy is skipped for every other reader",
177 {
178 plugins: [
179 Fixtures.stripping,
180 Fixtures.reading,
181 Fixtures.registering('mine'),
182 ],
183 },
184 async ($, on) => {
185 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
186
187 const registered = Fixtures.toolsRegistered(on)
188 const { text } = await $.command.run(Fixtures.POLICY_COMMAND)
189
190 await $.session.start(Fixtures.SESSION)
191
192 expect(
193 JSON.parse(text ?? 'null'),
194 "another user plugin's read sees the allowlist the stripper hides",
195 ).toEqual(Fixtures.MANAGED_POLICY)
196
197 expect(
198 registered,
199 "sec-default's own tool.register hook still reads the allowlist",
200 ).toEqual([])
201 },
202 )
203
204 test(
205 "an organization provider's subject passes over the user plugins",
206 { plugins: [Fixtures.marking] },
207 async ($, on) => {
208 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
209 Fixtures.subjectsEchoed(on)
210
211 for (const provider of Fixtures.ORG_PROVIDERS) {
212 expect(
213 await $.tool.describe(
214 Fixtures.toolDescribed('mcp__corp__search', provider),
215 ),
216 ).toEqual({ description: 'd' })
217
218 expect(
219 (
220 await $.command.describe(
221 Fixtures.commandDescribed('suite:deploy', provider),
222 )
223 ).isHidden,
224 ).toBe(false)
225
226 expect(
227 await $.agent.offer(
228 Fixtures.agentOffered('suite:reviewer', provider),
229 ),
230 ).toEqual({ isOffered: true })
231
232 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
233 model: 'core',
234 })
235 }
236
237 for (const provider of Fixtures.USER_REACHABLE_PROVIDERS) {
238 expect(
239 await $.tool.describe(
240 Fixtures.toolDescribed('mcp__mine__search', provider),
241 ),
242 ).toEqual({ description: 'user: d' })
243
244 expect(
245 (
246 await $.command.describe(
247 Fixtures.commandDescribed('mine:deploy', provider),
248 )
249 ).isHidden,
250 ).toBe(true)
251
252 expect(
253 await $.agent.offer(Fixtures.agentOffered('reviewer', provider)),
254 ).toEqual({ isOffered: false })
255
256 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
257 model: 'user',
258 })
259 }
260 },
261 )
262
263 test(
264 'an odd provider passes over the user plugins: it fails closed',
265 { plugins: [Fixtures.marking] },
266 async ($, on) => {
267 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
268 Fixtures.subjectsEchoed(on)
269
270 for (const provider of Fixtures.ODD_PROVIDERS) {
271 expect(
272 await $.tool.describe(Fixtures.toolDescribed('Bash', provider)),
273 ).toEqual({ description: 'd' })
274
275 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
276 model: 'core',
277 })
278 }
279 },
280 )
281
282 test(
283 'a subject decision reads no policy; a burst of listings reads once',
284 { plugins: [Fixtures.listing] },
285 async ($, on) => {
286 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
287
288 Fixtures.subjectsEchoed(on)
289 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
290
291 for (const provider of Fixtures.ORG_PROVIDERS) {
292 await $.tool.describe(Fixtures.toolDescribed('mcp__corp__x', provider))
293 await $.agent.spawn(Fixtures.agentSpawned(provider))
294 }
295
296 expect(reads(), "one read: the person's plugin was admitted").toBe(1)
297
298 await Promise.all([
299 $.command.run(Fixtures.TOOLS_COMMAND),
300 $.command.run(Fixtures.TOOLS_COMMAND),
301 $.command.run(Fixtures.TOOLS_COMMAND),
302 ])
303
304 expect(reads()).toBe(2)
305 },
306 )
307
308 test(
309 'the refusal a user-tier caller reads names the allowlist',
310 {
311 plugins: [
312 {
313 name: 'asking',
314 register(on) {
315 on('command.run', { command: 'greet' }, $ =>
316 $.tool
317 .register({
318 name: 'greet',
319 description: 'Says hello.',
320 inputSchema: { type: 'object' },
321 })
322 .then(
323 () => ({ text: 'registered' }),
324 (error: unknown) => ({ text: String(error) }),
325 ),
326 )
327 },
328 },
329 ],
330 },
331 async ($, on) => {
332 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
333
334 const { text } = await $.command.run({
335 command: 'greet',
336 args: '',
337 origin: { kind: 'composer' },
338 presentation: Fixtures.FULLSCREEN,
339 })
340
341 expect(text).toEndWith(
342 `asking: $.tool.register: ${Hooks.TOOL_REGISTER_REFUSAL}`,
343 )
344 },
345 )
346
347 test(
348 "under allowManagedModsOnly a person's mod is kept out, told why",
349 { plugins: [Fixtures.registering('mine')] },
350 async ($, on) => {
351 on('settings.read', () => ({ value: Fixtures.MANAGED_MODS_ONLY }))
352
353 const registered = Fixtures.toolsRegistered(on)
354
355 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
356 Hooks.managedModsOnlyRefusal('mine'),
357 )
358
359 expect(registered, 'no hook of it ever ran').toEqual([])
360 },
361 )
362
363 test(
364 "under it the organization's mods and the built-ins load",
365 {
366 plugins: [
367 Fixtures.registering('suite', 'prepend'),
368 Fixtures.registering('after', 'append'),
369 Fixtures.registering('bundled', 'builtin'),
370 ],
371 },
372 async ($, on) => {
373 on('settings.read', () => ({ value: Fixtures.MANAGED_MODS_ONLY }))
374
375 const registered = Fixtures.toolsRegistered(on)
376
377 await $.session.start(Fixtures.SESSION)
378
379 expect(registered).toEqual(['suite', 'after', 'bundled'])
380 },
381 )
382
383 test(
384 'set to false, a mod the person installed loads as before',
385 { plugins: [Fixtures.registering('mine')] },
386 async ($, on) => {
387 on('settings.read', () => ({ value: Fixtures.modsPolicyOf(false) }))
388
389 const registered = Fixtures.toolsRegistered(on)
390
391 await $.session.start(Fixtures.SESSION)
392
393 expect(registered).toEqual(['mine'])
394 },
395 )
396
397 test(
398 "a person's copy under an organization mod's name is still theirs",
399 { plugins: [Fixtures.registering('suite')] },
400 async ($, on) => {
401 on('settings.read', () => ({
402 value: { ...Fixtures.MANAGED_POLICY, ...Fixtures.MANAGED_MODS_ONLY },
403 }))
404
405 const registered = Fixtures.toolsRegistered(on)
406
407 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
408 Hooks.managedModsOnlyRefusal('suite'),
409 )
410
411 expect(registered).toEqual([])
412 },
413 )
414
415 test(
416 "only managed settings are asked: a person's own cannot loosen it",
417 { plugins: [Fixtures.registering('mine')] },
418 async ($, on) => {
419 Fixtures.policyBySource(
420 on,
421 Fixtures.MANAGED_MODS_ONLY,
422 Fixtures.modsPolicyOf(false),
423 )
424
425 const registered = Fixtures.toolsRegistered(on)
426
427 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
428 Hooks.managedModsOnlyRefusal('mine'),
429 )
430
431 expect(registered).toEqual([])
432 },
433 )
434
435 test(
436 "nor turn it on: set only in a person's settings, it is not read",
437 { plugins: [Fixtures.registering('mine')] },
438 async ($, on) => {
439 Fixtures.policyBySource(
440 on,
441 Fixtures.NO_ALLOWLIST,
442 Fixtures.MANAGED_MODS_ONLY,
443 )
444
445 const registered = Fixtures.toolsRegistered(on)
446
447 await $.session.start(Fixtures.SESSION)
448
449 expect(registered).toEqual(['mine'])
450 },
451 )
452
453 test(
454 "a policy that cannot be read keeps a person's mod out: the hook's catch",
455 { plugins: [Fixtures.registering('mine')] },
456 async ($, on) => {
457 on('settings.read', () => ({ deny: 'managed settings unreadable' }))
458
459 const lines = Fixtures.logged(on)
460 const registered = Fixtures.toolsRegistered(on)
461
462 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
463 Hooks.managedModsOnlyRefusal('mine'),
464 )
465
466 expect({ registered, lines }).toEqual({
467 registered: [],
468 lines: [
469 'debug: plugin.register hook failed judging mine (throw): ' +
470 'sec-default: $.settings.read: managed settings unreadable',
471 ],
472 })
473 },
474 )
475})