LibreChat/packages/data-provider/src/roles.ts
Danny Avila b189972381
🎭 fix: Set Explicit Permission Defaults for USER Role in roleDefaults (#12308)
* fix: set explicit permission defaults for USER role in roleDefaults

Previously several permission types for the USER role had empty
objects in roleDefaults, causing the getPermissionValue fallback to
resolve SHARE/CREATE via the zod schema defaults on fresh installs.
This silently granted users MCP server creation ability and left
share permissions ambiguous.

Sets explicit defaults for all multi-field permission types:
- PROMPTS/AGENTS: USE and CREATE true, SHARE false
- MCP_SERVERS: USE true, CREATE/SHARE false
- REMOTE_AGENTS: all false

Adds regression tests covering the exact reported scenarios (fresh
install with `agents: { use: true }`, restart preserving admin-panel
overrides) and structural guards against future permission schema
expansions missing explicit USER defaults.

Closes #12306.

* fix: guard MCP_SERVERS.CREATE against configDefaults fallback + add migration

The roleDefaults fix alone was insufficient: loadDefaultInterface propagates
configDefaults.mcpServers.create=true as tier-1 in getPermissionValue, overriding
the roleDefault of false. This commit:

- Adds conditional guards for MCP_SERVERS.CREATE and REMOTE_AGENTS.CREATE matching
  the existing AGENTS/PROMPTS pattern (only include CREATE when explicitly configured
  in yaml OR on fresh install)
- Uses raw interfaceConfig for MCP_SERVERS.CREATE tier-1 instead of loadedInterface
  (which includes configDefaults fallback)
- Adds one-time migration backfill: corrects existing MCP_SERVERS.CREATE=true for
  USER role in DB when no explicit yaml config is present
- Adds restart-scenario and migration regression tests for MCP_SERVERS
- Cleans up roles.spec.ts: for..of loops, Permissions[] typing, Set for lookups,
  removes unnecessary aliases, improves JSDoc for exclusion list
- Fixes misleading test name for agents regression test
- Removes redundant not.toHaveProperty assertions after strict toEqual

* fix: use raw interfaceConfig for REMOTE_AGENTS.CREATE tier-1 (consistency)

Aligns REMOTE_AGENTS.CREATE with the MCP_SERVERS.CREATE fix — reads from
raw interfaceConfig instead of loadedInterface to prevent a future
configDefaults fallback from silently overriding the roleDefault.
2026-03-19 14:52:06 -04:00

225 lines
7.3 KiB
TypeScript

import { z } from 'zod';
import {
Permissions,
PermissionTypes,
permissionsSchema,
agentPermissionsSchema,
promptPermissionsSchema,
memoryPermissionsSchema,
runCodePermissionsSchema,
bookmarkPermissionsSchema,
webSearchPermissionsSchema,
fileSearchPermissionsSchema,
multiConvoPermissionsSchema,
mcpServersPermissionsSchema,
peoplePickerPermissionsSchema,
remoteAgentsPermissionsSchema,
temporaryChatPermissionsSchema,
fileCitationsPermissionsSchema,
} from './permissions';
/**
* Enum for System Defined Roles
*/
export enum SystemRoles {
/**
* The Admin role
*/
ADMIN = 'ADMIN',
/**
* The default user role
*/
USER = 'USER',
}
export const roleSchema = z.object({
name: z.string(),
permissions: permissionsSchema,
});
export type TRole = z.infer<typeof roleSchema>;
const defaultRolesSchema = z.object({
[SystemRoles.ADMIN]: roleSchema.extend({
name: z.literal(SystemRoles.ADMIN),
permissions: permissionsSchema.extend({
[PermissionTypes.PROMPTS]: promptPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(true),
[Permissions.SHARE_PUBLIC]: z.boolean().default(true),
}),
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.MEMORIES]: memoryPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true),
[Permissions.UPDATE]: z.boolean().default(true),
[Permissions.READ]: z.boolean().default(true),
[Permissions.OPT_OUT]: z.boolean().default(true),
}),
[PermissionTypes.AGENTS]: agentPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(true),
[Permissions.SHARE_PUBLIC]: z.boolean().default(true),
}),
[PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.TEMPORARY_CHAT]: temporaryChatPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.RUN_CODE]: runCodePermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.WEB_SEARCH]: webSearchPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.PEOPLE_PICKER]: peoplePickerPermissionsSchema.extend({
[Permissions.VIEW_USERS]: z.boolean().default(true),
[Permissions.VIEW_GROUPS]: z.boolean().default(true),
[Permissions.VIEW_ROLES]: z.boolean().default(true),
}),
[PermissionTypes.MARKETPLACE]: z.object({
[Permissions.USE]: z.boolean().default(false),
}),
[PermissionTypes.FILE_SEARCH]: fileSearchPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.FILE_CITATIONS]: fileCitationsPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
}),
[PermissionTypes.MCP_SERVERS]: mcpServersPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(true),
[Permissions.SHARE_PUBLIC]: z.boolean().default(true),
}),
[PermissionTypes.REMOTE_AGENTS]: remoteAgentsPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(true),
[Permissions.SHARE_PUBLIC]: z.boolean().default(true),
}),
}),
}),
[SystemRoles.USER]: roleSchema.extend({
name: z.literal(SystemRoles.USER),
permissions: permissionsSchema,
}),
});
export const roleDefaults = defaultRolesSchema.parse({
[SystemRoles.ADMIN]: {
name: SystemRoles.ADMIN,
permissions: {
[PermissionTypes.PROMPTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.SHARE]: true,
[Permissions.SHARE_PUBLIC]: true,
},
[PermissionTypes.BOOKMARKS]: {
[Permissions.USE]: true,
},
[PermissionTypes.MEMORIES]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.UPDATE]: true,
[Permissions.READ]: true,
[Permissions.OPT_OUT]: true,
},
[PermissionTypes.AGENTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.SHARE]: true,
[Permissions.SHARE_PUBLIC]: true,
},
[PermissionTypes.MULTI_CONVO]: {
[Permissions.USE]: true,
},
[PermissionTypes.TEMPORARY_CHAT]: {
[Permissions.USE]: true,
},
[PermissionTypes.RUN_CODE]: {
[Permissions.USE]: true,
},
[PermissionTypes.WEB_SEARCH]: {
[Permissions.USE]: true,
},
[PermissionTypes.PEOPLE_PICKER]: {
[Permissions.VIEW_USERS]: true,
[Permissions.VIEW_GROUPS]: true,
[Permissions.VIEW_ROLES]: true,
},
[PermissionTypes.MARKETPLACE]: {
[Permissions.USE]: true,
},
[PermissionTypes.FILE_SEARCH]: {
[Permissions.USE]: true,
},
[PermissionTypes.FILE_CITATIONS]: {
[Permissions.USE]: true,
},
[PermissionTypes.MCP_SERVERS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.SHARE]: true,
[Permissions.SHARE_PUBLIC]: true,
},
[PermissionTypes.REMOTE_AGENTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.SHARE]: true,
[Permissions.SHARE_PUBLIC]: true,
},
},
},
[SystemRoles.USER]: {
name: SystemRoles.USER,
permissions: {
[PermissionTypes.PROMPTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.SHARE]: false,
[Permissions.SHARE_PUBLIC]: false,
},
[PermissionTypes.BOOKMARKS]: {},
[PermissionTypes.MEMORIES]: {},
[PermissionTypes.AGENTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
[Permissions.SHARE]: false,
[Permissions.SHARE_PUBLIC]: false,
},
[PermissionTypes.MULTI_CONVO]: {},
[PermissionTypes.TEMPORARY_CHAT]: {},
[PermissionTypes.RUN_CODE]: {},
[PermissionTypes.WEB_SEARCH]: {},
[PermissionTypes.PEOPLE_PICKER]: {
[Permissions.VIEW_USERS]: false,
[Permissions.VIEW_GROUPS]: false,
[Permissions.VIEW_ROLES]: false,
},
[PermissionTypes.MARKETPLACE]: {
[Permissions.USE]: false,
},
[PermissionTypes.FILE_SEARCH]: {},
[PermissionTypes.FILE_CITATIONS]: {},
[PermissionTypes.MCP_SERVERS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: false,
[Permissions.SHARE]: false,
[Permissions.SHARE_PUBLIC]: false,
},
[PermissionTypes.REMOTE_AGENTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: false,
[Permissions.SHARE]: false,
[Permissions.SHARE_PUBLIC]: false,
},
},
},
});