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
176 lines · 5.8 KBRaw
1import { describe, expect, test, tier } from 'claude-code/testing'
2
3import Hooks from '../hooks'
4import Fixtures from './fixtures'
5
6tier('prepend')
7
8describe('held-verdict', () => {
9 test('a deny that names its rule is a rule deny; any other is not', () => {
10 expect(
11 [Fixtures.RULE_DENY, Fixtures.PLAIN_DENY, Fixtures.ASKED].map(
12 Hooks.isRuleDeny,
13 ),
14 ).toEqual([true, false, false])
15 })
16
17 test('a link of theirs is named when it answered looser than handed', () => {
18 expect(
19 Hooks.loosenedByUsers([
20 Fixtures.linkOf('listening', 'user', Fixtures.ALLOWED),
21 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
22 Fixtures.linkOf('engine', 'core', Fixtures.ASKED),
23 ]),
24 ).toEqual(['easy'])
25 })
26
27 test('one that never called next is measured against a deny', () => {
28 expect(
29 Hooks.loosenedByUsers([
30 Fixtures.linkOf('listening', 'user', Fixtures.ALLOWED),
31 Fixtures.linkOf('blind', 'user', Fixtures.ALLOWED),
32 ]),
33 ).toEqual(['blind'])
34 })
35
36 test('a tightening, a skipped link and links beneath theirs are not', () => {
37 expect(
38 Hooks.loosenedByUsers([
39 Fixtures.linkOf('strict', 'user', Fixtures.PLAIN_DENY),
40 Fixtures.linkOf('passed-over', 'user'),
41 Fixtures.linkOf('suite', 'append', Fixtures.ALLOWED),
42 Fixtures.linkOf('bundled', 'builtin', Fixtures.ALLOWED),
43 Fixtures.linkOf('engine', 'core', Fixtures.RULE_DENY),
44 ]),
45 ).toEqual([])
46 })
47
48 test('a batch listed under prepend may hold a plugin of theirs', () => {
49 expect(
50 Hooks.loosenedByUsers([
51 Fixtures.linkOf('audit+easy', 'prepend', Fixtures.ALLOWED),
52 Fixtures.linkOf('engine', 'core', Fixtures.RULE_DENY),
53 ]),
54 ).toEqual(['audit+easy'])
55 })
56
57 test('the handler keeps a deny, and a verdict none of theirs made', () => {
58 const pastUsers = [
59 Fixtures.linkOf('easy', 'user'),
60 Fixtures.linkOf('engine', 'core', Fixtures.ASKED),
61 ]
62
63 expect([
64 Hooks.caughtAnswer(Fixtures.RULE_DENY, [
65 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
66 ]),
67 Hooks.caughtAnswer(Fixtures.ASKED, pastUsers),
68 ]).toEqual([Fixtures.RULE_DENY, Fixtures.ASKED])
69 })
70
71 test('the handler refuses a verdict they loosened, and no verdict', () => {
72 expect([
73 Hooks.caughtAnswer(Fixtures.ALLOWED, [
74 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
75 Fixtures.linkOf('engine', 'core', Fixtures.ASKED),
76 ]),
77 Hooks.caughtAnswer(undefined, []),
78 ]).toEqual([Hooks.UNCHECKED_DENY, Hooks.UNCHECKED_DENY])
79 })
80
81 test('only a verdict looser than the ceiling is over it', () => {
82 expect(
83 [Fixtures.ALLOWED, Fixtures.ASKED, Fixtures.PLAIN_DENY].map(verdict =>
84 Hooks.isOverCeiling(verdict, Fixtures.CAPPED.ceiling),
85 ),
86 ).toEqual([true, false, false])
87 })
88
89 test('where the organization set no ceiling nothing is over it', () => {
90 expect(
91 Hooks.isOverCeiling(Fixtures.ALLOWED, Fixtures.CHECKED.ceiling),
92 ).toBe(false)
93 })
94
95 test('the ceiling holds an answer over it by a stricter run', () => {
96 expect([
97 Hooks.isCeilingHeld(Fixtures.ALLOWED, Fixtures.CAPPED_ASK, 'ask'),
98 Hooks.isCeilingHeld(Fixtures.ALLOWED, Fixtures.RULE_DENY, 'ask'),
99 ]).toEqual([true, true])
100 })
101
102 test('it holds no run as permissive, and no answer within it', () => {
103 expect([
104 Hooks.isCeilingHeld(Fixtures.ALLOWED, Fixtures.CAPPED_ALLOWED, 'ask'),
105 Hooks.isCeilingHeld(Fixtures.ASKED, Fixtures.PLAIN_DENY, 'ask'),
106 Hooks.isCeilingHeld(Fixtures.ASKED, Fixtures.ALLOWED, 'deny'),
107 Hooks.isCeilingHeld(Fixtures.ALLOWED, Fixtures.ASKED, undefined),
108 ]).toEqual([false, false, false, false])
109 })
110
111 test('a ceiling it does not know holds a call at a deny', () => {
112 expect([
113 Hooks.ceilingVerdict('ask'),
114 Hooks.ceilingVerdict('blocked'),
115 Hooks.isOverCeiling(Fixtures.ASKED, 'blocked'),
116 Hooks.isOverCeiling(Fixtures.PLAIN_DENY, 'blocked'),
117 ]).toEqual(['ask', 'deny', true, false])
118 })
119
120 test('a link of theirs is named when it answered over the ceiling', () => {
121 expect(
122 Hooks.liftedByUsers(
123 [
124 Fixtures.linkOf('easy', 'user', Fixtures.ALLOWED),
125 Fixtures.linkOf('soft', 'user', Fixtures.ASKED),
126 Fixtures.linkOf('suite', 'append', Fixtures.ALLOWED),
127 Fixtures.linkOf('engine', 'core', Fixtures.PLAIN_DENY),
128 ],
129 'ask',
130 ),
131 ).toEqual(['easy'])
132 })
133
134 test('none is named over an allow handed up, or under no ceiling', () => {
135 const run = [
136 Fixtures.linkOf('listening', 'user', Fixtures.ALLOWED),
137 Fixtures.linkOf('suite', 'append', Fixtures.ALLOWED),
138 ]
139
140 expect([
141 Hooks.liftedByUsers(run, 'ask'),
142 Hooks.liftedByUsers(run.slice(0, 1), undefined),
143 ]).toEqual([[], []])
144 })
145
146 test('a plugin is told once, however many of its links are named', () => {
147 expect(
148 Hooks.untold(new Set(['told']), ['easy', 'told', 'soft', 'easy']),
149 ).toEqual(['easy', 'soft'])
150 })
151
152 test('the handler keeps a verdict within the ceiling, or under none', () => {
153 expect([
154 Hooks.underCeiling(Fixtures.ASKED, 'ask'),
155 Hooks.underCeiling(Hooks.UNCHECKED_DENY, 'ask'),
156 Hooks.underCeiling(Fixtures.ALLOWED, undefined),
157 ]).toEqual([Fixtures.ASKED, Hooks.UNCHECKED_DENY, Fixtures.ALLOWED])
158 })
159
160 test('the handler answers the ceiling for a verdict over it', () => {
161 expect([
162 Hooks.underCeiling(Fixtures.ALLOWED, 'ask'),
163 Hooks.underCeiling(Fixtures.ASKED, 'blocked'),
164 ]).toEqual([
165 Hooks.uncheckedCeiling('ask'),
166 { ...Hooks.uncheckedCeiling('ask'), decision: 'deny' },
167 ])
168 })
169
170 test('the handler makes no verdict of none: a rejection stays one', () => {
171 expect([
172 Hooks.underCeiling(undefined, 'ask'),
173 Hooks.underCeiling(undefined, undefined),
174 ]).toEqual([undefined, undefined])
175 })
176})