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
858 lines · 24.1 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('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
163
164 on('prompt.compose', () => ({
165 sections: [{ id: 'body', text: 'the body', scope: 'shared' }],
166 }))
167
168 expect(await $.prompt.compose(Fixtures.COMPOSED)).toEqual({
169 sections: [
170 { id: 'heading:org', text: 'the org says hi', scope: 'shared' },
171 { id: 'body', text: 'the body', scope: 'shared' },
172 ],
173 })
174 },
175 )
176
177 test(
178 "nor does a person's plugin drop or reword a section it asked for",
179 { plugins: [Fixtures.rewording, Fixtures.heading] },
180 async ($, on) => {
181 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
182
183 on('prompt.compose', () => ({
184 sections: [{ id: 'body', text: 'the body', scope: 'shared' }],
185 }))
186
187 expect(await $.prompt.compose(Fixtures.COMPOSED)).toEqual({
188 sections: [
189 { id: 'heading:org', text: 'the org says hi', scope: 'shared' },
190 { id: 'body', text: 'the body', scope: 'shared' },
191 ],
192 })
193 },
194 )
195
196 test(
197 "a user plugin's rewrite of policy is skipped for every other reader",
198 {
199 plugins: [
200 Fixtures.stripping,
201 Fixtures.reading,
202 Fixtures.registering('mine'),
203 ],
204 },
205 async ($, on) => {
206 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
207
208 const registered = Fixtures.toolsRegistered(on)
209 const { text } = await $.command.run(Fixtures.POLICY_COMMAND)
210
211 await $.session.start(Fixtures.SESSION)
212
213 expect(
214 JSON.parse(text ?? 'null'),
215 "another user plugin's read sees the allowlist the stripper hides",
216 ).toEqual(Fixtures.MANAGED_POLICY)
217
218 expect(
219 registered,
220 "sec-default's own tool.register hook still reads the allowlist",
221 ).toEqual([])
222 },
223 )
224
225 test(
226 "an organization provider's subject passes over the user plugins",
227 { plugins: [Fixtures.marking] },
228 async ($, on) => {
229 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
230 Fixtures.subjectsEchoed(on)
231
232 for (const provider of Fixtures.ORG_PROVIDERS) {
233 expect(
234 await $.tool.describe(
235 Fixtures.toolDescribed('mcp__corp__search', provider),
236 ),
237 ).toEqual({ description: 'd' })
238
239 expect(
240 (
241 await $.command.describe(
242 Fixtures.commandDescribed('suite:deploy', provider),
243 )
244 ).isHidden,
245 ).toBe(false)
246
247 expect(
248 await $.agent.offer(
249 Fixtures.agentOffered('suite:reviewer', provider),
250 ),
251 ).toEqual({ isOffered: true })
252
253 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
254 model: 'core',
255 })
256 }
257
258 for (const provider of Fixtures.USER_REACHABLE_PROVIDERS) {
259 expect(
260 await $.tool.describe(
261 Fixtures.toolDescribed('mcp__mine__search', provider),
262 ),
263 ).toEqual({ description: 'user: d' })
264
265 expect(
266 (
267 await $.command.describe(
268 Fixtures.commandDescribed('mine:deploy', provider),
269 )
270 ).isHidden,
271 ).toBe(true)
272
273 expect(
274 await $.agent.offer(Fixtures.agentOffered('reviewer', provider)),
275 ).toEqual({ isOffered: false })
276
277 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
278 model: 'user',
279 })
280 }
281 },
282 )
283
284 test(
285 'an odd provider passes over the user plugins: it fails closed',
286 { plugins: [Fixtures.marking] },
287 async ($, on) => {
288 on('settings.read', () => ({ value: Fixtures.NO_ALLOWLIST }))
289 Fixtures.subjectsEchoed(on)
290
291 for (const provider of Fixtures.ODD_PROVIDERS) {
292 expect(
293 await $.tool.describe(Fixtures.toolDescribed('Bash', provider)),
294 ).toEqual({ description: 'd' })
295
296 expect(await $.agent.spawn(Fixtures.agentSpawned(provider))).toEqual({
297 model: 'core',
298 })
299 }
300 },
301 )
302
303 test(
304 'a subject decision reads no policy; a burst of listings reads once',
305 { plugins: [Fixtures.listing] },
306 async ($, on) => {
307 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
308
309 Fixtures.subjectsEchoed(on)
310 on('tool.list', () => ({ value: [...Fixtures.TOOLS] }))
311
312 for (const provider of Fixtures.ORG_PROVIDERS) {
313 await $.tool.describe(Fixtures.toolDescribed('mcp__corp__x', provider))
314 await $.agent.spawn(Fixtures.agentSpawned(provider))
315 }
316
317 expect(reads(), "one read: the person's plugin was admitted").toBe(1)
318
319 await Promise.all([
320 $.command.run(Fixtures.TOOLS_COMMAND),
321 $.command.run(Fixtures.TOOLS_COMMAND),
322 $.command.run(Fixtures.TOOLS_COMMAND),
323 ])
324
325 expect(reads()).toBe(2)
326 },
327 )
328
329 test(
330 'the refusal a user-tier caller reads names the allowlist',
331 {
332 plugins: [
333 {
334 name: 'asking',
335 register(on) {
336 on('command.run', { command: 'greet' }, $ =>
337 $.tool
338 .register({
339 name: 'greet',
340 description: 'Says hello.',
341 inputSchema: { type: 'object' },
342 })
343 .then(
344 () => ({ text: 'registered' }),
345 (error: unknown) => ({ text: String(error) }),
346 ),
347 )
348 },
349 },
350 ],
351 },
352 async ($, on) => {
353 on('settings.read', () => ({ value: Fixtures.ALLOWLIST }))
354
355 const { text } = await $.command.run({
356 command: 'greet',
357 args: '',
358 origin: { kind: 'composer' },
359 presentation: Fixtures.FULLSCREEN,
360 })
361
362 expect(text).toEndWith(
363 `asking: $.tool.register: ${Hooks.TOOL_REGISTER_REFUSAL}`,
364 )
365 },
366 )
367
368 test(
369 "under allowManagedModsOnly a person's mod is kept out, told why",
370 { plugins: [Fixtures.registering('mine')] },
371 async ($, on) => {
372 on('settings.read', () => ({ value: Fixtures.MANAGED_MODS_ONLY }))
373
374 const registered = Fixtures.toolsRegistered(on)
375
376 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
377 Hooks.managedModsOnlyRefusal('mine'),
378 )
379
380 expect(registered, 'no hook of it ever ran').toEqual([])
381 },
382 )
383
384 test(
385 "under it the organization's mods and the built-ins load",
386 {
387 plugins: [
388 Fixtures.registering('suite', 'prepend'),
389 Fixtures.registering('after', 'append'),
390 Fixtures.registering('bundled', 'builtin'),
391 ],
392 },
393 async ($, on) => {
394 on('settings.read', () => ({ value: Fixtures.MANAGED_MODS_ONLY }))
395
396 const registered = Fixtures.toolsRegistered(on)
397
398 await $.session.start(Fixtures.SESSION)
399
400 expect(registered).toEqual(['suite', 'after', 'bundled'])
401 },
402 )
403
404 test(
405 'set to false, a mod the person installed loads as before',
406 { plugins: [Fixtures.registering('mine')] },
407 async ($, on) => {
408 on('settings.read', () => ({ value: Fixtures.modsPolicyOf(false) }))
409
410 const registered = Fixtures.toolsRegistered(on)
411
412 await $.session.start(Fixtures.SESSION)
413
414 expect(registered).toEqual(['mine'])
415 },
416 )
417
418 test(
419 "a person's copy under an organization mod's name is still theirs",
420 { plugins: [Fixtures.registering('suite')] },
421 async ($, on) => {
422 on('settings.read', () => ({
423 value: { ...Fixtures.MANAGED_POLICY, ...Fixtures.MANAGED_MODS_ONLY },
424 }))
425
426 const registered = Fixtures.toolsRegistered(on)
427
428 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
429 Hooks.managedModsOnlyRefusal('suite'),
430 )
431
432 expect(registered).toEqual([])
433 },
434 )
435
436 test(
437 "only managed settings are asked: a person's own cannot loosen it",
438 { plugins: [Fixtures.registering('mine')] },
439 async ($, on) => {
440 Fixtures.policyBySource(
441 on,
442 Fixtures.MANAGED_MODS_ONLY,
443 Fixtures.modsPolicyOf(false),
444 )
445
446 const registered = Fixtures.toolsRegistered(on)
447
448 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
449 Hooks.managedModsOnlyRefusal('mine'),
450 )
451
452 expect(registered).toEqual([])
453 },
454 )
455
456 test(
457 "nor turn it on: set only in a person's settings, it is not read",
458 { plugins: [Fixtures.registering('mine')] },
459 async ($, on) => {
460 Fixtures.policyBySource(
461 on,
462 Fixtures.NO_ALLOWLIST,
463 Fixtures.MANAGED_MODS_ONLY,
464 )
465
466 const registered = Fixtures.toolsRegistered(on)
467
468 await $.session.start(Fixtures.SESSION)
469
470 expect(registered).toEqual(['mine'])
471 },
472 )
473
474 test(
475 "a policy that cannot be read keeps a person's mod out: the hook's catch",
476 { plugins: [Fixtures.registering('mine')] },
477 async ($, on) => {
478 on('settings.read', () => ({ deny: 'managed settings unreadable' }))
479
480 const lines = Fixtures.logged(on)
481 const registered = Fixtures.toolsRegistered(on)
482
483 await expect($.session.start(Fixtures.SESSION)).rejects.toThrow(
484 Hooks.managedModsOnlyRefusal('mine'),
485 )
486
487 expect({ registered, lines }).toEqual({
488 registered: [],
489 lines: [
490 'debug: plugin.register hook failed judging mine (throw): ' +
491 'sec-default: $.settings.read: managed settings unreadable',
492 ],
493 })
494 },
495 )
496
497 test(
498 'a deny rule holds over an allow from a plugin the person installed',
499 { plugins: [Fixtures.allowing('easy')] },
500 async ($, on) => {
501 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
502
503 const lines = Fixtures.logged(on)
504
505 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
506
507 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
508
509 expect(lines).toEqual([
510 `transcript: ${Hooks.heldNotice('easy', 'Bash', 'Bash(echo *)')}`,
511 ])
512 },
513 )
514
515 test(
516 'two plugins of the person chained are each named once in a session',
517 {
518 plugins: [Fixtures.allowing('first'), Fixtures.asking('second')],
519 },
520 async ($, on) => {
521 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
522
523 const lines = Fixtures.logged(on)
524
525 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
526
527 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
528 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
529
530 expect(lines.toSorted()).toEqual([
531 `transcript: ${Hooks.heldNotice('first', 'Bash', 'Bash(echo *)')}`,
532 `transcript: ${Hooks.heldNotice('second', 'Bash', 'Bash(echo *)')}`,
533 ])
534 },
535 )
536
537 test(
538 'a deny rule turned into an ask by a plugin of the person holds too',
539 { plugins: [Fixtures.asking('easy')] },
540 async ($, on) => {
541 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
542 Fixtures.logged(on)
543 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
544
545 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
546 },
547 )
548
549 test(
550 "an organization plugin's allow over a deny rule stands, above or below",
551 {
552 plugins: [
553 Fixtures.allowing('suite', 'append'),
554 Fixtures.allowing('easy'),
555 ],
556 },
557 async ($, on) => {
558 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
559
560 const lines = Fixtures.logged(on)
561
562 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
563
564 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
565 expect(lines).toEqual([])
566 },
567 )
568
569 test(
570 "a prepended organization plugin's allow over a deny rule stands",
571 { plugins: [Fixtures.allowing('guard', 'prepend')] },
572 async ($, on) => {
573 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
574
575 const lines = Fixtures.logged(on)
576
577 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
578
579 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
580 expect(lines).toEqual([])
581 },
582 )
583
584 test(
585 "a built-in's allow over a deny rule stands",
586 { plugins: [Fixtures.allowing('bundled', 'builtin')] },
587 async ($, on) => {
588 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
589
590 const lines = Fixtures.logged(on)
591
592 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
593
594 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
595 expect(lines).toEqual([])
596 },
597 )
598
599 test(
600 'an ask a plugin of the person allows, no deny rule behind it, stands',
601 { plugins: [Fixtures.allowing('easy')] },
602 async ($, on) => {
603 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
604
605 const lines = Fixtures.logged(on)
606
607 Fixtures.checksAnswered(on, Fixtures.ASKED)
608
609 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
610 expect(lines).toEqual([])
611 },
612 )
613
614 test(
615 'a deny no rule decided is still theirs to answer over',
616 { plugins: [Fixtures.allowing('easy')] },
617 async ($, on) => {
618 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
619
620 const lines = Fixtures.logged(on)
621
622 Fixtures.checksAnswered(on, Fixtures.PLAIN_DENY)
623
624 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
625 expect(lines).toEqual([])
626 },
627 )
628
629 test(
630 'a plugin of the person that tightens is heard, with one evaluation',
631 { plugins: [Fixtures.tightening] },
632 async ($, on) => {
633 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
634 const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED)
635
636 await $.tool.check(Fixtures.CHECKED)
637
638 const loaded = { reads: reads(), evaluations: evaluations() }
639
640 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.PLAIN_DENY)
641
642 expect(
643 {
644 reads: reads() - loaded.reads,
645 evaluations: evaluations() - loaded.evaluations,
646 },
647 'once its plugins have loaded, a check reads no policy',
648 ).toEqual({ reads: 0, evaluations: 1 })
649 },
650 )
651
652 test(
653 "a deny rule holds when an organization's plugin listens above theirs",
654 {
655 plugins: [
656 Fixtures.listening('audit', 'prepend'),
657 Fixtures.allowing('easy'),
658 ],
659 },
660 async ($, on) => {
661 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
662
663 const lines = Fixtures.logged(on)
664
665 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
666
667 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
668
669 expect(
670 lines.map(line => line.includes('easy')),
671 'one line, naming the plugin of theirs, alone or in its batch',
672 ).toEqual([true])
673 },
674 )
675
676 test(
677 'a plugin of the person that only listens costs no second evaluation',
678 { plugins: [Fixtures.listening('listening')] },
679 async ($, on) => {
680 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
681 const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED)
682
683 await $.tool.check(Fixtures.CHECKED)
684
685 const loaded = { reads: reads(), evaluations: evaluations() }
686
687 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ASKED)
688
689 expect(
690 {
691 reads: reads() - loaded.reads,
692 evaluations: evaluations() - loaded.evaluations,
693 },
694 'once its plugins have loaded, a check reads no policy',
695 ).toEqual({ reads: 0, evaluations: 1 })
696 },
697 )
698
699 test('with none of their plugins the verdict passes once', async ($, on) => {
700 const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY)
701 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
702
703 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
704
705 expect({ reads: reads(), evaluations: evaluations() }).toEqual({
706 reads: 0,
707 evaluations: 1,
708 })
709 })
710
711 test(
712 'an allow that never called next meets the deny rule all the same',
713 { plugins: [Fixtures.blindAllowing] },
714 async ($, on) => {
715 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
716
717 const lines = Fixtures.logged(on)
718 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
719
720 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
721
722 expect({ lines, evaluations: evaluations() }).toEqual({
723 lines: [
724 `transcript: ${Hooks.heldNotice('blind', 'Bash', 'Bash(echo *)')}`,
725 ],
726 evaluations: 1,
727 })
728 },
729 )
730
731 test(
732 'a rule a plugin of the person writes into its answer is never read',
733 { plugins: [Fixtures.forging] },
734 async ($, on) => {
735 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
736
737 const lines = Fixtures.logged(on)
738
739 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
740
741 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
742
743 expect(lines).toEqual([
744 `transcript: ${Hooks.heldNotice('forging', 'Bash', 'Bash(echo *)')}`,
745 ])
746 },
747 )
748
749 test(
750 'a plugin of the person asking about another command is left out',
751 { plugins: [Fixtures.rewriting] },
752 async ($, on) => {
753 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
754 Fixtures.logged(on)
755
756 const asked: unknown[] = []
757
758 on('tool.check', ($, e) => {
759 asked.push(e.input)
760
761 return Fixtures.RULE_DENY
762 })
763
764 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
765
766 expect(
767 asked,
768 'the rules were asked about the command that would run, only',
769 ).toEqual([Fixtures.CHECKED.input])
770 },
771 )
772
773 test(
774 'managed settings may let the plugins a person installs override',
775 { plugins: [Fixtures.allowing('easy')] },
776 async ($, on) => {
777 on('settings.read', () => ({ value: Fixtures.overridePolicyOf(true) }))
778
779 const lines = Fixtures.logged(on)
780 const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
781
782 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED)
783
784 expect({ lines, evaluations: evaluations() }).toEqual({
785 lines: [],
786 evaluations: 1,
787 })
788 },
789 )
790
791 test(
792 "only managed settings are asked: a person's own cannot lift a deny rule",
793 { plugins: [Fixtures.allowing('easy')] },
794 async ($, on) => {
795 Fixtures.policyBySource(
796 on,
797 Fixtures.MANAGED_POLICY,
798 Fixtures.overridePolicyOf(true),
799 )
800
801 Fixtures.logged(on)
802 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
803
804 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
805 },
806 )
807
808 test(
809 'the option mistyped lifts nothing: only the literal true does',
810 { plugins: [Fixtures.allowing('easy')] },
811 async ($, on) => {
812 on('settings.read', () => ({ value: Fixtures.overridePolicyOf('true') }))
813 Fixtures.logged(on)
814 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
815
816 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY)
817 },
818 )
819
820 test(
821 'with a policy that cannot be read the deny rule holds: fails closed',
822 { plugins: [Fixtures.allowing('easy')] },
823 async ($, on) => {
824 const stopPolicy = Fixtures.policyUntilStopped(
825 on,
826 Fixtures.overridePolicyOf(true),
827 'managed settings unreadable',
828 )
829
830 Fixtures.logged(on)
831 Fixtures.checksAnswered(on, Fixtures.RULE_DENY)
832 on('prompt.section', ($, e) => ({ text: e.text }))
833
834 await $.prompt.section(Fixtures.MEMORY)
835 stopPolicy()
836
837 expect(
838 await $.tool.check(Fixtures.CHECKED),
839 'the policy that read let plugins override; unread, the rule holds',
840 ).toEqual(Fixtures.RULE_DENY)
841 },
842 )
843
844 test(
845 "when the rules cannot be evaluated the call is refused: the hook's catch",
846 { plugins: [Fixtures.blindAllowing] },
847 async ($, on) => {
848 on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY }))
849 Fixtures.logged(on)
850
851 on('tool.check', () => {
852 throw new Error('the evaluation failed')
853 })
854
855 expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Hooks.UNCHECKED_DENY)
856 },
857 )
858})