feat(admin): add support for MCP configuration via admin controls (pt1) (#18223)

This commit is contained in:
Shreya Keshive
2026-02-03 16:19:14 -05:00
committed by GitHub
parent 53027af94c
commit 1fc59484b1
10 changed files with 407 additions and 201 deletions
+10 -134
View File
@@ -2216,8 +2216,11 @@ describe('Settings Loading and Merging', () => {
// 2. Now, set remote admin settings.
loadedSettings.setRemoteAdminSettings({
strictModeDisabled: false,
mcpSetting: { mcpEnabled: false },
cliFeatureSetting: { extensionsSetting: { extensionsEnabled: false } },
mcpSetting: { mcpEnabled: false, mcpConfig: {} },
cliFeatureSetting: {
extensionsSetting: { extensionsEnabled: false },
unmanagedCapabilitiesEnabled: false,
},
});
// 3. Verify that remote admin settings take precedence.
@@ -2257,8 +2260,11 @@ describe('Settings Loading and Merging', () => {
const newRemoteSettings = {
strictModeDisabled: false,
mcpSetting: { mcpEnabled: false },
cliFeatureSetting: { extensionsSetting: { extensionsEnabled: false } },
mcpSetting: { mcpEnabled: false, mcpConfig: {} },
cliFeatureSetting: {
extensionsSetting: { extensionsEnabled: false },
unmanagedCapabilitiesEnabled: false,
},
};
loadedSettings.setRemoteAdminSettings(newRemoteSettings);
@@ -2269,13 +2275,6 @@ describe('Settings Loading and Merging', () => {
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
// Non-admin settings should remain untouched
expect(loadedSettings.merged.ui?.theme).toBe('initial-theme');
// Verify that calling setRemoteAdminSettings with partial data overwrites previous remote settings
// and missing properties revert to schema defaults.
loadedSettings.setRemoteAdminSettings({ strictModeDisabled: true });
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false); // Defaulting to false if missing
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false); // Defaulting to false if missing
});
it('should correctly handle undefined remote admin settings', () => {
@@ -2307,84 +2306,6 @@ describe('Settings Loading and Merging', () => {
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true);
});
it('should correctly handle missing properties in remote admin settings', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const systemSettingsContent = {
admin: {
secureModeEnabled: true,
},
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === getSystemSettingsPath()) {
return JSON.stringify(systemSettingsContent);
}
return '{}';
},
);
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
// Ensure initial state from defaults (as file-based admin settings are ignored)
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(true);
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(true);
// Set remote settings with only strictModeDisabled (false -> secureModeEnabled: true)
loadedSettings.setRemoteAdminSettings({
strictModeDisabled: false,
});
// Verify secureModeEnabled is updated, others default to false
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false);
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
// Set remote settings with only mcpSetting.mcpEnabled
loadedSettings.setRemoteAdminSettings({
mcpSetting: { mcpEnabled: false },
});
// Verify mcpEnabled is updated, others remain defaults (secureModeEnabled defaults to true if strictModeDisabled is missing)
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false);
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
// Set remote settings with only cliFeatureSetting.extensionsSetting.extensionsEnabled
loadedSettings.setRemoteAdminSettings({
cliFeatureSetting: { extensionsSetting: { extensionsEnabled: false } },
});
// Verify extensionsEnabled is updated, others remain defaults
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false);
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
// Verify that missing strictModeDisabled falls back to secureModeEnabled
loadedSettings.setRemoteAdminSettings({
secureModeEnabled: false,
});
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
loadedSettings.setRemoteAdminSettings({
secureModeEnabled: true,
});
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
// Verify strictModeDisabled takes precedence over secureModeEnabled
loadedSettings.setRemoteAdminSettings({
strictModeDisabled: false,
secureModeEnabled: false,
});
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
loadedSettings.setRemoteAdminSettings({
strictModeDisabled: true,
secureModeEnabled: true,
});
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(false);
});
it('should set skills based on unmanagedCapabilitiesEnabled', () => {
const loadedSettings = loadSettings();
loadedSettings.setRemoteAdminSettings({
@@ -2402,51 +2323,6 @@ describe('Settings Loading and Merging', () => {
expect(loadedSettings.merged.admin.skills?.enabled).toBe(false);
});
it('should default mcp.enabled to false if mcpSetting is present but mcpEnabled is undefined', () => {
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
loadedSettings.setRemoteAdminSettings({
mcpSetting: {},
});
expect(loadedSettings.merged.admin?.mcp?.enabled).toBe(false);
});
it('should default extensions.enabled to false if extensionsSetting is present but extensionsEnabled is undefined', () => {
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
loadedSettings.setRemoteAdminSettings({
cliFeatureSetting: {
extensionsSetting: {},
},
});
expect(loadedSettings.merged.admin?.extensions?.enabled).toBe(false);
});
it('should force secureModeEnabled to true if undefined, overriding schema defaults', () => {
// Mock schema to have secureModeEnabled default to false to verify the override
const originalSchema = getSettingsSchema();
const modifiedSchema = JSON.parse(JSON.stringify(originalSchema));
if (modifiedSchema.admin?.properties?.secureModeEnabled) {
modifiedSchema.admin.properties.secureModeEnabled.default = false;
}
vi.mocked(getSettingsSchema).mockReturnValue(modifiedSchema);
try {
(mockFsExistsSync as Mock).mockReturnValue(true);
(fs.readFileSync as Mock).mockImplementation(() => '{}');
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
// Pass a non-empty object that doesn't have strictModeDisabled
loadedSettings.setRemoteAdminSettings({
mcpSetting: {},
});
// It should be forced to true by the logic (default secure), overriding the mock default of false
expect(loadedSettings.merged.admin?.secureModeEnabled).toBe(true);
} finally {
vi.mocked(getSettingsSchema).mockReturnValue(originalSchema);
}
});
it('should handle completely empty remote admin settings response', () => {
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR);
+8 -18
View File
@@ -16,7 +16,7 @@ import {
Storage,
coreEvents,
homedir,
type FetchAdminControlsResponse,
type AdminControlsSettings,
} from '@google/gemini-cli-core';
import stripJsonComments from 'strip-json-comments';
import { DefaultLight } from '../ui/themes/default-light.js';
@@ -348,14 +348,10 @@ export class LoadedSettings {
coreEvents.emitSettingsChanged();
}
setRemoteAdminSettings(remoteSettings: FetchAdminControlsResponse): void {
setRemoteAdminSettings(remoteSettings: AdminControlsSettings): void {
const admin: Settings['admin'] = {};
const {
secureModeEnabled,
strictModeDisabled,
mcpSetting,
cliFeatureSetting,
} = remoteSettings;
const { strictModeDisabled, mcpSetting, cliFeatureSetting } =
remoteSettings;
if (Object.keys(remoteSettings).length === 0) {
this._remoteAdminSettings = { admin };
@@ -363,19 +359,13 @@ export class LoadedSettings {
return;
}
if (strictModeDisabled !== undefined) {
admin.secureModeEnabled = !strictModeDisabled;
} else if (secureModeEnabled !== undefined) {
admin.secureModeEnabled = secureModeEnabled;
} else {
admin.secureModeEnabled = true;
}
admin.mcp = { enabled: mcpSetting?.mcpEnabled ?? false };
admin.secureModeEnabled = !strictModeDisabled;
admin.mcp = { enabled: mcpSetting?.mcpEnabled };
admin.extensions = {
enabled: cliFeatureSetting?.extensionsSetting?.extensionsEnabled ?? false,
enabled: cliFeatureSetting?.extensionsSetting?.extensionsEnabled,
};
admin.skills = {
enabled: cliFeatureSetting?.unmanagedCapabilitiesEnabled ?? false,
enabled: cliFeatureSetting?.unmanagedCapabilitiesEnabled,
};
this._remoteAdminSettings = { admin };