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 / held-verdict.test.ts
143 lines · 4.4 KBRaw
1import { describe, expect, test, tier } from 'claude-code/testing'
2
3import Hooks from '../hooks'
4import Fixtures from './fixtures'
5
6tier('prepend')
7
8describe('held-verdict', () => {
9 test('over an allow: any deny, and an ask a settings rule decided', () => {
10 expect(
11 [
12 Fixtures.RULE_DENY,
13 Fixtures.RULE_ASK,
14 Fixtures.PLAIN_DENY,
15 Fixtures.ASKED,
16 Fixtures.ALLOWED,
17 ].map(held => Hooks.holdsOver(held, Fixtures.ALLOWED)),
18 ).toEqual([true, true, true, false, false])
19 })
20
21 test('over an ask only a deny is stricter; over a deny nothing is', () => {
22 expect(
23 [Fixtures.RULE_DENY, Fixtures.RULE_ASK].map(held => [
24 Hooks.holdsOver(held, Fixtures.ASKED),
25 Hooks.holdsOver(held, Fixtures.PLAIN_DENY),
26 ]),
27 ).toEqual([
28 [true, false],
29 [false, false],
30 ])
31 })
32
33 test('a rule the answer itself names makes nothing hold', () => {
34 expect(
35 Hooks.holdsOver(Fixtures.ASKED, {
36 ...Fixtures.ALLOWED,
37 rule: 'Bash(echo *)',
38 }),
39 ).toBe(false)
40 })
41
42 test('the notice names the kind that held, and the rule when one did', () => {
43 expect(
44 [Fixtures.RULE_DENY, Fixtures.RULE_ASK, Fixtures.PLAIN_DENY].map(held =>
45 Hooks.heldNotice('easy', 'Bash', held),
46 ),
47 ).toEqual(
48 [
49 'a deny rule in your settings from a Bash call (Bash(echo *)); ' +
50 'the deny rule',
51 'an ask rule in your settings from a Bash call (Bash(echo *)); ' +
52 'the ask rule',
53 'a refusal from a Bash call; the refusal',
54 ].map(
55 middle =>
56 `easy tried to lift ${middle} holds over the plugins you install ` +
57 '(allowModsToOverrideDenyRules)',
58 ),
59 )
60 })
61
62 test('what no check vouches for is refused, and says why', () => {
63 expect(Hooks.UNCHECKED_DENY).toEqual({
64 decision: 'deny',
65 reason:
66 'the rules in your settings could not be checked for this call, ' +
67 'so it is refused',
68 })
69 })
70
71 test('an ask of theirs over a deny, caught, is no more vouched for', () => {
72 expect(
73 Hooks.caughtAnswer(Fixtures.ASKED, [
74 Fixtures.linkOf('easy', 'user', Fixtures.ASKED),
75 Fixtures.linkOf('engine', 'core', Fixtures.RULE_DENY),
76 ]),
77 ).toEqual(Hooks.UNCHECKED_DENY)
78 })
79
80 test('a link of theirs is named when it answered looser than handed', () => {
81 expect(
82 Hooks.loosenedByUsers([
83 Fixtures.linkOf('listening', 'user', Fixtures.ALLOWED),
84 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
85 Fixtures.linkOf('engine', 'core', Fixtures.ASKED),
86 ]),
87 ).toEqual(['easy'])
88 })
89
90 test('one that never called next is measured against a deny', () => {
91 expect(
92 Hooks.loosenedByUsers([
93 Fixtures.linkOf('listening', 'user', Fixtures.ALLOWED),
94 Fixtures.linkOf('blind', 'user', Fixtures.ALLOWED),
95 ]),
96 ).toEqual(['blind'])
97 })
98
99 test('a tightening, a skipped link and links beneath theirs are not', () => {
100 expect(
101 Hooks.loosenedByUsers([
102 Fixtures.linkOf('strict', 'user', Fixtures.PLAIN_DENY),
103 Fixtures.linkOf('passed-over', 'user'),
104 Fixtures.linkOf('suite', 'append', Fixtures.ALLOWED),
105 Fixtures.linkOf('bundled', 'builtin', Fixtures.ALLOWED),
106 Fixtures.linkOf('engine', 'core', Fixtures.RULE_DENY),
107 ]),
108 ).toEqual([])
109 })
110
111 test('a batch listed under prepend may hold a plugin of theirs', () => {
112 expect(
113 Hooks.loosenedByUsers([
114 Fixtures.linkOf('audit+easy', 'prepend', Fixtures.ALLOWED),
115 Fixtures.linkOf('engine', 'core', Fixtures.RULE_DENY),
116 ]),
117 ).toEqual(['audit+easy'])
118 })
119
120 test('the handler keeps a deny, and a verdict none of theirs made', () => {
121 const pastUsers = [
122 Fixtures.linkOf('easy', 'user'),
123 Fixtures.linkOf('engine', 'core', Fixtures.ASKED),
124 ]
125
126 expect([
127 Hooks.caughtAnswer(Fixtures.RULE_DENY, [
128 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
129 ]),
130 Hooks.caughtAnswer(Fixtures.ASKED, pastUsers),
131 ]).toEqual([Fixtures.RULE_DENY, Fixtures.ASKED])
132 })
133
134 test('the handler refuses a verdict they loosened, and no verdict', () => {
135 expect([
136 Hooks.caughtAnswer(Fixtures.ALLOWED, [
137 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
138 Fixtures.linkOf('engine', 'core', Fixtures.ASKED),
139 ]),
140 Hooks.caughtAnswer(undefined, []),
141 ]).toEqual([Hooks.UNCHECKED_DENY, Hooks.UNCHECKED_DENY])
142 })
143})