Download packages/core/src/hooks/trustedHooks.test.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 5.54 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/hooks/trustedHooks.test.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/core/src/hooks/trustedHooks.test.ts
-
curl -L -o trustedHooks.test.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/hooks/trustedHooks.test.ts
5.54 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { describe, it, expect, vi, beforeEach } from 'vitest'; | |
| import * as fs from 'node:fs'; | |
| import { TrustedHooksManager } from './trustedHooks.js'; | |
| import { Storage } from '../config/storage.js'; | |
| import { HookEventName, HookType, type HookDefinition } from './types.js'; | |
| vi.mock('node:fs'); | |
| vi.mock('../config/storage.js'); | |
| vi.mock('../utils/debugLogger.js', () => ({ | |
| debugLogger: { | |
| warn: vi.fn(), | |
| error: vi.fn(), | |
| log: vi.fn(), | |
| debug: vi.fn(), | |
| }, | |
| })); | |
| describe('TrustedHooksManager', () => { | |
| beforeEach(() => { | |
| vi.resetAllMocks(); | |
| vi.mocked(Storage.getGlobalGeminiDir).mockReturnValue('/mock/home/.gemini'); | |
| }); | |
| describe('initialization', () => { | |
| it('should load existing trusted hooks', () => { | |
| const existingData = { | |
| '/project/a': ['hook1:cmd1'], | |
| }; | |
| vi.mocked(fs.existsSync).mockReturnValue(true); | |
| vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(existingData)); | |
| const manager = new TrustedHooksManager(); | |
| const untrusted = manager.getUntrustedHooks('/project/a', { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [{ type: HookType.Command, command: 'cmd1', name: 'hook1' }], | |
| }, | |
| ], | |
| }); | |
| expect(untrusted).toHaveLength(0); | |
| }); | |
| it('should handle missing config file', () => { | |
| vi.mocked(fs.existsSync).mockReturnValue(false); | |
| const manager = new TrustedHooksManager(); | |
| const untrusted = manager.getUntrustedHooks('/project/a', { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [{ type: HookType.Command, command: 'cmd1', name: 'hook1' }], | |
| }, | |
| ], | |
| }); | |
| expect(untrusted).toEqual(['hook1']); | |
| }); | |
| }); | |
| describe('getUntrustedHooks', () => { | |
| it('should return names of untrusted hooks', () => { | |
| vi.mocked(fs.existsSync).mockReturnValue(false); | |
| const manager = new TrustedHooksManager(); | |
| const projectHooks = { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [ | |
| { | |
| name: 'trusted-hook', | |
| type: HookType.Command, | |
| command: 'cmd1', | |
| } as const, | |
| { | |
| name: 'new-hook', | |
| type: HookType.Command, | |
| command: 'cmd2', | |
| } as const, | |
| ], | |
| }, | |
| ], | |
| }; | |
| // Initially both are untrusted | |
| expect(manager.getUntrustedHooks('/project', projectHooks)).toEqual([ | |
| 'trusted-hook', | |
| 'new-hook', | |
| ]); | |
| // Trust one | |
| manager.trustHooks('/project', { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [ | |
| { | |
| name: 'trusted-hook', | |
| type: HookType.Command, | |
| command: 'cmd1', | |
| } as const, | |
| ], | |
| }, | |
| ], | |
| }); | |
| // Only the other one is untrusted | |
| expect(manager.getUntrustedHooks('/project', projectHooks)).toEqual([ | |
| 'new-hook', | |
| ]); | |
| }); | |
| it('should use command if name is missing', () => { | |
| vi.mocked(fs.existsSync).mockReturnValue(false); | |
| const manager = new TrustedHooksManager(); | |
| const projectHooks = { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [{ type: HookType.Command, command: './script.sh' }], | |
| }, | |
| ], | |
| }; | |
| expect( | |
| manager.getUntrustedHooks( | |
| '/project', | |
| projectHooks as Partial<Record<HookEventName, HookDefinition[]>>, | |
| ), | |
| ).toEqual(['./script.sh']); | |
| }); | |
| it('should detect change in command as untrusted', () => { | |
| vi.mocked(fs.existsSync).mockReturnValue(false); | |
| const manager = new TrustedHooksManager(); | |
| const originalHook = { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [ | |
| { name: 'my-hook', type: HookType.Command, command: 'old-cmd' }, | |
| ], | |
| }, | |
| ], | |
| }; | |
| const updatedHook = { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [ | |
| { name: 'my-hook', type: HookType.Command, command: 'new-cmd' }, | |
| ], | |
| }, | |
| ], | |
| }; | |
| manager.trustHooks( | |
| '/project', | |
| originalHook as Partial<Record<HookEventName, HookDefinition[]>>, | |
| ); | |
| expect( | |
| manager.getUntrustedHooks( | |
| '/project', | |
| updatedHook as Partial<Record<HookEventName, HookDefinition[]>>, | |
| ), | |
| ).toEqual(['my-hook']); | |
| }); | |
| }); | |
| describe('persistence', () => { | |
| it('should save to file when trusting hooks', () => { | |
| vi.mocked(fs.existsSync).mockReturnValue(false); | |
| const manager = new TrustedHooksManager(); | |
| manager.trustHooks('/project', { | |
| [HookEventName.BeforeTool]: [ | |
| { | |
| hooks: [{ name: 'hook1', type: HookType.Command, command: 'cmd1' }], | |
| }, | |
| ], | |
| }); | |
| expect(fs.writeFileSync).toHaveBeenCalledWith( | |
| expect.stringContaining('trusted_hooks.json'), | |
| expect.stringContaining('hook1:cmd1'), | |
| ); | |
| }); | |
| it('should create directory if missing on save', () => { | |
| vi.mocked(fs.existsSync).mockReturnValue(false); | |
| const manager = new TrustedHooksManager(); | |
| manager.trustHooks('/project', {}); | |
| expect(fs.mkdirSync).toHaveBeenCalledWith(expect.any(String), { | |
| recursive: true, | |
| }); | |
| }); | |
| }); | |
| }); | |