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
| 1 | import { describe, expect, test, tier } from 'claude-code/testing' |
| 2 | |
| 3 | import Hooks from '../hooks' |
| 4 | import Fixtures from './fixtures' |
| 5 | |
| 6 | tier('prepend') |
| 7 | |
| 8 | describe('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', Fixtures.RULE_DENY)}`, |
| 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', Fixtures.RULE_DENY)}`, |
| 532 | `transcript: ${Hooks.heldNotice('second', 'Bash', Fixtures.RULE_DENY)}`, |
| 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 rule holds over an allow from a plugin the person installed', |
| 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.RULE_ASK) |
| 608 | |
| 609 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK) |
| 610 | |
| 611 | expect(lines).toEqual([ |
| 612 | `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.RULE_ASK)}`, |
| 613 | ]) |
| 614 | }, |
| 615 | ) |
| 616 | |
| 617 | test( |
| 618 | 'an allow that never called next meets the ask rule all the same', |
| 619 | { plugins: [Fixtures.blindAllowing] }, |
| 620 | async ($, on) => { |
| 621 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 622 | Fixtures.logged(on) |
| 623 | |
| 624 | const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_ASK) |
| 625 | |
| 626 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK) |
| 627 | expect(evaluations()).toBe(1) |
| 628 | }, |
| 629 | ) |
| 630 | |
| 631 | test( |
| 632 | "an organization plugin's allow over an ask rule stands", |
| 633 | { |
| 634 | plugins: [ |
| 635 | Fixtures.allowing('suite', 'append'), |
| 636 | Fixtures.allowing('easy'), |
| 637 | ], |
| 638 | }, |
| 639 | async ($, on) => { |
| 640 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 641 | |
| 642 | const lines = Fixtures.logged(on) |
| 643 | |
| 644 | Fixtures.checksAnswered(on, Fixtures.RULE_ASK) |
| 645 | |
| 646 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED) |
| 647 | expect(lines).toEqual([]) |
| 648 | }, |
| 649 | ) |
| 650 | |
| 651 | test( |
| 652 | 'an ask of theirs over an ask rule loosens nothing: one evaluation', |
| 653 | { plugins: [Fixtures.asking('easy')] }, |
| 654 | async ($, on) => { |
| 655 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 656 | |
| 657 | const lines = Fixtures.logged(on) |
| 658 | const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_ASK) |
| 659 | |
| 660 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ASKED) |
| 661 | expect({ lines, evaluations: evaluations() }).toEqual({ |
| 662 | lines: [], |
| 663 | evaluations: 1, |
| 664 | }) |
| 665 | }, |
| 666 | ) |
| 667 | |
| 668 | test( |
| 669 | 'the option that lets them override deny rules lets them override these', |
| 670 | { plugins: [Fixtures.allowing('easy')] }, |
| 671 | async ($, on) => { |
| 672 | on('settings.read', () => ({ value: Fixtures.overridePolicyOf(true) })) |
| 673 | |
| 674 | const lines = Fixtures.logged(on) |
| 675 | |
| 676 | Fixtures.checksAnswered(on, Fixtures.RULE_ASK) |
| 677 | |
| 678 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED) |
| 679 | expect(lines).toEqual([]) |
| 680 | }, |
| 681 | ) |
| 682 | |
| 683 | test( |
| 684 | "the mode's own ask, no rule behind it, is theirs to allow", |
| 685 | { plugins: [Fixtures.allowing('easy')] }, |
| 686 | async ($, on) => { |
| 687 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 688 | |
| 689 | const lines = Fixtures.logged(on) |
| 690 | |
| 691 | Fixtures.checksAnswered(on, Fixtures.ASKED) |
| 692 | |
| 693 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED) |
| 694 | expect(lines).toEqual([]) |
| 695 | }, |
| 696 | ) |
| 697 | |
| 698 | test( |
| 699 | "a deny holds whatever decided it: it may stand before a rule's ask", |
| 700 | { plugins: [Fixtures.allowing('easy')] }, |
| 701 | async ($, on) => { |
| 702 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 703 | |
| 704 | const lines = Fixtures.logged(on) |
| 705 | |
| 706 | Fixtures.checksAnswered(on, Fixtures.PLAIN_DENY) |
| 707 | |
| 708 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.PLAIN_DENY) |
| 709 | |
| 710 | expect(lines).toEqual([ |
| 711 | `transcript: ${Hooks.heldNotice('easy', 'Bash', Fixtures.PLAIN_DENY)}`, |
| 712 | ]) |
| 713 | }, |
| 714 | ) |
| 715 | |
| 716 | test( |
| 717 | 'the notice is no door: a plugin of theirs never runs inside this hook', |
| 718 | { plugins: [Fixtures.sneaking] }, |
| 719 | async ($, on) => { |
| 720 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 721 | |
| 722 | const lines = Fixtures.logged(on) |
| 723 | |
| 724 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 725 | |
| 726 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 727 | |
| 728 | expect(lines).toEqual([ |
| 729 | 'transcript: ' + |
| 730 | Hooks.heldNotice('sneaking', 'Bash', Fixtures.RULE_DENY), |
| 731 | ]) |
| 732 | }, |
| 733 | ) |
| 734 | |
| 735 | test( |
| 736 | 'nor is the notice theirs to drop', |
| 737 | { plugins: [Fixtures.muting] }, |
| 738 | async ($, on) => { |
| 739 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 740 | |
| 741 | const lines = Fixtures.logged(on) |
| 742 | |
| 743 | Fixtures.checksAnswered(on, Fixtures.RULE_ASK) |
| 744 | |
| 745 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_ASK) |
| 746 | |
| 747 | expect(lines).toEqual([ |
| 748 | `transcript: ${Hooks.heldNotice('muting', 'Bash', Fixtures.RULE_ASK)}`, |
| 749 | ]) |
| 750 | }, |
| 751 | ) |
| 752 | |
| 753 | test( |
| 754 | "an organization's line is not theirs to drop; a line of their own is", |
| 755 | { |
| 756 | plugins: [ |
| 757 | Fixtures.muting, |
| 758 | Fixtures.logging('mine'), |
| 759 | Fixtures.logging('bundled', 'builtin'), |
| 760 | Fixtures.logging('suite', 'append'), |
| 761 | ], |
| 762 | }, |
| 763 | async ($, on) => { |
| 764 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 765 | on('session.start', ($, e) => ({ cwd: e.cwd })) |
| 766 | |
| 767 | const heard: string[] = [] |
| 768 | |
| 769 | on('ui.log', ($, e, next) => { |
| 770 | heard.push(next.origin.plugin) |
| 771 | |
| 772 | return { value: undefined } |
| 773 | }) |
| 774 | |
| 775 | await $.session.start(Fixtures.SESSION) |
| 776 | |
| 777 | expect(heard).toEqual(['suite']) |
| 778 | }, |
| 779 | ) |
| 780 | |
| 781 | test( |
| 782 | 'each plugin is told of a kind, by the tool it answered on', |
| 783 | { plugins: [Fixtures.allowingBash, Fixtures.allowingRead] }, |
| 784 | async ($, on) => { |
| 785 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 786 | |
| 787 | const lines = Fixtures.logged(on) |
| 788 | |
| 789 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 790 | |
| 791 | await $.tool.check(Fixtures.CHECKED) |
| 792 | await $.tool.check(Fixtures.CHECKED_READ) |
| 793 | |
| 794 | expect(lines).toEqual([ |
| 795 | `transcript: ${Hooks.heldNotice('basher', 'Bash', Fixtures.RULE_DENY)}`, |
| 796 | `transcript: ${Hooks.heldNotice('reader', 'Read', Fixtures.RULE_DENY)}`, |
| 797 | ]) |
| 798 | }, |
| 799 | ) |
| 800 | |
| 801 | test( |
| 802 | "an organization's appended plugin has its say in the run past theirs", |
| 803 | { |
| 804 | plugins: [Fixtures.allowing('suite', 'append'), Fixtures.blindAllowing], |
| 805 | }, |
| 806 | async ($, on) => { |
| 807 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 808 | |
| 809 | const lines = Fixtures.logged(on) |
| 810 | |
| 811 | Fixtures.checksAnswered(on, Fixtures.RULE_ASK) |
| 812 | |
| 813 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED) |
| 814 | expect(lines).toEqual([]) |
| 815 | }, |
| 816 | ) |
| 817 | |
| 818 | test( |
| 819 | 'a plugin is told once of each kind of thing that held over it', |
| 820 | { plugins: [Fixtures.allowing('easy')] }, |
| 821 | async ($, on) => { |
| 822 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 823 | |
| 824 | const lines = Fixtures.logged(on) |
| 825 | const verdicts = [ |
| 826 | Fixtures.RULE_DENY, |
| 827 | Fixtures.RULE_ASK, |
| 828 | Fixtures.RULE_ASK, |
| 829 | Fixtures.PLAIN_DENY, |
| 830 | Fixtures.RULE_DENY, |
| 831 | ] |
| 832 | const turn = Fixtures.checksAnsweredInTurn(on, verdicts) |
| 833 | |
| 834 | for (const verdict of verdicts) { |
| 835 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(verdict) |
| 836 | turn() |
| 837 | } |
| 838 | |
| 839 | expect(lines).toEqual( |
| 840 | [Fixtures.RULE_DENY, Fixtures.RULE_ASK, Fixtures.PLAIN_DENY].map( |
| 841 | held => `transcript: ${Hooks.heldNotice('easy', 'Bash', held)}`, |
| 842 | ), |
| 843 | ) |
| 844 | }, |
| 845 | ) |
| 846 | |
| 847 | test( |
| 848 | 'a plugin of the person that tightens is heard, with one evaluation', |
| 849 | { plugins: [Fixtures.tightening] }, |
| 850 | async ($, on) => { |
| 851 | const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY) |
| 852 | const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED) |
| 853 | |
| 854 | await $.tool.check(Fixtures.CHECKED) |
| 855 | |
| 856 | const loaded = { reads: reads(), evaluations: evaluations() } |
| 857 | |
| 858 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.PLAIN_DENY) |
| 859 | |
| 860 | expect( |
| 861 | { |
| 862 | reads: reads() - loaded.reads, |
| 863 | evaluations: evaluations() - loaded.evaluations, |
| 864 | }, |
| 865 | 'once its plugins have loaded, a check reads no policy', |
| 866 | ).toEqual({ reads: 0, evaluations: 1 }) |
| 867 | }, |
| 868 | ) |
| 869 | |
| 870 | test( |
| 871 | "a deny rule holds when an organization's plugin listens above theirs", |
| 872 | { |
| 873 | plugins: [ |
| 874 | Fixtures.listening('audit', 'prepend'), |
| 875 | Fixtures.allowing('easy'), |
| 876 | ], |
| 877 | }, |
| 878 | async ($, on) => { |
| 879 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 880 | |
| 881 | const lines = Fixtures.logged(on) |
| 882 | |
| 883 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 884 | |
| 885 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 886 | |
| 887 | expect( |
| 888 | lines.map(line => line.includes('easy')), |
| 889 | 'one line, naming the plugin of theirs, alone or in its batch', |
| 890 | ).toEqual([true]) |
| 891 | }, |
| 892 | ) |
| 893 | |
| 894 | test( |
| 895 | 'a plugin of the person that only listens costs no second evaluation', |
| 896 | { plugins: [Fixtures.listening('listening')] }, |
| 897 | async ($, on) => { |
| 898 | const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY) |
| 899 | const evaluations = Fixtures.checksAnswered(on, Fixtures.ASKED) |
| 900 | |
| 901 | await $.tool.check(Fixtures.CHECKED) |
| 902 | |
| 903 | const loaded = { reads: reads(), evaluations: evaluations() } |
| 904 | |
| 905 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ASKED) |
| 906 | |
| 907 | expect( |
| 908 | { |
| 909 | reads: reads() - loaded.reads, |
| 910 | evaluations: evaluations() - loaded.evaluations, |
| 911 | }, |
| 912 | 'once its plugins have loaded, a check reads no policy', |
| 913 | ).toEqual({ reads: 0, evaluations: 1 }) |
| 914 | }, |
| 915 | ) |
| 916 | |
| 917 | test('with none of their plugins the verdict passes once', async ($, on) => { |
| 918 | const reads = Fixtures.policyReads(on, Fixtures.MANAGED_POLICY) |
| 919 | const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 920 | |
| 921 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 922 | |
| 923 | expect({ reads: reads(), evaluations: evaluations() }).toEqual({ |
| 924 | reads: 0, |
| 925 | evaluations: 1, |
| 926 | }) |
| 927 | }) |
| 928 | |
| 929 | test( |
| 930 | 'an allow that never called next meets the deny rule all the same', |
| 931 | { plugins: [Fixtures.blindAllowing] }, |
| 932 | async ($, on) => { |
| 933 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 934 | |
| 935 | const lines = Fixtures.logged(on) |
| 936 | const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 937 | |
| 938 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 939 | |
| 940 | expect({ lines, evaluations: evaluations() }).toEqual({ |
| 941 | lines: [ |
| 942 | 'transcript: ' + |
| 943 | Hooks.heldNotice('blind', 'Bash', Fixtures.RULE_DENY), |
| 944 | ], |
| 945 | evaluations: 1, |
| 946 | }) |
| 947 | }, |
| 948 | ) |
| 949 | |
| 950 | test( |
| 951 | 'a rule a plugin of the person writes into its answer is never read', |
| 952 | { plugins: [Fixtures.forging] }, |
| 953 | async ($, on) => { |
| 954 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 955 | |
| 956 | const lines = Fixtures.logged(on) |
| 957 | |
| 958 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 959 | |
| 960 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 961 | |
| 962 | expect(lines).toEqual([ |
| 963 | 'transcript: ' + |
| 964 | Hooks.heldNotice('forging', 'Bash', Fixtures.RULE_DENY), |
| 965 | ]) |
| 966 | }, |
| 967 | ) |
| 968 | |
| 969 | test( |
| 970 | 'a plugin of the person asking about another command is left out', |
| 971 | { plugins: [Fixtures.rewriting] }, |
| 972 | async ($, on) => { |
| 973 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 974 | Fixtures.logged(on) |
| 975 | |
| 976 | const asked: unknown[] = [] |
| 977 | |
| 978 | on('tool.check', ($, e) => { |
| 979 | asked.push(e.input) |
| 980 | |
| 981 | return Fixtures.RULE_DENY |
| 982 | }) |
| 983 | |
| 984 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 985 | |
| 986 | expect( |
| 987 | asked, |
| 988 | 'the rules were asked about the command that would run, only', |
| 989 | ).toEqual([Fixtures.CHECKED.input]) |
| 990 | }, |
| 991 | ) |
| 992 | |
| 993 | test( |
| 994 | 'managed settings may let the plugins a person installs override', |
| 995 | { plugins: [Fixtures.allowing('easy')] }, |
| 996 | async ($, on) => { |
| 997 | on('settings.read', () => ({ value: Fixtures.overridePolicyOf(true) })) |
| 998 | |
| 999 | const lines = Fixtures.logged(on) |
| 1000 | const evaluations = Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 1001 | |
| 1002 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.ALLOWED) |
| 1003 | |
| 1004 | expect({ lines, evaluations: evaluations() }).toEqual({ |
| 1005 | lines: [], |
| 1006 | evaluations: 1, |
| 1007 | }) |
| 1008 | }, |
| 1009 | ) |
| 1010 | |
| 1011 | test( |
| 1012 | "only managed settings are asked: a person's own cannot lift a deny rule", |
| 1013 | { plugins: [Fixtures.allowing('easy')] }, |
| 1014 | async ($, on) => { |
| 1015 | Fixtures.policyBySource( |
| 1016 | on, |
| 1017 | Fixtures.MANAGED_POLICY, |
| 1018 | Fixtures.overridePolicyOf(true), |
| 1019 | ) |
| 1020 | |
| 1021 | Fixtures.logged(on) |
| 1022 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 1023 | |
| 1024 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 1025 | }, |
| 1026 | ) |
| 1027 | |
| 1028 | test( |
| 1029 | 'the option mistyped lifts nothing: only the literal true does', |
| 1030 | { plugins: [Fixtures.allowing('easy')] }, |
| 1031 | async ($, on) => { |
| 1032 | on('settings.read', () => ({ value: Fixtures.overridePolicyOf('true') })) |
| 1033 | Fixtures.logged(on) |
| 1034 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 1035 | |
| 1036 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Fixtures.RULE_DENY) |
| 1037 | }, |
| 1038 | ) |
| 1039 | |
| 1040 | test( |
| 1041 | 'with a policy that cannot be read the deny rule holds: fails closed', |
| 1042 | { plugins: [Fixtures.allowing('easy')] }, |
| 1043 | async ($, on) => { |
| 1044 | const stopPolicy = Fixtures.policyUntilStopped( |
| 1045 | on, |
| 1046 | Fixtures.overridePolicyOf(true), |
| 1047 | 'managed settings unreadable', |
| 1048 | ) |
| 1049 | |
| 1050 | Fixtures.logged(on) |
| 1051 | Fixtures.checksAnswered(on, Fixtures.RULE_DENY) |
| 1052 | on('prompt.section', ($, e) => ({ text: e.text })) |
| 1053 | |
| 1054 | await $.prompt.section(Fixtures.MEMORY) |
| 1055 | stopPolicy() |
| 1056 | |
| 1057 | expect( |
| 1058 | await $.tool.check(Fixtures.CHECKED), |
| 1059 | 'the policy that read let plugins override; unread, the rule holds', |
| 1060 | ).toEqual(Fixtures.RULE_DENY) |
| 1061 | }, |
| 1062 | ) |
| 1063 | |
| 1064 | test( |
| 1065 | "when the rules cannot be evaluated the call is refused: the hook's catch", |
| 1066 | { plugins: [Fixtures.blindAllowing] }, |
| 1067 | async ($, on) => { |
| 1068 | on('settings.read', () => ({ value: Fixtures.MANAGED_POLICY })) |
| 1069 | Fixtures.logged(on) |
| 1070 | |
| 1071 | on('tool.check', () => { |
| 1072 | throw new Error('the evaluation failed') |
| 1073 | }) |
| 1074 | |
| 1075 | expect(await $.tool.check(Fixtures.CHECKED)).toEqual(Hooks.UNCHECKED_DENY) |
| 1076 | }, |
| 1077 | ) |
| 1078 | |
| 1079 | test( |
| 1080 | 'a variable managed settings pin is not for a plugin of the person to set', |
| 1081 | { |
| 1082 | plugins: [ |
| 1083 | Fixtures.settingProxy('suite', 'prepend'), |
| 1084 | Fixtures.settingProxy('mine'), |
| 1085 | Fixtures.settingProxy('bundled', 'builtin'), |
| 1086 | ], |
| 1087 | }, |
| 1088 | async ($, on) => { |
| 1089 | on('settings.read', () => ({ value: Fixtures.PINNING_POLICY })) |
| 1090 | |
| 1091 | const lines = Fixtures.logged(on) |
| 1092 | const set = Fixtures.variablesSet(on) |
| 1093 | |
| 1094 | await $.session.start(Fixtures.SESSION) |
| 1095 | |
| 1096 | expect(set).toEqual(['suite CORP_PROXY=mine', 'bundled CORP_PROXY=mine']) |
| 1097 | expect(lines).toHaveLength(1) |
| 1098 | expect(lines[0]).toContain(Hooks.pinnedVariableRefusal('CORP_PROXY')) |
| 1099 | }, |
| 1100 | ) |
| 1101 | |
| 1102 | test( |
| 1103 | 'nor to unset', |
| 1104 | { plugins: [Fixtures.unsettingProxy] }, |
| 1105 | async ($, on) => { |
| 1106 | on('settings.read', () => ({ value: Fixtures.PINNING_POLICY })) |
| 1107 | |
| 1108 | const set = Fixtures.variablesSet(on) |
| 1109 | |
| 1110 | await $.session.start(Fixtures.SESSION) |
| 1111 | |
| 1112 | expect(set).toEqual([]) |
| 1113 | }, |
| 1114 | ) |
| 1115 | |
| 1116 | test( |
| 1117 | 'nor under another case, which some systems read as the same name', |
| 1118 | { plugins: [Fixtures.settingLowerCase] }, |
| 1119 | async ($, on) => { |
| 1120 | on('settings.read', () => ({ value: Fixtures.PINNING_POLICY })) |
| 1121 | Fixtures.logged(on) |
| 1122 | |
| 1123 | const set = Fixtures.variablesSet(on) |
| 1124 | |
| 1125 | await $.session.start(Fixtures.SESSION) |
| 1126 | |
| 1127 | expect(set).toEqual([]) |
| 1128 | }, |
| 1129 | ) |
| 1130 | |
| 1131 | test( |
| 1132 | "nor to rewrite while an organization's plugin sets it", |
| 1133 | { |
| 1134 | plugins: [ |
| 1135 | Fixtures.revaluing, |
| 1136 | Fixtures.settingProxy('suite', 'append'), |
| 1137 | Fixtures.settingOther('audit', 'append'), |
| 1138 | ], |
| 1139 | }, |
| 1140 | async ($, on) => { |
| 1141 | on('settings.read', () => ({ value: Fixtures.PINNING_POLICY })) |
| 1142 | |
| 1143 | const set = Fixtures.variablesSet(on) |
| 1144 | |
| 1145 | await $.session.start(Fixtures.SESSION) |
| 1146 | |
| 1147 | expect(set.toSorted()).toEqual([ |
| 1148 | 'audit OTHER=theirs', |
| 1149 | 'suite CORP_PROXY=mine', |
| 1150 | ]) |
| 1151 | }, |
| 1152 | ) |
| 1153 | |
| 1154 | test( |
| 1155 | 'the option that lets them override deny rules unpins nothing', |
| 1156 | { plugins: [Fixtures.settingProxy('mine')] }, |
| 1157 | async ($, on) => { |
| 1158 | on('settings.read', () => ({ |
| 1159 | value: { |
| 1160 | ...Fixtures.overridePolicyOf(true), |
| 1161 | ...Fixtures.PINNING_POLICY, |
| 1162 | }, |
| 1163 | })) |
| 1164 | Fixtures.logged(on) |
| 1165 | |
| 1166 | const set = Fixtures.variablesSet(on) |
| 1167 | |
| 1168 | await $.session.start(Fixtures.SESSION) |
| 1169 | |
| 1170 | expect(set).toEqual([]) |
| 1171 | }, |
| 1172 | ) |
| 1173 | |
| 1174 | test( |
| 1175 | 'a variable managed settings do not pin is theirs to set', |
| 1176 | { plugins: [Fixtures.settingOther('mine')] }, |
| 1177 | async ($, on) => { |
| 1178 | on('settings.read', () => ({ value: Fixtures.PINNING_POLICY })) |
| 1179 | |
| 1180 | const set = Fixtures.variablesSet(on) |
| 1181 | |
| 1182 | await $.session.start(Fixtures.SESSION) |
| 1183 | |
| 1184 | expect(set).toEqual(['mine OTHER=mine']) |
| 1185 | }, |
| 1186 | ) |
| 1187 | |
| 1188 | test( |
| 1189 | "only managed settings pin: a person's own env binds no plugin", |
| 1190 | { plugins: [Fixtures.settingProxy('mine')] }, |
| 1191 | async ($, on) => { |
| 1192 | Fixtures.policyBySource( |
| 1193 | on, |
| 1194 | Fixtures.MANAGED_POLICY, |
| 1195 | Fixtures.PINNING_POLICY, |
| 1196 | ) |
| 1197 | |
| 1198 | const set = Fixtures.variablesSet(on) |
| 1199 | |
| 1200 | await $.session.start(Fixtures.SESSION) |
| 1201 | |
| 1202 | expect(set).toEqual(['mine CORP_PROXY=mine']) |
| 1203 | }, |
| 1204 | ) |
| 1205 | |
| 1206 | test( |
| 1207 | 'with a policy that cannot be read they set no variable: fails closed', |
| 1208 | { plugins: [Fixtures.settingOther('mine')] }, |
| 1209 | async ($, on) => { |
| 1210 | const stopPolicy = Fixtures.policyUntilStopped( |
| 1211 | on, |
| 1212 | Fixtures.MANAGED_POLICY, |
| 1213 | 'managed settings unreadable', |
| 1214 | ) |
| 1215 | |
| 1216 | Fixtures.logged(on) |
| 1217 | |
| 1218 | on('prompt.section', ($, e) => ({ text: e.text })) |
| 1219 | |
| 1220 | const set = Fixtures.variablesSet(on) |
| 1221 | |
| 1222 | await $.prompt.section(Fixtures.MEMORY) |
| 1223 | stopPolicy() |
| 1224 | await $.session.start(Fixtures.SESSION) |
| 1225 | |
| 1226 | expect(set).toEqual([]) |
| 1227 | }, |
| 1228 | ) |
| 1229 | }) |