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
329 lines · 8.8 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 on('settings.read', () => ({ deny: 'managed settings unreadable' }))
71
72 const registered = Fixtures.toolsRegistered(on)
73
74 await $.session.start(Fixtures.SESSION)
75
76 expect(registered).toEqual([])
77 },
78 )
79
80 test(
81 'the organization tools are listed as its tiers listed them',
82 { plugins: [Fixtures.relabeling, Fixtures.listing] },
83 async ($, on) => {
84 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
85 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
86
87 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
88
89 expect(text?.split('\n')).toEqual([
90 'mcp__corp__search: Searches the corp wiki.',
91 'Bash: relabeled',
92 ])
93 },
94 )
95
96 test(
97 'a server policy delivers itself counts as a tool policy, unlisted',
98 { plugins: [Fixtures.relabeling, Fixtures.listing] },
99 async ($, on) => {
100 on('settings.read', () => ({ value: Fixtures.SERVER_POLICY }))
101 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
102
103 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
104
105 expect(text?.split('\n')).toEqual([
106 'mcp__corp__search: Searches the corp wiki.',
107 'Bash: relabeled',
108 ])
109 },
110 )
111
112 test(
113 "with no policy to read the organization's listing stands whole",
114 { plugins: [Fixtures.relabeling, Fixtures.listing] },
115 async ($, on) => {
116 on('settings.read', () => ({ deny: 'settings unreadable' }))
117 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
118
119 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
120
121 expect(text?.split('\n')).toEqual([
122 'mcp__corp__search: Searches the corp wiki.',
123 'Bash: Runs a command.',
124 ])
125 },
126 )
127
128 test(
129 'a prompt section passes over the plugins the person installed',
130 { plugins: [Fixtures.dropping, Fixtures.signing] },
131 async ($, on) => {
132 on('prompt.section', ($, e) => ({ text: e.text }))
133
134 expect(await $.prompt.section(Fixtures.MEMORY)).toEqual({
135 text: 'the org says hi (signed)',
136 })
137 },
138 )
139
140 test(
141 'a collector record passes over the plugins the person installed',
142 { plugins: [Fixtures.withholding, Fixtures.exporting] },
143 async ($, on) => {
144 const reached: unknown[] = []
145 on('telemetry.log', { to: 'collector' }, ($, e) => {
146 reached.push([e.event, e.props?.edited])
147
148 return { value: undefined }
149 })
150
151 await $.command.run(Fixtures.EXPORT_COMMAND)
152
153 expect(reached).toEqual([
154 ['kept', undefined],
155 ['withheld', undefined],
156 ])
157 },
158 )
159
160 test(
161 "a user plugin's rewrite of policy is skipped for every other reader",
162 {
163 plugins: [
164 Fixtures.stripping,
165 Fixtures.reading,
166 Fixtures.registering('mine'),
167 ],
168 },
169 async ($, on) => {
170 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
171
172 const registered = Fixtures.toolsRegistered(on)
173 const { text } = await $.command.run(Fixtures.POLICY_COMMAND)
174
175 await $.session.start(Fixtures.SESSION)
176
177 expect(
178 JSON.parse(text ?? 'null'),
179 "another user plugin's read sees the allowlist the stripper hides",
180 ).toEqual(Fixtures.MANAGED_POLICY)
181
182 expect(
183 registered,
184 "sec-default's own tool.register hook still reads the allowlist",
185 ).toEqual([])
186 },
187 )
188
189 test(
190 "an organization provider's subject passes over the user plugins",
191 { plugins: [Fixtures.marking] },
192 async ($, on) => {
193 Fixtures.subjectsEchoed(on)
194
195 for (const provider of Fixtures.ORG_PROVIDERS) {
196 expect(
197 await $.tool.describe(
198 Fixtures.toolDescribed('mcp__corp__search', provider),
199 ),
200 ).toEqual({ description: 'd' })
201
202 expect(
203 (
204 await $.command.describe(
205 Fixtures.commandDescribed('suite:deploy', provider),
206 )
207 ).isHidden,
208 ).toBe(false)
209
210 expect(
211 await $.agent.offer(
212 Fixtures.agentOffered('suite:reviewer', provider),
213 ),
214 ).toEqual({ isOffered: true })
215
216 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
217 model: 'core',
218 })
219 }
220
221 for (const provider of Fixtures.USER_REACHABLE_PROVIDERS) {
222 expect(
223 await $.tool.describe(
224 Fixtures.toolDescribed('mcp__mine__search', provider),
225 ),
226 ).toEqual({ description: 'user: d' })
227
228 expect(
229 (
230 await $.command.describe(
231 Fixtures.commandDescribed('mine:deploy', provider),
232 )
233 ).isHidden,
234 ).toBe(true)
235
236 expect(
237 await $.agent.offer(Fixtures.agentOffered('reviewer', provider)),
238 ).toEqual({ isOffered: false })
239
240 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
241 model: 'user',
242 })
243 }
244 },
245 )
246
247 test(
248 'an odd provider passes over the user plugins: it fails closed',
249 { plugins: [Fixtures.marking] },
250 async ($, on) => {
251 Fixtures.subjectsEchoed(on)
252
253 for (const provider of Fixtures.ODD_PROVIDERS) {
254 expect(
255 await $.tool.describe(Fixtures.toolDescribed('Bash', provider)),
256 ).toEqual({ description: 'd' })
257
258 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
259 model: 'core',
260 })
261 }
262 },
263 )
264
265 test(
266 'a subject decision reads no policy; a burst of listings reads once',
267 { plugins: [Fixtures.listing] },
268 async ($, on) => {
269 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
270
271 Fixtures.subjectsEchoed(on)
272 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
273
274 for (const provider of Fixtures.ORG_PROVIDERS) {
275 await $.tool.describe(Fixtures.toolDescribed('mcp__corp__x', provider))
276 await $.agent.spawn(Fixtures.agentSpawned(provider))
277 }
278
279 expect(reads()).toBe(0)
280
281 await Promise.all([
282 $.command.run(Fixtures.TOOLS_COMMAND),
283 $.command.run(Fixtures.TOOLS_COMMAND),
284 $.command.run(Fixtures.TOOLS_COMMAND),
285 ])
286
287 expect(reads()).toBe(1)
288 },
289 )
290
291 test(
292 'the refusal a user-tier caller reads names the allowlist',
293 {
294 plugins: [
295 {
296 name: 'asking',
297 register(on) {
298 on('command.run', { command: 'greet' }, $ =>
299 $.tool
300 .register({
301 name: 'greet',
302 description: 'Says hello.',
303 inputSchema: { type: 'object' },
304 })
305 .then(
306 () => ({ text: 'registered' }),
307 (error: unknown) => ({ text: String(error) }),
308 ),
309 )
310 },
311 },
312 ],
313 },
314 async ($, on) => {
315 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
316
317 const { text } = await $.command.run({
318 command: 'greet',
319 args: '',
320 origin: { kind: 'composer' },
321 presentation: Fixtures.FULLSCREEN,
322 })
323
324 expect(text).toEndWith(
325 `asking: $.tool.register: ${Hooks.TOOL_REGISTER_REFUSAL}`,
326 )
327 },
328 )
329})