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
GitHub Actions (publish-mods)chore: Update mods/ bf2323b · 11 days ago History
2,435 lines · 68.3 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 "a plugin of theirs named as an organization's server adds no tool",
90 {
91 plugins: [
92 Fixtures.registering('corp'),
93 Fixtures.registering('mine'),
94 Fixtures.registering('bundled', 'builtin'),
95 ],
96 },
97 async ($, on) => {
98 on('settings.read', () => ({ value: Fixtures.SERVER_POLICY }))
99
100 const registered = Fixtures.toolsRegistered(on)
101
102 await $.session.start(Fixtures.SESSION)
103
104 expect(registered).toEqual(['mine', 'bundled'])
105 },
106 )
107
108 test(
109 "a plugin of theirs named as a seated plugin's own server adds no tool",
110 {
111 plugins: [
112 Fixtures.registering('plugin-corp-suite-corp-jira'),
113 Fixtures.registering('mine'),
114 ],
115 },
116 async ($, on) => {
117 on('settings.read', () => ({ value: Fixtures.SEATED_SUITE }))
118
119 const registered = Fixtures.toolsRegistered(on)
120
121 await $.session.start(Fixtures.SESSION)
122
123 expect(registered).toEqual(['mine'])
124 },
125 )
126
127 test(
128 "the organization's own plugin under such a name still adds its tool",
129 { plugins: [Fixtures.registering('corp', 'append')] },
130 async ($, on) => {
131 on('settings.read', () => ({ value: Fixtures.SERVER_POLICY }))
132
133 const registered = Fixtures.toolsRegistered(on)
134
135 await $.session.start(Fixtures.SESSION)
136
137 expect(registered).toEqual(['corp'])
138 },
139 )
140
141 test(
142 'the organization tools are listed as its tiers listed them',
143 { plugins: [Fixtures.relabeling, Fixtures.listing] },
144 async ($, on) => {
145 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
146 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
147
148 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
149
150 expect(text?.split('\n')).toEqual([
151 'mcp__corp__search: Searches the corp wiki.',
152 'Bash: relabeled',
153 ])
154 },
155 )
156
157 test(
158 "a seated plugin's own server tools are listed as its tiers listed them",
159 { plugins: [Fixtures.relabeling, Fixtures.listing] },
160 async ($, on) => {
161 on('settings.read', () => ({ value: Fixtures.SEATED_SUITE }))
162 on('tool.list', () => ({ value: [...Fixtures.SUITE_TOOLS] }))
163
164 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
165
166 expect(text?.split('\n')).toEqual([
167 'mcp__plugin_corp-suite_corp-jira__create_ticket: Creates a ticket.',
168 'Bash: relabeled',
169 ])
170 },
171 )
172
173 test(
174 'a seated plugin listed in another case has its server tools listed too',
175 { plugins: [Fixtures.relabeling, Fixtures.listing] },
176 async ($, on) => {
177 on('settings.read', () => ({
178 value: { prependPlugins: ['Corp-Suite@market'] },
179 }))
180 on('tool.list', () => ({ value: [...Fixtures.SUITE_TOOLS] }))
181
182 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
183
184 expect(text?.split('\n')).toEqual([
185 'mcp__plugin_corp-suite_corp-jira__create_ticket: Creates a ticket.',
186 'Bash: relabeled',
187 ])
188 },
189 )
190
191 test(
192 'a plugin named as one a version-pinned entry turns on adds no tool',
193 {
194 plugins: [
195 Fixtures.registering('corp-suite'),
196 Fixtures.registering('mine'),
197 ],
198 },
199 async ($, on) => {
200 on('settings.read', () => ({
201 value: { enabledPlugins: { 'corp-suite@market': ['^1.0.0'] } },
202 }))
203
204 const registered = Fixtures.toolsRegistered(on)
205
206 await $.session.start(Fixtures.SESSION)
207
208 expect(registered).toEqual(['mine'])
209 },
210 )
211
212 test(
213 'a server policy delivers itself counts as a tool policy, unlisted',
214 { plugins: [Fixtures.relabeling, Fixtures.listing] },
215 async ($, on) => {
216 on('settings.read', () => ({ value: Fixtures.SERVER_POLICY }))
217 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
218
219 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
220
221 expect(text?.split('\n')).toEqual([
222 'mcp__corp__search: Searches the corp wiki.',
223 'Bash: relabeled',
224 ])
225 },
226 )
227
228 test(
229 "with no policy to read the organization's listing stands whole",
230 { plugins: [Fixtures.relabeling, Fixtures.listing] },
231 async ($, on) => {
232 const stopPolicy = Fixtures.policyUntilStopped(
233 on,
234 Fixtures.ALLOWLIST,
235 'settings unreadable',
236 )
237
238 on('prompt.section', ($, e) => ({ text: e.text }))
239 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
240
241 await $.prompt.section(Fixtures.MEMORY)
242 stopPolicy()
243
244 const { text } = await $.command.run(Fixtures.TOOLS_COMMAND)
245
246 expect(text?.split('\n')).toEqual([
247 'mcp__corp__search: Searches the corp wiki.',
248 'Bash: Runs a command.',
249 ])
250 },
251 )
252
253 test(
254 'a prompt section passes over the plugins the person installed',
255 { plugins: [Fixtures.dropping, Fixtures.signing] },
256 async ($, on) => {
257 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
258 on('prompt.section', ($, e) => ({ text: e.text }))
259
260 expect(await $.prompt.section(Fixtures.MEMORY)).toEqual({
261 text: 'the org says hi (signed)',
262 })
263 },
264 )
265
266 test(
267 'what the engine attaches passes over the plugins the person installed',
268 { plugins: [Fixtures.droppingAttachments] },
269 async ($, on) => {
270 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
271 on('prompt.attachment', ($, e) => ({ text: e.text }))
272
273 expect(await $.prompt.attachment(Fixtures.HOOK_NOTE)).toEqual({
274 text: Fixtures.HOOK_NOTE.text,
275 })
276 },
277 )
278
279 test(
280 'a row the engine injects is kept whole over the plugins they installed',
281 { plugins: [Fixtures.blankingRows] },
282 async ($, on) => {
283 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
284
285 expect(await $.session.append(Fixtures.HOOK_CONTEXT_ROW)).toMatchObject({
286 message: { content: Fixtures.HOOK_CONTEXT_ROW.message.content },
287 })
288 expect(await $.session.append(Fixtures.REMINDER_ROW)).toMatchObject({
289 message: { content: Fixtures.REMINDER_ROW.message.content },
290 })
291 },
292 )
293
294 test(
295 'any other row is theirs to shape as before',
296 { plugins: [Fixtures.blankingRows] },
297 async ($, on) => {
298 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
299
300 expect(await $.session.append(Fixtures.PROMPT_ROW)).not.toMatchObject({
301 message: { content: Fixtures.PROMPT_ROW.message.content },
302 })
303 },
304 )
305
306 test(
307 "an organization plugin's note is not theirs to blank; their own is",
308 {
309 plugins: [
310 Fixtures.blankingRows,
311 Fixtures.noting('mine'),
312 Fixtures.noting('suite', 'append'),
313 ],
314 },
315 async ($, on) => {
316 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
317 on('session.start', ($, e) => ({ cwd: e.cwd }))
318
319 const kept: string[] = []
320
321 on('ui.log', ($, e, next) => {
322 kept.push(`${next.origin.plugin} kept ${e.text}`)
323
324 return { value: undefined }
325 })
326
327 await $.session.start(Fixtures.SESSION)
328
329 expect(kept.toSorted()).toEqual([
330 'mine kept []',
331 'suite kept [{"type":"text","text":"a note"}]',
332 ])
333 },
334 )
335
336 test(
337 "the system prompt's sections pass over the plugins the person installed",
338 { plugins: [Fixtures.emptying, Fixtures.heading] },
339 async ($, on) => {
340 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
341
342 on('prompt.compose', () => ({
343 sections: [{ id: 'body', text: 'the body', scope: 'shared' }],
344 }))
345
346 expect(await $.prompt.compose(Fixtures.COMPOSED)).toEqual({
347 sections: [
348 { id: 'heading:org', text: 'the org says hi', scope: 'shared' },
349 { id: 'body', text: 'the body', scope: 'shared' },
350 ],
351 })
352 },
353 )
354
355 test(
356 "nor does a person's plugin drop or reword a section it asked for",
357 { plugins: [Fixtures.rewording, Fixtures.heading] },
358 async ($, on) => {
359 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
360
361 on('prompt.compose', () => ({
362 sections: [{ id: 'body', text: 'the body', scope: 'shared' }],
363 }))
364
365 expect(await $.prompt.compose(Fixtures.COMPOSED)).toEqual({
366 sections: [
367 { id: 'heading:org', text: 'the org says hi', scope: 'shared' },
368 { id: 'body', text: 'the body', scope: 'shared' },
369 ],
370 })
371 },
372 )
373
374 test(
375 "a user plugin's rewrite of policy is skipped for every other reader",
376 {
377 plugins: [
378 Fixtures.stripping,
379 Fixtures.reading,
380 Fixtures.registering('mine'),
381 ],
382 },
383 async ($, on) => {
384 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
385
386 const registered = Fixtures.toolsRegistered(on)
387 const { text } = await $.command.run(Fixtures.POLICY_COMMAND)
388
389 await $.session.start(Fixtures.SESSION)
390
391 expect(
392 JSON.parse(text ?? 'null'),
393 "another user plugin's read sees the allowlist the stripper hides",
394 ).toEqual(Fixtures.MANAGED_POLICY)
395
396 expect(
397 registered,
398 "sec-default's own tool.register hook still reads the allowlist",
399 ).toEqual([])
400 },
401 )
402
403 test(
404 "an organization provider's subject passes over the user plugins",
405 { plugins: [Fixtures.marking] },
406 async ($, on) => {
407 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
408 Fixtures.subjectsEchoed(on)
409
410 for (const provider of Fixtures.ORG_PROVIDERS) {
411 expect(
412 await $.tool.describe(
413 Fixtures.toolDescribed('mcp__corp__search', provider),
414 ),
415 ).toEqual({ description: 'd' })
416
417 expect(
418 (
419 await $.command.describe(
420 Fixtures.commandDescribed('suite:deploy', provider),
421 )
422 ).isHidden,
423 ).toBe(false)
424
425 expect(
426 await $.agent.offer(
427 Fixtures.agentOffered('suite:reviewer', provider),
428 ),
429 ).toEqual({ isOffered: true })
430
431 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
432 model: 'core',
433 })
434 }
435
436 for (const provider of Fixtures.USER_REACHABLE_PROVIDERS) {
437 expect(
438 await $.tool.describe(
439 Fixtures.toolDescribed('mcp__mine__search', provider),
440 ),
441 ).toEqual({ description: 'user: d' })
442
443 expect(
444 (
445 await $.command.describe(
446 Fixtures.commandDescribed('mine:deploy', provider),
447 )
448 ).isHidden,
449 ).toBe(true)
450
451 expect(
452 await $.agent.offer(Fixtures.agentOffered('reviewer', provider)),
453 ).toEqual({ isOffered: false })
454
455 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
456 model: 'user',
457 })
458 }
459 },
460 )
461
462 test(
463 'an odd provider passes over the user plugins: it fails closed',
464 { plugins: [Fixtures.marking] },
465 async ($, on) => {
466 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
467 Fixtures.subjectsEchoed(on)
468
469 for (const provider of Fixtures.ODD_PROVIDERS) {
470 expect(
471 await $.tool.describe(Fixtures.toolDescribed('Bash', provider)),
472 ).toEqual({ description: 'd' })
473
474 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
475 model: 'core',
476 })
477 }
478 },
479 )
480
481 test(
482 'a subject decision reads no policy; a burst of listings reads once',
483 { plugins: [Fixtures.listing] },
484 async ($, on) => {
485 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
486
487 Fixtures.subjectsEchoed(on)
488 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
489
490 for (const provider of Fixtures.ORG_PROVIDERS) {
491 await $.tool.describe(Fixtures.toolDescribed('mcp__corp__x', provider))
492 await $.agent.spawn(Fixtures.agentSpawned(provider))
493 }
494
495 expect(reads(), "one read: the person's plugin was admitted").toBe(1)
496
497 await Promise.all([
498 $.command.run(Fixtures.TOOLS_COMMAND),
499 $.command.run(Fixtures.TOOLS_COMMAND),
500 $.command.run(Fixtures.TOOLS_COMMAND),
501 ])
502
503 expect(reads()).toBe(2)
504 },
505 )
506
507 test(
508 'the refusal a user-tier caller reads names the allowlist',
509 {
510 plugins: [
511 {
512 name: 'asking',
513 register(on) {
514 on('command.run', { command: 'greet' }, $ =>
515 $.tool
516 .register({
517 name: 'greet',
518 description: 'Says hello.',
519 inputSchema: { type: 'object' },
520 })
521 .then(
522 () => ({ text: 'registered' }),
523 (error: unknown) => ({ text: String(error) }),
524 ),
525 )
526 },
527 },
528 ],
529 },
530 async ($, on) => {
531 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
532
533 const { text } = await $.command.run({
534 command: 'greet',
535 args: '',
536 origin: { kind: 'composer' },
537 presentation: Fixtures.FULLSCREEN,
538 })
539
540 expect(text).toEndWith(
541 `asking: $.tool.register: ${Hooks.TOOL_REGISTER_REFUSAL}`,
542 )
543 },
544 )
545
546 test(
547 "under allowManagedModsOnly a person's mod is kept out, told why",
548 { plugins: [Fixtures.registering('mine')] },
549 async ($, on) => {
550 on('settings.read', () => ({ value: Fixtures.MANAGED_MODS_ONLY }))
551
552 const registered = Fixtures.toolsRegistered(on)
553
554 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
555 Hooks.managedModsOnlyRefusal('mine'),
556 )
557
558 expect(registered, 'no hook of it ever ran').toEqual([])
559 },
560 )
561
562 test(
563 "under it the organization's mods and the built-ins load",
564 {
565 plugins: [
566 Fixtures.registering('suite', 'prepend'),
567 Fixtures.registering('after', 'append'),
568 Fixtures.registering('bundled', 'builtin'),
569 ],
570 },
571 async ($, on) => {
572 on('settings.read', () => ({ value: Fixtures.MANAGED_MODS_ONLY }))
573
574 const registered = Fixtures.toolsRegistered(on)
575
576 await $.session.start(Fixtures.SESSION)
577
578 expect(registered).toEqual(['suite', 'after', 'bundled'])
579 },
580 )
581
582 test(
583 'set to false, a mod the person installed loads as before',
584 { plugins: [Fixtures.registering('mine')] },
585 async ($, on) => {
586 on('settings.read', () => ({ value: Fixtures.modsPolicyOf(false) }))
587
588 const registered = Fixtures.toolsRegistered(on)
589
590 await $.session.start(Fixtures.SESSION)
591
592 expect(registered).toEqual(['mine'])
593 },
594 )
595
596 test(
597 "a person's copy under an organization mod's name is still theirs",
598 { plugins: [Fixtures.registering('suite')] },
599 async ($, on) => {
600 on('settings.read', () => ({
601 value: { ...Fixtures.MANAGED_POLICY, ...Fixtures.MANAGED_MODS_ONLY },
602 }))
603
604 const registered = Fixtures.toolsRegistered(on)
605
606 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
607 Hooks.managedModsOnlyRefusal('suite'),
608 )
609
610 expect(registered).toEqual([])
611 },
612 )
613
614 test(
615 "only managed settings are asked: a person's own cannot loosen it",
616 { plugins: [Fixtures.registering('mine')] },
617 async ($, on) => {
618 Fixtures.policyBySource(
619 on,
620 Fixtures.MANAGED_MODS_ONLY,
621 Fixtures.modsPolicyOf(false),
622 )
623
624 const registered = Fixtures.toolsRegistered(on)
625
626 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
627 Hooks.managedModsOnlyRefusal('mine'),
628 )
629
630 expect(registered).toEqual([])
631 },
632 )
633
634 test(
635 "nor turn it on: set only in a person's settings, it is not read",
636 { plugins: [Fixtures.registering('mine')] },
637 async ($, on) => {
638 Fixtures.policyBySource(
639 on,
640 Fixtures.NO_ALLOWLIST,
641 Fixtures.MANAGED_MODS_ONLY,
642 )
643
644 const registered = Fixtures.toolsRegistered(on)
645
646 await $.session.start(Fixtures.SESSION)
647
648 expect(registered).toEqual(['mine'])
649 },
650 )
651
652 test(
653 "a policy that cannot be read keeps a person's mod out: the hook's catch",
654 { plugins: [Fixtures.registering('mine')] },
655 async ($, on) => {
656 on('settings.read', () => ({ deny: 'managed settings unreadable' }))
657
658 const lines = Fixtures.logged(on)
659 const registered = Fixtures.toolsRegistered(on)
660
661 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
662 Hooks.managedModsOnlyRefusal('mine'),
663 )
664
665 expect({ registered, lines }).toEqual({
666 registered: [],
667 lines: [
668 'debug: plugin.register hook failed judging mine (throw): ' +
669 'sec-default: $.settings.read: managed settings unreadable',
670 ],
671 })
672 },
673 )
674
675 test(
676 'a deny rule holds over an allow from a plugin the person installed',
677 { plugins: [Fixtures.allowing('easy')] },
678 async ($, on) => {
679 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
680
681 const lines = Fixtures.logged(on)
682
683 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
684
685 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
686
687 expect(lines).toEqual([
688 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.RULE_DENY, 'lift')}`,
689 ])
690 },
691 )
692
693 test(
694 'two plugins of the person chained are each named once in a session',
695 {
696 plugins: [Fixtures.allowing('first'), Fixtures.asking('second')],
697 },
698 async ($, on) => {
699 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
700
701 const lines = Fixtures.logged(on)
702
703 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
704
705 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
706 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
707
708 expect(lines.toSorted()).toEqual([
709 `transcript: ${Hooks.heldNotice('first', 'Bash', Fixtures.RULE_DENY, 'lift')}`,
710 `transcript: ${Hooks.heldNotice('second', 'Bash', Fixtures.RULE_DENY, 'lift')}`,
711 ])
712 },
713 )
714
715 test(
716 'a deny rule turned into an ask by a plugin of the person holds too',
717 { plugins: [Fixtures.asking('easy')] },
718 async ($, on) => {
719 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
720 Fixtures.logged(on)
721 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
722
723 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
724 },
725 )
726
727 test(
728 "an organization plugin's allow over a deny rule stands, above or below",
729 {
730 plugins: [
731 Fixtures.allowing('suite', 'append'),
732 Fixtures.allowing('easy'),
733 ],
734 },
735 async ($, on) => {
736 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
737
738 const lines = Fixtures.logged(on)
739
740 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
741
742 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
743 expect(lines).toEqual([])
744 },
745 )
746
747 test(
748 "a prepended organization plugin's allow over a deny rule stands",
749 { plugins: [Fixtures.allowing('guard', 'prepend')] },
750 async ($, on) => {
751 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
752
753 const lines = Fixtures.logged(on)
754
755 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
756
757 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
758 expect(lines).toEqual([])
759 },
760 )
761
762 test(
763 "a built-in's allow over a deny rule stands",
764 { plugins: [Fixtures.allowing('bundled', 'builtin')] },
765 async ($, on) => {
766 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
767
768 const lines = Fixtures.logged(on)
769
770 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
771
772 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
773 expect(lines).toEqual([])
774 },
775 )
776
777 test(
778 'an ask rule holds over an allow from a plugin the person installed',
779 { plugins: [Fixtures.allowing('easy')] },
780 async ($, on) => {
781 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
782
783 const lines = Fixtures.logged(on)
784
785 Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
786
787 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK)
788
789 expect(lines).toEqual([
790 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.RULE_ASK, 'lift')}`,
791 ])
792 },
793 )
794
795 test(
796 "a classic hook's ask holds over an allow from a plugin of the person",
797 { plugins: [Fixtures.allowing('easy')] },
798 async ($, on) => {
799 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
800
801 const lines = Fixtures.logged(on)
802
803 Fixtures.checksAnswered(on, Fixtures.HOOK_ASK)
804
805 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.HOOK_ASK)
806
807 expect(lines).toEqual([
808 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.HOOK_ASK, 'lift')}`,
809 ])
810 },
811 )
812
813 test(
814 "the read block's ask on a shell read holds over their allow",
815 { plugins: [Fixtures.allowing('easy')] },
816 async ($, on) => {
817 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
818
819 const lines = Fixtures.logged(on)
820
821 Fixtures.checksAnswered(on, Fixtures.SETTING_ASK)
822
823 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.SETTING_ASK)
824
825 expect(lines).toEqual([
826 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.SETTING_ASK, 'lift')}`,
827 ])
828 },
829 )
830
831 test(
832 "the mode's own ask, where a host answers it, holds over their allow",
833 { plugins: [Fixtures.allowing('easy')] },
834 async ($, on) => {
835 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
836
837 const lines = Fixtures.logged(on)
838
839 Fixtures.checksAnswered(on, Fixtures.HOST_ASK)
840
841 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.HOST_ASK)
842
843 expect(lines).toEqual([
844 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.HOST_ASK, 'lift')}`,
845 ])
846 },
847 )
848
849 test(
850 "an organization plugin's allow over a host's ask stands",
851 { plugins: [Fixtures.allowing('corp', 'append')] },
852 async ($, on) => {
853 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
854 Fixtures.checksAnswered(on, Fixtures.HOST_ASK)
855
856 expect(await $.tool.check(Fixtures.CHECKED)).toEqual({
857 decision: 'allow',
858 })
859 },
860 )
861
862 test(
863 "a classic hook's deny holds over their allow",
864 { plugins: [Fixtures.allowing('easy')] },
865 async ($, on) => {
866 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
867
868 const lines = Fixtures.logged(on)
869
870 Fixtures.checksAnswered(on, Fixtures.HOOK_DENY)
871
872 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.HOOK_DENY)
873
874 expect(lines).toEqual([
875 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.HOOK_DENY, 'lift')}`,
876 ])
877 },
878 )
879
880 test(
881 "a classic hook's deny holds over their ask",
882 { plugins: [Fixtures.asking('easy')] },
883 async ($, on) => {
884 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
885 Fixtures.logged(on)
886 Fixtures.checksAnswered(on, Fixtures.HOOK_DENY)
887
888 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.HOOK_DENY)
889 },
890 )
891
892 test(
893 'an allow that never called next meets the ask rule all the same',
894 { plugins: [Fixtures.blindAllowing] },
895 async ($, on) => {
896 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
897 Fixtures.logged(on)
898
899 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
900
901 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK)
902 expect(evaluations()).toBe(1)
903 },
904 )
905
906 test(
907 "an organization plugin's allow over an ask rule stands",
908 {
909 plugins: [
910 Fixtures.allowing('suite', 'append'),
911 Fixtures.allowing('easy'),
912 ],
913 },
914 async ($, on) => {
915 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
916
917 const lines = Fixtures.logged(on)
918
919 Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
920
921 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
922 expect(lines).toEqual([])
923 },
924 )
925
926 test(
927 "an ask of theirs over an ask rule is the rule's ask again, whole",
928 { plugins: [Fixtures.asking('easy')] },
929 async ($, on) => {
930 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
931
932 const lines = Fixtures.logged(on)
933
934 Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
935
936 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK)
937
938 expect(lines).toEqual([
939 'transcript: ' +
940 Hooks.heldNotice('easy', 'Bash', Fixtures.RULE_ASK, 'reword'),
941 ])
942 },
943 )
944
945 test(
946 "a deny of theirs over a deny rule is the rule's deny again, whole",
947 { plugins: [Fixtures.tightening] },
948 async ($, on) => {
949 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
950
951 const lines = Fixtures.logged(on)
952
953 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
954
955 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
956
957 expect(lines).toEqual([
958 'transcript: ' +
959 Hooks.heldNotice('strict', 'Bash', Fixtures.RULE_DENY, 'reword'),
960 ])
961 },
962 )
963
964 test(
965 'an ask of theirs that says what it heard costs no second look',
966 { plugins: [Fixtures.asking('easy')] },
967 async ($, on) => {
968 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
969
970 const lines = Fixtures.logged(on)
971 const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED)
972
973 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ASKED)
974 expect({ lines, evaluations: evaluations() }).toEqual({
975 lines: [],
976 evaluations: 1,
977 })
978 },
979 )
980
981 test(
982 'the option that lets them override deny rules lets them override these',
983 { plugins: [Fixtures.allowing('easy')] },
984 async ($, on) => {
985 on('settings.read', () => ({ value: Fixtures.overridePolicyOf(true) }))
986
987 const lines = Fixtures.logged(on)
988
989 Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
990
991 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
992 expect(lines).toEqual([])
993 },
994 )
995
996 test(
997 "the mode's own ask, no rule or hook behind it, is theirs to allow",
998 { plugins: [Fixtures.allowing('easy')] },
999 async ($, on) => {
1000 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1001
1002 const lines = Fixtures.logged(on)
1003
1004 Fixtures.checksAnswered(on, Fixtures.ASKED)
1005
1006 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
1007 expect(lines).toEqual([])
1008 },
1009 )
1010
1011 test(
1012 'a deny holds whatever decided it: it may stand before a rule or a hook',
1013 { plugins: [Fixtures.allowing('easy')] },
1014 async ($, on) => {
1015 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1016
1017 const lines = Fixtures.logged(on)
1018
1019 Fixtures.checksAnswered(on, Fixtures.PLAIN_DENY)
1020
1021 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.PLAIN_DENY)
1022
1023 expect(lines).toEqual([
1024 `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.PLAIN_DENY, 'lift')}`,
1025 ])
1026 },
1027 )
1028
1029 test(
1030 'the notice is no door: a plugin of theirs never runs inside this hook',
1031 { plugins: [Fixtures.sneaking] },
1032 async ($, on) => {
1033 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1034
1035 const lines = Fixtures.logged(on)
1036
1037 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1038
1039 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1040
1041 expect(lines).toEqual([
1042 'transcript: ' +
1043 Hooks.heldNotice('sneaking', 'Bash', Fixtures.RULE_DENY, 'lift'),
1044 ])
1045 },
1046 )
1047
1048 test(
1049 'nor is the notice theirs to drop',
1050 { plugins: [Fixtures.muting] },
1051 async ($, on) => {
1052 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1053
1054 const lines = Fixtures.logged(on)
1055
1056 Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
1057
1058 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK)
1059
1060 expect(lines).toEqual([
1061 `transcript: ${Hooks.heldNotice('muting', 'Bash', Fixtures.RULE_ASK, 'lift')}`,
1062 ])
1063 },
1064 )
1065
1066 test(
1067 "an organization's line is not theirs to drop; a line of their own is",
1068 {
1069 plugins: [
1070 Fixtures.muting,
1071 Fixtures.logging('mine'),
1072 Fixtures.logging('bundled', 'builtin'),
1073 Fixtures.logging('suite', 'append'),
1074 ],
1075 },
1076 async ($, on) => {
1077 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1078 on('session.start', ($, e) => ({ cwd: e.cwd }))
1079
1080 const heard: string[] = []
1081
1082 on('ui.log', ($, e, next) => {
1083 heard.push(next.origin.plugin)
1084
1085 return { value: undefined }
1086 })
1087
1088 await $.session.start(Fixtures.SESSION)
1089
1090 expect(heard).toEqual(['suite'])
1091 },
1092 )
1093
1094 test(
1095 'each plugin is told of a kind, by the tool it answered on',
1096 { plugins: [Fixtures.allowingBash, Fixtures.allowingRead] },
1097 async ($, on) => {
1098 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1099
1100 const lines = Fixtures.logged(on)
1101
1102 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1103
1104 await $.tool.check(Fixtures.CHECKED)
1105 await $.tool.check(Fixtures.CHECKED_READ)
1106
1107 expect(lines).toEqual([
1108 `transcript: ${Hooks.heldNotice('basher', 'Bash', Fixtures.RULE_DENY, 'lift')}`,
1109 `transcript: ${Hooks.heldNotice('reader', 'Read', Fixtures.RULE_DENY, 'lift')}`,
1110 ])
1111 },
1112 )
1113
1114 test(
1115 "an organization's appended plugin has its say in the run past theirs",
1116 {
1117 plugins: [Fixtures.allowing('suite', 'append'), Fixtures.blindAllowing],
1118 },
1119 async ($, on) => {
1120 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1121
1122 const lines = Fixtures.logged(on)
1123
1124 Fixtures.checksAnswered(on, Fixtures.RULE_ASK)
1125
1126 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
1127 expect(lines).toEqual([])
1128 },
1129 )
1130
1131 test(
1132 'a plugin is told once of each kind of thing that held over it',
1133 { plugins: [Fixtures.allowing('easy')] },
1134 async ($, on) => {
1135 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1136
1137 const lines = Fixtures.logged(on)
1138 const verdicts = [
1139 Fixtures.RULE_DENY,
1140 Fixtures.RULE_ASK,
1141 Fixtures.RULE_ASK,
1142 Fixtures.HOOK_ASK,
1143 Fixtures.PLAIN_DENY,
1144 Fixtures.RULE_DENY,
1145 ]
1146 const turn = Fixtures.checksAnsweredInTurn(on, verdicts)
1147
1148 for (const verdict of verdicts) {
1149 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(verdict)
1150 turn()
1151 }
1152
1153 expect(lines).toEqual(
1154 [
1155 Fixtures.RULE_DENY,
1156 Fixtures.RULE_ASK,
1157 Fixtures.HOOK_ASK,
1158 Fixtures.PLAIN_DENY,
1159 ].map(
1160 held =>
1161 `transcript: ${Hooks.heldNotice('easy', 'Bash', held, 'lift')}`,
1162 ),
1163 )
1164 },
1165 )
1166
1167 test(
1168 'a plugin of the person that tightens is heard, with one evaluation',
1169 { plugins: [Fixtures.tightening] },
1170 async ($, on) => {
1171 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
1172 const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED)
1173
1174 await $.tool.check(Fixtures.CHECKED)
1175
1176 const loaded = { reads: reads(), evaluations: evaluations() }
1177
1178 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.PLAIN_DENY)
1179
1180 expect(
1181 {
1182 reads: reads() - loaded.reads,
1183 evaluations: evaluations() - loaded.evaluations,
1184 },
1185 'once its plugins have loaded, a check reads no policy',
1186 ).toEqual({ reads: 0, evaluations: 1 })
1187 },
1188 )
1189
1190 test(
1191 "a deny rule holds when an organization's plugin listens above theirs",
1192 {
1193 plugins: [
1194 Fixtures.listening('audit', 'prepend'),
1195 Fixtures.allowing('easy'),
1196 ],
1197 },
1198 async ($, on) => {
1199 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1200
1201 const lines = Fixtures.logged(on)
1202
1203 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1204
1205 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1206
1207 expect(
1208 lines.map(line => line.includes('easy')),
1209 'one line, naming the plugin of theirs, alone or in its batch',
1210 ).toEqual([true])
1211 },
1212 )
1213
1214 test(
1215 'a plugin of the person that only listens costs no second evaluation',
1216 { plugins: [Fixtures.listening('listening')] },
1217 async ($, on) => {
1218 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
1219 const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED)
1220
1221 await $.tool.check(Fixtures.CHECKED)
1222
1223 const loaded = { reads: reads(), evaluations: evaluations() }
1224
1225 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ASKED)
1226
1227 expect(
1228 {
1229 reads: reads() - loaded.reads,
1230 evaluations: evaluations() - loaded.evaluations,
1231 },
1232 'once its plugins have loaded, a check reads no policy',
1233 ).toEqual({ reads: 0, evaluations: 1 })
1234 },
1235 )
1236
1237 test('with none of their plugins the verdict passes once', async ($, on) => {
1238 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
1239 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1240
1241 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1242
1243 expect({ reads: reads(), evaluations: evaluations() }).toEqual({
1244 reads: 0,
1245 evaluations: 1,
1246 })
1247 })
1248
1249 test(
1250 'an allow that never called next meets the deny rule all the same',
1251 { plugins: [Fixtures.blindAllowing] },
1252 async ($, on) => {
1253 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1254
1255 const lines = Fixtures.logged(on)
1256 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1257
1258 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1259
1260 expect({ lines, evaluations: evaluations() }).toEqual({
1261 lines: [
1262 'transcript: ' +
1263 Hooks.heldNotice('blind', 'Bash', Fixtures.RULE_DENY, 'lift'),
1264 ],
1265 evaluations: 1,
1266 })
1267 },
1268 )
1269
1270 test(
1271 'a rule a plugin of the person writes into its answer is never read',
1272 { plugins: [Fixtures.forging] },
1273 async ($, on) => {
1274 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1275
1276 const lines = Fixtures.logged(on)
1277
1278 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1279
1280 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1281
1282 expect(lines).toEqual([
1283 'transcript: ' +
1284 Hooks.heldNotice('forging', 'Bash', Fixtures.RULE_DENY, 'lift'),
1285 ])
1286 },
1287 )
1288
1289 test(
1290 'a plugin of the person asking about another command is left out',
1291 { plugins: [Fixtures.rewriting] },
1292 async ($, on) => {
1293 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1294 Fixtures.logged(on)
1295
1296 const asked: unknown[] = []
1297
1298 on('tool.check', ($, e) => {
1299 asked.push(e.input)
1300
1301 return Fixtures.RULE_DENY
1302 })
1303
1304 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1305
1306 expect(
1307 asked,
1308 'the rules were asked about the command that would run, only',
1309 ).toEqual([Fixtures.CHECKED.input])
1310 },
1311 )
1312
1313 test(
1314 'managed settings may let the plugins a person installs override',
1315 { plugins: [Fixtures.allowing('easy')] },
1316 async ($, on) => {
1317 on('settings.read', () => ({ value: Fixtures.overridePolicyOf(true) }))
1318
1319 const lines = Fixtures.logged(on)
1320 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1321
1322 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
1323
1324 expect({ lines, evaluations: evaluations() }).toEqual({
1325 lines: [],
1326 evaluations: 1,
1327 })
1328 },
1329 )
1330
1331 test(
1332 "only managed settings are asked: a person's own cannot lift a deny rule",
1333 { plugins: [Fixtures.allowing('easy')] },
1334 async ($, on) => {
1335 Fixtures.policyBySource(
1336 on,
1337 Fixtures.MANAGED_POLICY,
1338 Fixtures.overridePolicyOf(true),
1339 )
1340
1341 Fixtures.logged(on)
1342 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1343
1344 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1345 },
1346 )
1347
1348 test(
1349 'the option mistyped lifts nothing: only the literal true does',
1350 { plugins: [Fixtures.allowing('easy')] },
1351 async ($, on) => {
1352 on('settings.read', () => ({ value: Fixtures.overridePolicyOf('true') }))
1353 Fixtures.logged(on)
1354 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1355
1356 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
1357 },
1358 )
1359
1360 test(
1361 'with a policy that cannot be read the deny rule holds: fails closed',
1362 { plugins: [Fixtures.allowing('easy')] },
1363 async ($, on) => {
1364 const stopPolicy = Fixtures.policyUntilStopped(
1365 on,
1366 Fixtures.overridePolicyOf(true),
1367 'managed settings unreadable',
1368 )
1369
1370 Fixtures.logged(on)
1371 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
1372 on('prompt.section', ($, e) => ({ text: e.text }))
1373
1374 await $.prompt.section(Fixtures.MEMORY)
1375 stopPolicy()
1376
1377 expect(
1378 await $.tool.check(Fixtures.CHECKED),
1379 'the policy that read let plugins override; unread, the rule holds',
1380 ).toEqual(Fixtures.RULE_DENY)
1381 },
1382 )
1383
1384 test(
1385 "when the rules cannot be evaluated the call is refused: the hook's catch",
1386 { plugins: [Fixtures.blindAllowing] },
1387 async ($, on) => {
1388 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
1389 Fixtures.logged(on)
1390
1391 on('tool.check', () => {
1392 throw new Error('the evaluation failed')
1393 })
1394
1395 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Hooks.UNCHECKED_DENY)
1396 },
1397 )
1398
1399 test('the refusal of a pinned variable names the setting and it', () => {
1400 expect(Hooks.pinnedVariableRefusal('CORP_PROXY')).toBe(
1401 'env (managed): CORP_PROXY is not for plugins outside policy to change',
1402 )
1403 })
1404
1405 test('a name managed env sets is pinned, in any case; no other is', () => {
1406 expect(
1407 ['CORP_PROXY', 'corp_proxy', 'Corp_Proxy', 'CORP', 'CORP_PROXY_2'].map(
1408 name => Hooks.isPinnedVariable(Fixtures.PINNING_POLICY, name),
1409 ),
1410 ).toEqual([true, true, true, false, false])
1411 })
1412
1413 test('whichever case managed env itself spells it in', () => {
1414 expect(
1415 ['CORP_PROXY', 'corp_proxy', 'CORP'].map(name =>
1416 Hooks.isPinnedVariable(Fixtures.LOWER_CASE_PINNING_POLICY, name),
1417 ),
1418 ).toEqual([true, true, false])
1419 })
1420
1421 test('a name managed env sets to nothing is pinned all the same', () => {
1422 expect(
1423 Hooks.isPinnedVariable({ env: { CORP_PROXY: '' } }, 'CORP_PROXY'),
1424 ).toBe(true)
1425 })
1426
1427 test('settings with no env pin nothing', () => {
1428 expect(
1429 [Fixtures.MANAGED_POLICY, {}, { env: {} }].map(policy =>
1430 Hooks.isPinnedVariable(policy, 'CORP_PROXY'),
1431 ),
1432 ).toEqual([false, false, false])
1433 })
1434
1435 test(
1436 'a variable managed settings pin is not for a plugin of the person to set',
1437 {
1438 plugins: [
1439 Fixtures.settingProxy('suite', 'prepend'),
1440 Fixtures.settingProxy('mine'),
1441 Fixtures.settingProxy('bundled', 'builtin'),
1442 ],
1443 },
1444 async ($, on) => {
1445 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1446
1447 const lines = Fixtures.logged(on)
1448 const set = Fixtures.variablesSet(on)
1449
1450 await $.session.start(Fixtures.SESSION)
1451
1452 expect(set).toEqual(['suite CORP_PROXY=mine', 'bundled CORP_PROXY=mine'])
1453 expect(lines).toHaveLength(1)
1454 expect(lines[0]).toContain(Hooks.pinnedVariableRefusal('CORP_PROXY'))
1455 },
1456 )
1457
1458 test(
1459 'nor to unset',
1460 { plugins: [Fixtures.unsettingProxy] },
1461 async ($, on) => {
1462 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1463
1464 const set = Fixtures.variablesSet(on)
1465
1466 await $.session.start(Fixtures.SESSION)
1467
1468 expect(set).toEqual([])
1469 },
1470 )
1471
1472 test(
1473 'nor under another case, which some systems read as the same name',
1474 { plugins: [Fixtures.settingLowerCase] },
1475 async ($, on) => {
1476 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1477 Fixtures.logged(on)
1478
1479 const set = Fixtures.variablesSet(on)
1480
1481 await $.session.start(Fixtures.SESSION)
1482
1483 expect(set).toEqual([])
1484 },
1485 )
1486
1487 test(
1488 "what an organization's plugin reads is not theirs to answer",
1489 {
1490 plugins: [
1491 Fixtures.answeringReads,
1492 Fixtures.readingProxy('mine'),
1493 Fixtures.readingProxy('suite', 'append'),
1494 Fixtures.readingProxy('guard', 'prepend'),
1495 ],
1496 },
1497 async ($, on) => {
1498 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1499 on('session.start', ($, e) => ({ cwd: e.cwd }))
1500 on('env.get', () => ({ value: 'as the engine holds it' }))
1501
1502 const lines = Fixtures.loggedBy(on)
1503
1504 await $.session.start(Fixtures.SESSION)
1505
1506 expect(lines.toSorted()).toEqual([
1507 'guard read as the engine holds it',
1508 'mine read theirs',
1509 'suite read as the engine holds it',
1510 ])
1511 },
1512 )
1513
1514 test(
1515 "nor to rewrite what an organization's plugin sets, pinned or not",
1516 {
1517 plugins: [
1518 Fixtures.revaluing,
1519 Fixtures.settingProxy('suite', 'append'),
1520 Fixtures.settingOther('audit', 'append'),
1521 Fixtures.settingOther('guard', 'prepend'),
1522 ],
1523 },
1524 async ($, on) => {
1525 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1526
1527 const set = Fixtures.variablesSet(on)
1528
1529 await $.session.start(Fixtures.SESSION)
1530
1531 expect(set.toSorted()).toEqual([
1532 'audit OTHER=mine',
1533 'guard OTHER=mine',
1534 'suite CORP_PROXY=mine',
1535 ])
1536 },
1537 )
1538
1539 test(
1540 "an organization's write waits on no policy read, so none can fail it",
1541 {
1542 plugins: [Fixtures.revaluing, Fixtures.settingOther('audit', 'append')],
1543 },
1544 async ($, on) => {
1545 const stopPolicy = Fixtures.policyUntilStopped(
1546 on,
1547 Fixtures.MANAGED_POLICY,
1548 'managed settings unreadable',
1549 )
1550
1551 Fixtures.logged(on)
1552
1553 on('prompt.section', ($, e) => ({ text: e.text }))
1554
1555 const set = Fixtures.variablesSet(on)
1556
1557 await $.prompt.section(Fixtures.MEMORY)
1558 stopPolicy()
1559 await $.session.start(Fixtures.SESSION)
1560
1561 expect(set).toEqual(['audit OTHER=mine'])
1562 },
1563 )
1564
1565 test(
1566 "a built-in's write of a variable nobody pins still passes their hooks",
1567 {
1568 plugins: [
1569 Fixtures.revaluing,
1570 Fixtures.settingOther('bundled', 'builtin'),
1571 ],
1572 },
1573 async ($, on) => {
1574 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1575
1576 const set = Fixtures.variablesSet(on)
1577
1578 await $.session.start(Fixtures.SESSION)
1579
1580 expect(set).toEqual(['bundled OTHER=theirs'])
1581 },
1582 )
1583
1584 test(
1585 'the option that lets them override deny rules unpins nothing',
1586 { plugins: [Fixtures.settingProxy('mine')] },
1587 async ($, on) => {
1588 on('settings.read', () => ({
1589 value: {
1590 ...Fixtures.overridePolicyOf(true),
1591 ...Fixtures.PINNING_POLICY,
1592 },
1593 }))
1594 Fixtures.logged(on)
1595
1596 const set = Fixtures.variablesSet(on)
1597
1598 await $.session.start(Fixtures.SESSION)
1599
1600 expect(set).toEqual([])
1601 },
1602 )
1603
1604 test(
1605 'a variable managed settings do not pin is theirs to set',
1606 { plugins: [Fixtures.settingOther('mine')] },
1607 async ($, on) => {
1608 on('settings.read', () => ({ value: Fixtures.PINNING_POLICY }))
1609
1610 const set = Fixtures.variablesSet(on)
1611
1612 await $.session.start(Fixtures.SESSION)
1613
1614 expect(set).toEqual(['mine OTHER=mine'])
1615 },
1616 )
1617
1618 test(
1619 "only managed settings pin: a person's own env binds no plugin",
1620 { plugins: [Fixtures.settingProxy('mine')] },
1621 async ($, on) => {
1622 Fixtures.policyBySource(
1623 on,
1624 Fixtures.MANAGED_POLICY,
1625 Fixtures.PINNING_POLICY,
1626 )
1627
1628 const set = Fixtures.variablesSet(on)
1629
1630 await $.session.start(Fixtures.SESSION)
1631
1632 expect(set).toEqual(['mine CORP_PROXY=mine'])
1633 },
1634 )
1635
1636 test(
1637 'with a policy that cannot be read they set no variable: fails closed',
1638 { plugins: [Fixtures.settingOther('mine')] },
1639 async ($, on) => {
1640 const stopPolicy = Fixtures.policyUntilStopped(
1641 on,
1642 Fixtures.MANAGED_POLICY,
1643 'managed settings unreadable',
1644 )
1645
1646 Fixtures.logged(on)
1647
1648 on('prompt.section', ($, e) => ({ text: e.text }))
1649
1650 const set = Fixtures.variablesSet(on)
1651
1652 await $.prompt.section(Fixtures.MEMORY)
1653 stopPolicy()
1654 await $.session.start(Fixtures.SESSION)
1655
1656 expect(set).toEqual([])
1657 },
1658 )
1659
1660 test("a server's own name, and any name under its tools' prefix", () => {
1661 expect(
1662 ['corp', 'corp__x', 'corp__x__y', 'corp._x'].map(plugin =>
1663 Hooks.namesOrgTool(Fixtures.SERVER_POLICY, plugin, 'greet'),
1664 ),
1665 ).toEqual([true, true, true, true])
1666 })
1667
1668 test('a name that only begins like one is no server of theirs', () => {
1669 expect(
1670 ['corporate', 'corpx', 'x__corp', 'x-corp', 'mine'].map(plugin =>
1671 Hooks.namesOrgTool(Fixtures.SERVER_POLICY, plugin, 'greet'),
1672 ),
1673 ).toEqual([false, false, false, false, false])
1674 })
1675
1676 test('another case or other separators spell the same server', () => {
1677 expect(
1678 ['Corp', 'CORP', 'corp_x', 'corp-x', 'corp.x', '_corp_'].map(plugin =>
1679 Hooks.namesOrgTool(Fixtures.SERVER_POLICY, plugin, 'greet'),
1680 ),
1681 ).toEqual([true, true, true, true, true, true])
1682 })
1683
1684 test('a claude.ai server with a run of spaces folds as its tools do', () => {
1685 expect(
1686 ['mcp__claude_ai_tools__x', 'mcp__claude_ai__tools__x'].map(tool =>
1687 Hooks.isOrgTool(
1688 { managedMcpServers: { 'claude.ai tools': {} } },
1689 tool,
1690 ),
1691 ),
1692 ).toEqual([true, true])
1693 })
1694
1695 test('a plugin and its tool that spell a server together count too', () => {
1696 expect(
1697 [
1698 ['corp', 'prod__deploy'],
1699 ['corp', 'deploy'],
1700 ['corp_tools', 'greet'],
1701 ['corp', 'tools__greet'],
1702 ].map(([plugin = '', tool = '']) =>
1703 Hooks.namesOrgTool(
1704 { managedMcpServers: { corp__prod: {}, 'corp.tools': {} } },
1705 plugin,
1706 tool,
1707 ),
1708 ),
1709 ).toEqual([true, false, true, true])
1710 })
1711
1712 test("a seated plugin's own servers are the organization's", () => {
1713 expect([
1714 Hooks.namesOrgTool(
1715 Fixtures.SEATED_SUITE,
1716 'plugin_corp-suite_corp-jira',
1717 'create_ticket',
1718 ),
1719 Hooks.namesOrgTool(Fixtures.SEATED_SUITE, 'Plugin.Corp_Suite.x', 'y'),
1720 Hooks.isOrgTool(
1721 Fixtures.SEATED_SUITE,
1722 'mcp__plugin_corp-suite_corp-jira__create_ticket',
1723 ),
1724 ]).toEqual([true, true, true])
1725 })
1726
1727 test('a seated plugin is told in any case, as the engine seats it', () => {
1728 const listed = { prependPlugins: ['Corp-Suite@market'] }
1729
1730 expect([
1731 Hooks.isOrgTool(listed, 'mcp__plugin_corp-suite_corp-jira__x'),
1732 Hooks.isOrgTool(listed, 'mcp__corp-suite__greet'),
1733 Hooks.isOrgTool(Fixtures.SEATED_SUITE, 'mcp__plugin_Corp-Suite_j__x'),
1734 Hooks.isOrgTool(listed, 'mcp__plugin_corp-suites_j__x'),
1735 Hooks.isOrgTool(Fixtures.SERVER_POLICY, 'mcp__Corp__search'),
1736 ]).toEqual([true, true, true, false, false])
1737 })
1738
1739 test('an entry that pins versions turns its plugin on, as true does', () => {
1740 const pinned = { enabledPlugins: { 'corp-suite@market': ['^1.0.0'] } }
1741 const off = { enabledPlugins: { 'corp-suite@market': false } }
1742
1743 expect([
1744 Hooks.namesOrgTool(pinned, 'corp-suite', 'greet'),
1745 Hooks.isOrgTool(pinned, 'mcp__corp-suite__greet'),
1746 Hooks.namesOrgTool(off, 'corp-suite', 'greet'),
1747 Hooks.namesOrgTool(pinned, 'mine', 'greet'),
1748 ]).toEqual([true, true, false, false])
1749 })
1750
1751 test('a name in the other normalization form is the same name', () => {
1752 const policy = { prependPlugins: ['caf\u00e9-suite@market'] }
1753
1754 expect([
1755 Hooks.namesOrgTool(policy, 'cafe\u0301-suite', 'x'),
1756 Hooks.isOrgTool(policy, 'mcp__plugin_cafe\u0301-suite_jira__x'),
1757 Hooks.isOrgTool(policy, 'mcp__cafe\u0301-suite__x'),
1758 ]).toEqual([true, true, true])
1759 })
1760
1761 test('only the id managed settings turn on keeps its own name', () => {
1762 const policy = {
1763 enabledPlugins: { 'corp-guard@corp-market': true },
1764 appendPlugins: ['corp-guard@corp-market'],
1765 }
1766 const asked = (id?: string) =>
1767 Hooks.namesOrgTool(policy, 'corp-guard', 'x', id)
1768
1769 expect([
1770 asked('corp-guard@corp-market'),
1771 asked('Corp-Guard@Corp-Market'),
1772 asked('corp-guard@inline'),
1773 asked('corp-guard@elsewhere'),
1774 asked('corp_guard@corp-market'),
1775 asked(),
1776 Hooks.namesOrgTool(
1777 { ...policy, managedMcpServersUnreadable: true },
1778 'corp-guard',
1779 'x',
1780 'corp-guard@corp-market',
1781 ),
1782 Hooks.namesOrgTool({}, 'corp-guard', 'x', 'corp-guard@inline'),
1783 ]).toEqual([false, false, true, true, true, true, true, false])
1784 })
1785
1786 test('an accented name is told as the engine spells it in a tool', () => {
1787 const composed = { prependPlugins: ['caf\u00e9-suite@market'] }
1788 const decomposed = { prependPlugins: ['cafe\u0301-suite@market'] }
1789
1790 expect([
1791 Hooks.isOrgTool(composed, 'mcp__caf_-suite__x'),
1792 Hooks.isOrgTool(composed, 'mcp__cafe_-suite__x'),
1793 Hooks.isOrgTool(decomposed, 'mcp__caf_-suite__x'),
1794 Hooks.isOrgTool(decomposed, 'mcp__cafe_-suite__x'),
1795 Hooks.isOrgTool(composed, 'mcp__plugin_caf_-suite_jira__x'),
1796 Hooks.namesOrgTool(composed, 'caf.-suite', 'x'),
1797 Hooks.namesOrgTool(composed, 'cafe\u0301-suite', 'x'),
1798 Hooks.namesOrgTool(decomposed, 'caf\u00e9-suite', 'x'),
1799 ]).toEqual([true, true, true, true, true, true, true, true])
1800 })
1801
1802 test('a combining mark on a plain letter does not part a name', () => {
1803 const decomposed = { prependPlugins: ['cafe\u0301-suite@market'] }
1804
1805 expect([
1806 Hooks.namesOrgTool(Fixtures.SEATED_SUITE, 'corp-suite\u0301', 'x'),
1807 Hooks.isOrgTool(
1808 Fixtures.SEATED_SUITE,
1809 'mcp__plugin_corp-suite\u0301_jira__x',
1810 ),
1811 Hooks.namesOrgTool(decomposed, 'cafe\u0301-suite', 'x'),
1812 Hooks.isOrgTool(decomposed, 'mcp__cafe\u0301-suite__x'),
1813 ]).toEqual([true, true, true, true])
1814 })
1815
1816 test('a name in plain letters folds exactly as before', () => {
1817 expect(
1818 ['Corp__Tools', 'corp-tools', 'corp.tools', 'CORP TOOLS'].map(
1819 Hooks.toolPrefixOf,
1820 ),
1821 ).toEqual([
1822 'mcp_corp_tools_',
1823 'mcp_corp_tools_',
1824 'mcp_corp_tools_',
1825 'mcp_corp_tools_',
1826 ])
1827 })
1828
1829 test("a name unlike a seated plugin's servers is nobody else's", () => {
1830 expect([
1831 Hooks.namesOrgTool(Fixtures.SEATED_SUITE, 'mine', 'greet'),
1832 Hooks.namesOrgTool(Fixtures.SEATED_SUITE, 'plugin_mine_jira', 'x'),
1833 Hooks.namesOrgTool(Fixtures.SEATED_SUITE, 'plugin_corp-suites', 'x'),
1834 Hooks.isOrgTool(Fixtures.SEATED_SUITE, 'mcp__plugin_mine_jira__x'),
1835 Hooks.isOrgTool(Fixtures.SEATED_SUITE, 'mcp__plugin_corp-suites_j__x'),
1836 Hooks.isOrgTool(Fixtures.SEATED_SUITE, 'mcp__mine__greet'),
1837 ]).toEqual([false, false, false, false, false, false])
1838 })
1839
1840 test('a server the allowlist names counts as one it delivers does', () => {
1841 expect(
1842 [Fixtures.ALLOWLIST, Fixtures.NO_ALLOWLIST, {}].map(policy =>
1843 Hooks.namesOrgTool(policy, 'corp__x', 'greet'),
1844 ),
1845 ).toEqual([true, false, false])
1846 })
1847
1848 test('a server named with a dot or a space owns its tools', () => {
1849 expect(
1850 ['mcp__corp_tools__x', 'mcp__my_wiki__x', 'mcp__corp__x'].map(tool =>
1851 Hooks.isOrgTool(
1852 { managedMcpServers: { 'corp.tools': {}, 'my wiki': {} } },
1853 tool,
1854 ),
1855 ),
1856 ).toEqual([true, true, false])
1857 })
1858
1859 test("an organization's ask cap holds over a plugin's allow", () => {
1860 expect(Hooks.holdsOver(Fixtures.CEILING_ASK, Fixtures.CEILING_ALLOW)).toBe(
1861 true,
1862 )
1863 })
1864
1865 test('the launcher variable is pinned where policy names a launcher', () => {
1866 expect(
1867 [
1868 'CLAUDE_CODE_PROCESS_WRAPPER',
1869 'claude_code_process_wrapper',
1870 'CORP_PROXY',
1871 ].map(name => Hooks.isPinnedVariable(Fixtures.WRAPPING_POLICY, name)),
1872 ).toEqual([true, true, false])
1873 })
1874
1875 test('a server whose name folds to nothing refuses every name', () => {
1876 expect(
1877 ['mine', 'corp', 'x__y'].map(plugin =>
1878 Hooks.namesOrgTool(Fixtures.UNFOLDABLE_POLICY, plugin, 'greet'),
1879 ),
1880 ).toEqual([true, true, true])
1881 })
1882
1883 test("a server's tools are told by its name whole, as the engine spells it", () => {
1884 expect(
1885 ['mcp__corp__x', 'mcp__corp-tools__x', 'mcp__Corp__x', 'mcp__--__x'].map(
1886 tool =>
1887 Hooks.isOrgTool({ managedMcpServers: { corp: {}, '--': {} } }, tool),
1888 ),
1889 ).toEqual([true, false, false, true])
1890 })
1891
1892 test("a server named corp does not claim a corp-tools server's tools", () => {
1893 expect(
1894 Hooks.isOrgTool(
1895 { managedMcpServers: { corp: {} } },
1896 'mcp__corp-tools__x',
1897 ),
1898 ).toBe(false)
1899 })
1900
1901 test(
1902 'a compaction is not theirs to answer',
1903 { plugins: [Fixtures.compacting] },
1904 async ($, on) => {
1905 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
1906 on('session.compact', ($, e) => ({ messages: e.messages }))
1907
1908 expect(
1909 await $.session.compact({
1910 trigger: 'plugin',
1911 messages: [Fixtures.COMPACTED_TURN],
1912 }),
1913 ).toEqual({ messages: [Fixtures.COMPACTED_TURN] })
1914 },
1915 )
1916
1917 test("a tool whose own name folds to nothing reads as the server's too", () => {
1918 expect(
1919 [
1920 ['Corp', '-'],
1921 ['Corp', '_'],
1922 ['other', '-'],
1923 ].map(([plugin = '', tool = '']) =>
1924 Hooks.namesOrgTool({ managedMcpServers: { corp: {} } }, plugin, tool),
1925 ),
1926 ).toEqual([true, true, false])
1927 })
1928
1929 test("an organization's own plugins' names are refused like its servers'", () => {
1930 const policy = {
1931 prependPlugins: ['corp-guard@market'],
1932 appendPlugins: ['corp-audit@market', 'plain'],
1933 }
1934
1935 expect(
1936 [
1937 ['Corp_Audit', 'x'],
1938 ['corp.guard', 'x'],
1939 ['PLAIN', 'x'],
1940 ['mine', 'x'],
1941 ].map(([plugin = '', tool = '']) =>
1942 Hooks.namesOrgTool(policy, plugin, tool),
1943 ),
1944 ).toEqual([true, true, true, false])
1945 expect(
1946 ['mcp__corp-audit__x', 'mcp__plain__x', 'mcp__mine__x'].map(tool =>
1947 Hooks.isOrgTool(policy, tool),
1948 ),
1949 ).toEqual([true, true, false])
1950 })
1951
1952 test('an unreadable server file refuses every name and owns every server tool', () => {
1953 const policy = { managedMcpServersUnreadable: true }
1954
1955 expect(Hooks.namesOrgTool(policy, 'mine', 'greet')).toBe(true)
1956 expect(
1957 ['mcp__any__x', 'Bash'].map(tool => Hooks.isOrgTool(policy, tool)),
1958 ).toEqual([true, false])
1959 expect(Hooks.isPinnedVariable(policy, 'CORP_PROXY')).toBe(false)
1960 })
1961
1962 test(
1963 "a compaction's summary is kept whole over the plugins they installed",
1964 { plugins: [Fixtures.blankingRows] },
1965 async ($, on) => {
1966 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
1967
1968 expect(await $.session.append(Fixtures.COMPACTION_ROW)).toMatchObject({
1969 message: { content: Fixtures.COMPACTION_ROW.message.content },
1970 })
1971 },
1972 )
1973
1974 test("a plugin managed settings turn on is the organization's by name too", () => {
1975 const policy = {
1976 enabledPlugins: {
1977 'corp-guard@corp-market': true,
1978 'left-off@corp-market': false,
1979 'diff@builtin': true,
1980 },
1981 }
1982
1983 expect(
1984 ['Corp_Guard', 'left-off', 'diff', 'mine'].map(plugin =>
1985 Hooks.namesOrgTool(policy, plugin, 'x'),
1986 ),
1987 ).toEqual([true, false, false, false])
1988 expect(
1989 ['mcp__corp-guard__x', 'mcp__left-off__x'].map(tool =>
1990 Hooks.isOrgTool(policy, tool),
1991 ),
1992 ).toEqual([true, false])
1993 })
1994
1995 test(
1996 "a skill the Skill tool hands over is kept whole; another tool's row is theirs",
1997 { plugins: [Fixtures.blankingRows] },
1998 async ($, on) => {
1999 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
2000
2001 expect(await $.session.append(Fixtures.SKILL_ROW)).toMatchObject({
2002 message: { content: Fixtures.SKILL_ROW.message.content },
2003 })
2004 expect(
2005 await $.session.append(Fixtures.READ_MESSAGE_ROW),
2006 ).not.toMatchObject({
2007 message: { content: Fixtures.READ_MESSAGE_ROW.message.content },
2008 })
2009 },
2010 )
2011
2012 test(
2013 "the organization's own plugin in the user tier keeps its name",
2014 {
2015 plugins: [
2016 Fixtures.registering('corp-guard'),
2017 Fixtures.registering('mine'),
2018 ],
2019 },
2020 async ($, on) => {
2021 on('settings.read', () => ({
2022 value: { enabledPlugins: { 'corp-guard@claude-plugin-test': true } },
2023 }))
2024
2025 const registered = Fixtures.toolsRegistered(on)
2026
2027 await $.session.start(Fixtures.SESSION)
2028
2029 expect(registered).toEqual(['corp-guard', 'mine'])
2030 },
2031 )
2032
2033 test(
2034 'and keeps it when a version list turns it on',
2035 {
2036 plugins: [
2037 Fixtures.registering('corp-guard'),
2038 Fixtures.registering('mine'),
2039 ],
2040 },
2041 async ($, on) => {
2042 on('settings.read', () => ({
2043 value: {
2044 enabledPlugins: { 'corp-guard@claude-plugin-test': ['^1.0.0'] },
2045 },
2046 }))
2047
2048 const registered = Fixtures.toolsRegistered(on)
2049
2050 await $.session.start(Fixtures.SESSION)
2051
2052 expect(registered).toEqual(['corp-guard', 'mine'])
2053 },
2054 )
2055
2056 test(
2057 'an id in another letter case is the same id, as the engine folds one',
2058 {
2059 plugins: [
2060 Fixtures.registering('corp-guard'),
2061 Fixtures.registering('mine'),
2062 ],
2063 },
2064 async ($, on) => {
2065 on('settings.read', () => ({
2066 value: { enabledPlugins: { 'Corp-Guard@Claude-Plugin-Test': true } },
2067 }))
2068
2069 const registered = Fixtures.toolsRegistered(on)
2070
2071 await $.session.start(Fixtures.SESSION)
2072
2073 expect(registered).toEqual(['corp-guard', 'mine'])
2074 },
2075 )
2076
2077 test(
2078 'an id listed only for its place exempts nobody',
2079 {
2080 plugins: [
2081 Fixtures.registering('corp-guard'),
2082 Fixtures.registering('mine'),
2083 ],
2084 },
2085 async ($, on) => {
2086 on('settings.read', () => ({
2087 value: { prependPlugins: ['corp-guard@claude-plugin-test'] },
2088 }))
2089
2090 const registered = Fixtures.toolsRegistered(on)
2091
2092 await $.session.start(Fixtures.SESSION)
2093
2094 expect(registered).toEqual(['mine'])
2095 },
2096 )
2097
2098 test(
2099 'an id managed settings turn off exempts nobody',
2100 {
2101 plugins: [
2102 Fixtures.registering('corp-guard'),
2103 Fixtures.registering('mine'),
2104 ],
2105 },
2106 async ($, on) => {
2107 on('settings.read', () => ({
2108 value: {
2109 enabledPlugins: { 'corp-guard@claude-plugin-test': false },
2110 appendPlugins: ['corp-guard@claude-plugin-test'],
2111 },
2112 }))
2113
2114 const registered = Fixtures.toolsRegistered(on)
2115
2116 await $.session.start(Fixtures.SESSION)
2117
2118 expect(registered).toEqual(['mine'])
2119 },
2120 )
2121
2122 test(
2123 "a plugin whose name only folds to the organization's is refused",
2124 {
2125 plugins: [
2126 Fixtures.registering('corp--guard'),
2127 Fixtures.registering('mine'),
2128 ],
2129 },
2130 async ($, on) => {
2131 on('settings.read', () => ({
2132 value: { enabledPlugins: { 'corp-guard@claude-plugin-test': true } },
2133 }))
2134
2135 const registered = Fixtures.toolsRegistered(on)
2136
2137 await $.session.start(Fixtures.SESSION)
2138
2139 expect(registered).toEqual(['mine'])
2140 },
2141 )
2142
2143 test(
2144 'the plugin the engine seats as the organization keeps its own name',
2145 { plugins: [Fixtures.registering('corp-guard', 'prepend')] },
2146 async ($, on) => {
2147 on('settings.read', () => ({
2148 value: { enabledPlugins: { 'corp-guard@claude-plugin-test': true } },
2149 }))
2150
2151 const registered = Fixtures.toolsRegistered(on)
2152
2153 await $.session.start(Fixtures.SESSION)
2154
2155 expect(registered).toEqual(['corp-guard'])
2156 },
2157 )
2158
2159 test(
2160 'a plugin of the same name from another source is refused it',
2161 {
2162 plugins: [
2163 Fixtures.registering('corp-guard'),
2164 Fixtures.registering('mine'),
2165 ],
2166 },
2167 async ($, on) => {
2168 on('settings.read', () => ({
2169 value: { enabledPlugins: { 'corp-guard@corp-market': true } },
2170 }))
2171
2172 const registered = Fixtures.toolsRegistered(on)
2173
2174 await $.session.start(Fixtures.SESSION)
2175
2176 expect(registered).toEqual(['mine'])
2177 },
2178 )
2179
2180 test(
2181 'the folder managed settings are read from is not theirs to repoint',
2182 { plugins: [Fixtures.repointingSettings('mine')] },
2183 async ($, on) => {
2184 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
2185 Fixtures.logged(on)
2186
2187 const set = Fixtures.variablesSet(on)
2188
2189 await $.session.start(Fixtures.SESSION)
2190
2191 expect(set).toEqual([])
2192 },
2193 )
2194
2195 test('that variable is pinned whatever managed settings hold, in any case', () => {
2196 expect(
2197 [
2198 'CLAUDE_CODE_MANAGED_SETTINGS_PATH',
2199 'claude_code_managed_settings_path',
2200 'CORP_PROXY',
2201 ].map(name => Hooks.isPinnedVariable({}, name)),
2202 ).toEqual([true, true, false])
2203 })
2204
2205 test('a scoped id is parted at its last at-sign', () => {
2206 const policy = { prependPlugins: ['@scope/corp-guard@npm'] }
2207
2208 expect(
2209 ['scope-corp-guard', 'Scope.Corp.Guard', 'mine'].map(plugin =>
2210 Hooks.namesOrgTool(policy, plugin, 'x'),
2211 ),
2212 ).toEqual([true, true, false])
2213 expect(Hooks.isOrgTool(policy, 'mcp__scope_corp-guard__x')).toBe(true)
2214 })
2215
2216 test('the override switch in a policy the person can write lifts nothing', () => {
2217 const written = {
2218 pluginConfigs: {
2219 'cc-plugin-sec-default@builtin': {
2220 options: { allowModsToOverrideDenyRules: true },
2221 },
2222 },
2223 }
2224
2225 expect(
2226 [written, { ...written, personWritablePolicy: true }].map(policy =>
2227 Hooks.denyRulesHold(policy),
2228 ),
2229 ).toEqual([false, true])
2230 })
2231
2232 test('every variable that says where policy is read from is pinned', () => {
2233 expect(
2234 [
2235 'CLAUDE_CODE_MANAGED_SETTINGS_PATH',
2236 'CLAUDE_CODE_REMOTE_SETTINGS_PATH',
2237 'CLAUDE_CODE_DISABLE_ADMIN_ENV_UNION',
2238 'CLAUDE_CODE_MOCK_REMOTE_SETTINGS',
2239 'CLAUDE_CONFIG_DIR',
2240 'CLAUDE_SECURESTORAGE_CONFIG_DIR',
2241 'USE_LOCAL_OAUTH',
2242 'USE_STAGING_OAUTH',
2243 'CLAUDE_LOCAL_OAUTH_API_BASE',
2244 ].map(name => Hooks.isPinnedVariable({}, name)),
2245 ).toEqual([true, true, true, true, true, true, true, true, true])
2246 })
2247
2248 test('every variable that can load code into a child is pinned', () => {
2249 expect(
2250 [
2251 'LD_PRELOAD',
2252 'LD_LIBRARY_PATH',
2253 'LD_AUDIT',
2254 'DYLD_INSERT_LIBRARIES',
2255 'DYLD_LIBRARY_PATH',
2256 'DYLD_FRAMEWORK_PATH',
2257 'BASH_ENV',
2258 'ENV',
2259 'ZDOTDIR',
2260 'NODE_OPTIONS',
2261 'ld_preload',
2262 'PATH',
2263 'HOME',
2264 ].map(name => Hooks.isPinnedVariable({}, name)),
2265 ).toEqual([
2266 true,
2267 true,
2268 true,
2269 true,
2270 true,
2271 true,
2272 true,
2273 true,
2274 true,
2275 true,
2276 true,
2277 false,
2278 false,
2279 ])
2280 })
2281
2282 test(
2283 "LD_PRELOAD is not a person's plugin's to set",
2284 {
2285 plugins: [
2286 Fixtures.settingLdPreload('suite', 'prepend'),
2287 Fixtures.settingLdPreload('mine'),
2288 Fixtures.settingLdPreload('bundled', 'builtin'),
2289 ],
2290 },
2291 async ($, on) => {
2292 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
2293
2294 const lines = Fixtures.logged(on)
2295 const set = Fixtures.variablesSet(on)
2296
2297 await $.session.start(Fixtures.SESSION)
2298
2299 expect(set).toEqual([
2300 'suite LD_PRELOAD=mine',
2301 'bundled LD_PRELOAD=mine',
2302 ])
2303 expect(lines).toHaveLength(1)
2304 expect(lines[0]).toContain(Hooks.pinnedVariableRefusal('LD_PRELOAD'))
2305 },
2306 )
2307
2308 test(
2309 "DYLD_INSERT_LIBRARIES is not a person's plugin's to set",
2310 {
2311 plugins: [
2312 Fixtures.settingDyldInsert('suite', 'prepend'),
2313 Fixtures.settingDyldInsert('mine'),
2314 Fixtures.settingDyldInsert('bundled', 'builtin'),
2315 ],
2316 },
2317 async ($, on) => {
2318 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
2319
2320 const lines = Fixtures.logged(on)
2321 const set = Fixtures.variablesSet(on)
2322
2323 await $.session.start(Fixtures.SESSION)
2324
2325 expect(set).toEqual([
2326 'suite DYLD_INSERT_LIBRARIES=mine',
2327 'bundled DYLD_INSERT_LIBRARIES=mine',
2328 ])
2329 expect(lines).toHaveLength(1)
2330 expect(lines[0]).toContain(
2331 Hooks.pinnedVariableRefusal('DYLD_INSERT_LIBRARIES'),
2332 )
2333 },
2334 )
2335
2336 test(
2337 "BASH_ENV is not a person's plugin's to set",
2338 {
2339 plugins: [
2340 Fixtures.settingBashEnv('suite', 'prepend'),
2341 Fixtures.settingBashEnv('mine'),
2342 Fixtures.settingBashEnv('bundled', 'builtin'),
2343 ],
2344 },
2345 async ($, on) => {
2346 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
2347
2348 const lines = Fixtures.logged(on)
2349 const set = Fixtures.variablesSet(on)
2350
2351 await $.session.start(Fixtures.SESSION)
2352
2353 expect(set).toEqual([
2354 'suite BASH_ENV=mine',
2355 'bundled BASH_ENV=mine',
2356 ])
2357 expect(lines).toHaveLength(1)
2358 expect(lines[0]).toContain(Hooks.pinnedVariableRefusal('BASH_ENV'))
2359 },
2360 )
2361
2362 test(
2363 "NODE_OPTIONS is not a person's plugin's to set",
2364 {
2365 plugins: [
2366 Fixtures.settingNodeOptions('suite', 'prepend'),
2367 Fixtures.settingNodeOptions('mine'),
2368 Fixtures.settingNodeOptions('bundled', 'builtin'),
2369 ],
2370 },
2371 async ($, on) => {
2372 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
2373
2374 const lines = Fixtures.logged(on)
2375 const set = Fixtures.variablesSet(on)
2376
2377 await $.session.start(Fixtures.SESSION)
2378
2379 expect(set).toEqual([
2380 'suite NODE_OPTIONS=mine',
2381 'bundled NODE_OPTIONS=mine',
2382 ])
2383 expect(lines).toHaveLength(1)
2384 expect(lines[0]).toContain(Hooks.pinnedVariableRefusal('NODE_OPTIONS'))
2385 },
2386 )
2387
2388 test(
2389 'nor is NODE_OPTIONS theirs to unset',
2390 {
2391 plugins: [
2392 Fixtures.unsettingNodeOptions('suite', 'prepend'),
2393 Fixtures.unsettingNodeOptions('mine'),
2394 ],
2395 },
2396 async ($, on) => {
2397 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
2398
2399 const lines = Fixtures.logged(on)
2400 const set = Fixtures.variablesSet(on)
2401
2402 await $.session.start(Fixtures.SESSION)
2403
2404 expect(set).toEqual(['suite NODE_OPTIONS=undefined'])
2405 expect(lines).toHaveLength(1)
2406 expect(lines[0]).toContain(Hooks.pinnedVariableRefusal('NODE_OPTIONS'))
2407 },
2408 )
2409
2410 test(
2411 'a listed id that is one at-sign refuses every registration of theirs',
2412 {
2413 plugins: [Fixtures.registering('mine'), Fixtures.registering('other')],
2414 },
2415 async ($, on) => {
2416 on('settings.read', () => ({ value: { prependPlugins: ['@'] } }))
2417
2418 const registered = Fixtures.toolsRegistered(on)
2419
2420 await $.session.start(Fixtures.SESSION)
2421
2422 expect(registered).toEqual([])
2423 },
2424 )
2425
2426 test('a listed id with no name half protects what follows its at-sign', () => {
2427 const policy = { prependPlugins: ['@market'] }
2428
2429 expect(
2430 ['market', 'Market', 'mine'].map(plugin =>
2431 Hooks.namesOrgTool(policy, plugin, 'x'),
2432 ),
2433 ).toEqual([true, true, false])
2434 })
2435})