mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-23 11:34:44 -07:00
Security: Project-level hook warnings (#15470)
This commit is contained in:
@@ -8,7 +8,6 @@ import yargs from 'yargs/yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import process from 'node:process';
|
||||
import { mcpCommand } from '../commands/mcp.js';
|
||||
import type { OutputFormat } from '@google/gemini-cli-core';
|
||||
import { extensionsCommand } from '../commands/extensions.js';
|
||||
import { hooksCommand } from '../commands/hooks.js';
|
||||
import {
|
||||
@@ -33,6 +32,9 @@ import {
|
||||
WEB_FETCH_TOOL_NAME,
|
||||
getVersion,
|
||||
PREVIEW_GEMINI_MODEL_AUTO,
|
||||
type HookDefinition,
|
||||
type HookEventName,
|
||||
type OutputFormat,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Settings } from './settings.js';
|
||||
import { saveModelChange, loadSettings } from './settings.js';
|
||||
@@ -380,12 +382,20 @@ export function isDebugMode(argv: CliArgs): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
export interface LoadCliConfigOptions {
|
||||
cwd?: string;
|
||||
projectHooks?: { [K in HookEventName]?: HookDefinition[] } & {
|
||||
disabled?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadCliConfig(
|
||||
settings: Settings,
|
||||
sessionId: string,
|
||||
argv: CliArgs,
|
||||
cwd: string = process.cwd(),
|
||||
options: LoadCliConfigOptions = {},
|
||||
): Promise<Config> {
|
||||
const { cwd = process.cwd(), projectHooks } = options;
|
||||
const debugMode = isDebugMode(argv);
|
||||
|
||||
const loadedSettings = loadSettings(cwd);
|
||||
@@ -696,6 +706,7 @@ export async function loadCliConfig(
|
||||
// TODO: loading of hooks based on workspace trust
|
||||
enableHooks: settings.tools?.enableHooks ?? false,
|
||||
hooks: settings.hooks || {},
|
||||
projectHooks: projectHooks || {},
|
||||
onModelChange: (model: string) => saveModelChange(loadedSettings, model),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ vi.mock('./config/settings.js', () => ({
|
||||
security: { auth: {} },
|
||||
ui: {},
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -289,6 +290,7 @@ describe('gemini.tsx main function', () => {
|
||||
security: { auth: {} },
|
||||
ui: {},
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
} as never);
|
||||
@@ -522,6 +524,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
security: { auth: {} },
|
||||
ui: {},
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
} as never);
|
||||
@@ -583,6 +586,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
security: { auth: {} },
|
||||
ui: {},
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -669,6 +673,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
security: { auth: {} },
|
||||
ui: {},
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -737,6 +742,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
security: { auth: {} },
|
||||
ui: { theme: 'non-existent-theme' },
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -819,6 +825,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
|
||||
vi.mocked(loadSettings).mockReturnValue({
|
||||
merged: { advanced: {}, security: { auth: {} }, ui: { theme: 'test' } },
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -898,6 +905,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
|
||||
vi.mocked(loadSettings).mockReturnValue({
|
||||
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -971,6 +979,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
|
||||
vi.mocked(loadSettings).mockReturnValue({
|
||||
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -1118,6 +1127,7 @@ describe('gemini.tsx main function exit codes', () => {
|
||||
security: { auth: { selectedType: 'google', useExternal: false } },
|
||||
ui: {},
|
||||
},
|
||||
workspace: { settings: {} },
|
||||
errors: [],
|
||||
} as never);
|
||||
vi.mocked(parseArguments).mockResolvedValue({} as unknown as CliArgs);
|
||||
@@ -1174,6 +1184,7 @@ describe('gemini.tsx main function exit codes', () => {
|
||||
} as unknown as Config);
|
||||
vi.mocked(loadSettings).mockReturnValue({
|
||||
merged: { security: { auth: {} }, ui: {} },
|
||||
workspace: { settings: {} },
|
||||
errors: [],
|
||||
} as never);
|
||||
vi.mocked(parseArguments).mockResolvedValue({
|
||||
@@ -1237,6 +1248,7 @@ describe('gemini.tsx main function exit codes', () => {
|
||||
} as unknown as Config);
|
||||
vi.mocked(loadSettings).mockReturnValue({
|
||||
merged: { security: { auth: {} }, ui: {} },
|
||||
workspace: { settings: {} },
|
||||
errors: [],
|
||||
} as never);
|
||||
vi.mocked(parseArguments).mockResolvedValue({} as unknown as CliArgs);
|
||||
|
||||
@@ -393,6 +393,7 @@ export async function main() {
|
||||
settings.merged,
|
||||
sessionId,
|
||||
argv,
|
||||
{ projectHooks: settings.workspace.settings.hooks },
|
||||
);
|
||||
|
||||
if (
|
||||
@@ -464,7 +465,9 @@ export async function main() {
|
||||
// may have side effects.
|
||||
{
|
||||
const loadConfigHandle = startupProfiler.start('load_cli_config');
|
||||
const config = await loadCliConfig(settings.merged, sessionId, argv);
|
||||
const config = await loadCliConfig(settings.merged, sessionId, argv, {
|
||||
projectHooks: settings.workspace.settings.hooks,
|
||||
});
|
||||
loadConfigHandle?.end();
|
||||
|
||||
// Register config for telemetry shutdown
|
||||
|
||||
@@ -60,6 +60,7 @@ vi.mock('./config/settings.js', async (importOriginal) => {
|
||||
...actual,
|
||||
loadSettings: vi.fn().mockReturnValue({
|
||||
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
@@ -171,6 +172,7 @@ describe('gemini.tsx main function cleanup', () => {
|
||||
|
||||
vi.mocked(loadSettings).mockReturnValue({
|
||||
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
||||
workspace: { settings: {} },
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
errors: [],
|
||||
|
||||
@@ -180,7 +180,7 @@ describe('GeminiAgent', () => {
|
||||
}),
|
||||
'test-session-id',
|
||||
mockArgv,
|
||||
'/tmp',
|
||||
{ cwd: '/tmp' },
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ export class GeminiAgent {
|
||||
|
||||
const settings = { ...this.settings.merged, mcpServers: mergedMcpServers };
|
||||
|
||||
const config = await loadCliConfig(settings, sessionId, this.argv, cwd);
|
||||
const config = await loadCliConfig(settings, sessionId, this.argv, { cwd });
|
||||
|
||||
await config.initialize();
|
||||
startupProfiler.flush(config);
|
||||
|
||||
Reference in New Issue
Block a user