From 53f8617b249c9f0443f5082a293a30504a118030 Mon Sep 17 00:00:00 2001 From: shrutip90 Date: Thu, 7 Aug 2025 14:06:17 -0700 Subject: [PATCH] Add new folderTrust setting that the users can enable or disable (#5798) --- packages/cli/src/config/config.test.ts | 52 ++++++++++++++++++++++ packages/cli/src/config/config.ts | 3 ++ packages/cli/src/config/settings.test.ts | 56 ++++++++++++++++++++++++ packages/cli/src/config/settings.ts | 12 ++++- packages/core/src/config/config.ts | 11 ++++- 5 files changed, 130 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/config/config.test.ts b/packages/cli/src/config/config.test.ts index b670fbc8..1d83ccbc 100644 --- a/packages/cli/src/config/config.test.ts +++ b/packages/cli/src/config/config.test.ts @@ -1042,6 +1042,58 @@ describe('loadCliConfig folderTrustFeature', () => { }); }); +describe('loadCliConfig folderTrust', () => { + const originalArgv = process.argv; + const originalEnv = { ...process.env }; + + beforeEach(() => { + vi.resetAllMocks(); + vi.mocked(os.homedir).mockReturnValue('/mock/home/user'); + process.env.GEMINI_API_KEY = 'test-api-key'; + }); + + afterEach(() => { + process.argv = originalArgv; + process.env = originalEnv; + vi.restoreAllMocks(); + }); + + it('should be false if folderTrustFeature is false and folderTrust is false', async () => { + process.argv = ['node', 'script.js']; + const settings: Settings = { + folderTrustFeature: false, + folderTrust: false, + }; + const argv = await parseArguments(); + const config = await loadCliConfig(settings, [], 'test-session', argv); + expect(config.getFolderTrust()).toBe(false); + }); + + it('should be false if folderTrustFeature is true and folderTrust is false', async () => { + process.argv = ['node', 'script.js']; + const argv = await parseArguments(); + const settings: Settings = { folderTrustFeature: true, folderTrust: false }; + const config = await loadCliConfig(settings, [], 'test-session', argv); + expect(config.getFolderTrust()).toBe(false); + }); + + it('should be false if folderTrustFeature is false and folderTrust is true', async () => { + process.argv = ['node', 'script.js']; + const argv = await parseArguments(); + const settings: Settings = { folderTrustFeature: false, folderTrust: true }; + const config = await loadCliConfig(settings, [], 'test-session', argv); + expect(config.getFolderTrust()).toBe(false); + }); + + it('should be true when folderTrustFeature is true and folderTrust is true', async () => { + process.argv = ['node', 'script.js']; + const argv = await parseArguments(); + const settings: Settings = { folderTrustFeature: true, folderTrust: true }; + const config = await loadCliConfig(settings, [], 'test-session', argv); + expect(config.getFolderTrust()).toBe(true); + }); +}); + vi.mock('fs', async () => { const actualFs = await vi.importActual('fs'); const MOCK_CWD1 = process.cwd(); diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index a47d8301..3104e4c1 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -314,6 +314,8 @@ export async function loadCliConfig( argv.ideModeFeature ?? settings.ideModeFeature ?? false; const folderTrustFeature = settings.folderTrustFeature ?? false; + const folderTrustSetting = settings.folderTrust ?? false; + const folderTrust = folderTrustFeature && folderTrustSetting; const allExtensions = annotateActiveExtensions( extensions, @@ -484,6 +486,7 @@ export async function loadCliConfig( ideModeFeature, chatCompression: settings.chatCompression, folderTrustFeature, + folderTrust, }); } diff --git a/packages/cli/src/config/settings.test.ts b/packages/cli/src/config/settings.test.ts index f68b13e3..353a5783 100644 --- a/packages/cli/src/config/settings.test.ts +++ b/packages/cli/src/config/settings.test.ts @@ -310,6 +310,62 @@ describe('Settings Loading and Merging', () => { }); }); + it('should ignore folderTrust from workspace settings', () => { + (mockFsExistsSync as Mock).mockReturnValue(true); + const userSettingsContent = { + folderTrust: true, + }; + const workspaceSettingsContent = { + folderTrust: false, // This should be ignored + }; + const systemSettingsContent = { + // No folderTrust here + }; + + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === getSystemSettingsPath()) + return JSON.stringify(systemSettingsContent); + if (p === USER_SETTINGS_PATH) + return JSON.stringify(userSettingsContent); + if (p === MOCK_WORKSPACE_SETTINGS_PATH) + return JSON.stringify(workspaceSettingsContent); + return '{}'; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + expect(settings.merged.folderTrust).toBe(true); // User setting should be used + }); + + it('should use system folderTrust over user setting', () => { + (mockFsExistsSync as Mock).mockReturnValue(true); + const userSettingsContent = { + folderTrust: false, + }; + const workspaceSettingsContent = { + folderTrust: true, // This should be ignored + }; + const systemSettingsContent = { + folderTrust: true, + }; + + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === getSystemSettingsPath()) + return JSON.stringify(systemSettingsContent); + if (p === USER_SETTINGS_PATH) + return JSON.stringify(userSettingsContent); + if (p === MOCK_WORKSPACE_SETTINGS_PATH) + return JSON.stringify(workspaceSettingsContent); + return '{}'; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + expect(settings.merged.folderTrust).toBe(true); // System setting should be used + }); + it('should handle contextFileName correctly when only in user settings', () => { (mockFsExistsSync as Mock).mockImplementation( (p: fs.PathLike) => p === USER_SETTINGS_PATH, diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index 8005ad65..a3bd8d47 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -113,10 +113,14 @@ export interface Settings { // Flag to be removed post-launch. ideModeFeature?: boolean; - folderTrustFeature?: boolean; /// IDE mode setting configured via slash command toggle. ideMode?: boolean; + // Flag to be removed post-launch. + folderTrustFeature?: boolean; + // Setting to track whether Folder trust is enabled. + folderTrust?: boolean; + // Setting to track if the user has seen the IDE integration nudge. hasSeenIdeIntegrationNudge?: boolean; @@ -178,9 +182,13 @@ export class LoadedSettings { const user = this.user.settings; const workspace = this.workspace.settings; + // folderTrust is not supported at workspace level. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { folderTrust, ...workspaceWithoutFolderTrust } = workspace; + return { ...user, - ...workspace, + ...workspaceWithoutFolderTrust, ...system, customThemes: { ...(user.customThemes || {}), diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 4848bfb6..db226c76 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -193,6 +193,7 @@ export interface ConfigParameters { summarizeToolOutput?: Record; ideModeFeature?: boolean; folderTrustFeature?: boolean; + folderTrust?: boolean; ideMode?: boolean; loadMemoryFromIncludeDirectories?: boolean; chatCompression?: ChatCompressionSettings; @@ -240,6 +241,7 @@ export class Config { private readonly noBrowser: boolean; private readonly ideModeFeature: boolean; private readonly folderTrustFeature: boolean; + private readonly folderTrust: boolean; private ideMode: boolean; private ideClient: IdeClient; private inFallbackMode = false; @@ -314,6 +316,7 @@ export class Config { this.summarizeToolOutput = params.summarizeToolOutput; this.ideModeFeature = params.ideModeFeature ?? false; this.folderTrustFeature = params.folderTrustFeature ?? false; + this.folderTrust = params.folderTrust ?? false; this.ideMode = params.ideMode ?? false; this.ideClient = IdeClient.getInstance(); if (this.ideMode && this.ideModeFeature) { @@ -648,12 +651,16 @@ export class Config { return this.ideModeFeature; } + getIdeMode(): boolean { + return this.ideMode; + } + getFolderTrustFeature(): boolean { return this.folderTrustFeature; } - getIdeMode(): boolean { - return this.ideMode; + getFolderTrust(): boolean { + return this.folderTrust; } setIdeMode(value: boolean): void {