mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-22 19:14:33 -07:00
fix(trust): Update config.isTrustedFolder (#7373)
This commit is contained in:
@@ -675,69 +675,47 @@ describe('Server Config (config.ts)', () => {
|
||||
});
|
||||
|
||||
describe('setApprovalMode with folder trust', () => {
|
||||
const baseParams: ConfigParameters = {
|
||||
sessionId: 'test',
|
||||
targetDir: '.',
|
||||
debugMode: false,
|
||||
model: 'test-model',
|
||||
cwd: '.',
|
||||
};
|
||||
|
||||
it('should throw an error when setting YOLO mode in an untrusted folder', () => {
|
||||
const config = new Config({
|
||||
sessionId: 'test',
|
||||
targetDir: '.',
|
||||
debugMode: false,
|
||||
model: 'test-model',
|
||||
cwd: '.',
|
||||
trustedFolder: false, // Untrusted
|
||||
});
|
||||
const config = new Config(baseParams);
|
||||
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(false);
|
||||
expect(() => config.setApprovalMode(ApprovalMode.YOLO)).toThrow(
|
||||
'Cannot enable privileged approval modes in an untrusted folder.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error when setting AUTO_EDIT mode in an untrusted folder', () => {
|
||||
const config = new Config({
|
||||
sessionId: 'test',
|
||||
targetDir: '.',
|
||||
debugMode: false,
|
||||
model: 'test-model',
|
||||
cwd: '.',
|
||||
trustedFolder: false, // Untrusted
|
||||
});
|
||||
const config = new Config(baseParams);
|
||||
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(false);
|
||||
expect(() => config.setApprovalMode(ApprovalMode.AUTO_EDIT)).toThrow(
|
||||
'Cannot enable privileged approval modes in an untrusted folder.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should NOT throw an error when setting DEFAULT mode in an untrusted folder', () => {
|
||||
const config = new Config({
|
||||
sessionId: 'test',
|
||||
targetDir: '.',
|
||||
debugMode: false,
|
||||
model: 'test-model',
|
||||
cwd: '.',
|
||||
trustedFolder: false, // Untrusted
|
||||
});
|
||||
const config = new Config(baseParams);
|
||||
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(false);
|
||||
expect(() => config.setApprovalMode(ApprovalMode.DEFAULT)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should NOT throw an error when setting any mode in a trusted folder', () => {
|
||||
const config = new Config({
|
||||
sessionId: 'test',
|
||||
targetDir: '.',
|
||||
debugMode: false,
|
||||
model: 'test-model',
|
||||
cwd: '.',
|
||||
trustedFolder: true, // Trusted
|
||||
});
|
||||
const config = new Config(baseParams);
|
||||
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true);
|
||||
expect(() => config.setApprovalMode(ApprovalMode.YOLO)).not.toThrow();
|
||||
expect(() => config.setApprovalMode(ApprovalMode.AUTO_EDIT)).not.toThrow();
|
||||
expect(() => config.setApprovalMode(ApprovalMode.DEFAULT)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should NOT throw an error when setting any mode if trustedFolder is undefined', () => {
|
||||
const config = new Config({
|
||||
sessionId: 'test',
|
||||
targetDir: '.',
|
||||
debugMode: false,
|
||||
model: 'test-model',
|
||||
cwd: '.',
|
||||
trustedFolder: undefined, // Undefined
|
||||
});
|
||||
const config = new Config(baseParams);
|
||||
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true); // isTrustedFolder defaults to true
|
||||
expect(() => config.setApprovalMode(ApprovalMode.YOLO)).not.toThrow();
|
||||
expect(() => config.setApprovalMode(ApprovalMode.AUTO_EDIT)).not.toThrow();
|
||||
expect(() => config.setApprovalMode(ApprovalMode.DEFAULT)).not.toThrow();
|
||||
|
||||
@@ -572,7 +572,7 @@ export class Config {
|
||||
}
|
||||
|
||||
setApprovalMode(mode: ApprovalMode): void {
|
||||
if (this.isTrustedFolder() === false && mode !== ApprovalMode.DEFAULT) {
|
||||
if (!this.isTrustedFolder() && mode !== ApprovalMode.DEFAULT) {
|
||||
throw new Error(
|
||||
'Cannot enable privileged approval modes in an untrusted folder.',
|
||||
);
|
||||
@@ -730,8 +730,18 @@ export class Config {
|
||||
return this.folderTrust;
|
||||
}
|
||||
|
||||
isTrustedFolder(): boolean | undefined {
|
||||
return this.trustedFolder;
|
||||
isTrustedFolder(): boolean {
|
||||
// isWorkspaceTrusted in cli/src/config/trustedFolder.js returns undefined
|
||||
// when the file based trust value is unavailable, since it is mainly used
|
||||
// in the initialization for trust dialogs, etc. Here we return true since
|
||||
// config.isTrustedFolder() is used for the main business logic of blocking
|
||||
// tool calls etc in the rest of the application.
|
||||
//
|
||||
// Default value is true since we load with trusted settings to avoid
|
||||
// restarts in the more common path. If the user chooses to mark the folder
|
||||
// as untrusted, the CLI will restart and we will have the trust value
|
||||
// reloaded.
|
||||
return this.trustedFolder ?? true;
|
||||
}
|
||||
|
||||
setIdeMode(value: boolean): void {
|
||||
|
||||
@@ -55,33 +55,6 @@ describe('McpClientManager', () => {
|
||||
expect(mockedMcpClient.discover).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should discover tools if isTrustedFolder is undefined', async () => {
|
||||
const mockedMcpClient = {
|
||||
connect: vi.fn(),
|
||||
discover: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
getStatus: vi.fn(),
|
||||
};
|
||||
vi.mocked(McpClient).mockReturnValue(
|
||||
mockedMcpClient as unknown as McpClient,
|
||||
);
|
||||
const manager = new McpClientManager(
|
||||
{
|
||||
'test-server': {},
|
||||
},
|
||||
'',
|
||||
{} as ToolRegistry,
|
||||
{} as PromptRegistry,
|
||||
false,
|
||||
{} as WorkspaceContext,
|
||||
);
|
||||
await manager.discoverAllMcpTools({
|
||||
isTrustedFolder: () => undefined,
|
||||
} as unknown as Config);
|
||||
expect(mockedMcpClient.connect).toHaveBeenCalledOnce();
|
||||
expect(mockedMcpClient.discover).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should not discover tools if folder is not trusted', async () => {
|
||||
const mockedMcpClient = {
|
||||
connect: vi.fn(),
|
||||
|
||||
@@ -56,7 +56,7 @@ export class McpClientManager {
|
||||
* them with the `ToolRegistry`.
|
||||
*/
|
||||
async discoverAllMcpTools(cliConfig: Config): Promise<void> {
|
||||
if (cliConfig.isTrustedFolder() === false) {
|
||||
if (!cliConfig.isTrustedFolder()) {
|
||||
return;
|
||||
}
|
||||
await this.stop();
|
||||
|
||||
@@ -598,6 +598,8 @@ describe('DiscoveredMCPTool', () => {
|
||||
inputSchema,
|
||||
undefined,
|
||||
true,
|
||||
undefined,
|
||||
{ isTrustedFolder: () => true } as any,
|
||||
);
|
||||
const invocation = trustedTool.build({ param: 'mock' });
|
||||
expect(
|
||||
@@ -809,25 +811,6 @@ describe('DiscoveredMCPTool', () => {
|
||||
expect(confirmation).not.toBe(false);
|
||||
expect(confirmation).toHaveProperty('type', 'mcp');
|
||||
});
|
||||
|
||||
it('should return false if trust is true and folder trust is undefined', async () => {
|
||||
// The check is `isTrustedFolder() !== false`, so `undefined` should pass
|
||||
const trustedTool = new DiscoveredMCPTool(
|
||||
mockCallableToolInstance,
|
||||
serverName,
|
||||
serverToolName,
|
||||
baseDescription,
|
||||
inputSchema,
|
||||
undefined,
|
||||
true, // trust = true
|
||||
undefined,
|
||||
mockConfig(undefined) as any, // isTrustedFolder = undefined
|
||||
);
|
||||
const invocation = trustedTool.build({ param: 'mock' });
|
||||
expect(
|
||||
await invocation.shouldConfirmExecute(new AbortController().signal),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DiscoveredMCPToolInvocation', () => {
|
||||
|
||||
@@ -82,9 +82,7 @@ class DiscoveredMCPToolInvocation extends BaseToolInvocation<
|
||||
const serverAllowListKey = this.serverName;
|
||||
const toolAllowListKey = `${this.serverName}.${this.serverToolName}`;
|
||||
|
||||
const isTrustedFolder = this.cliConfig?.isTrustedFolder() !== false;
|
||||
|
||||
if (this.trust && isTrustedFolder) {
|
||||
if (this.cliConfig?.isTrustedFolder() && this.trust) {
|
||||
return false; // server is trusted, no confirmation needed
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user