feat(ee): add enterprise modules (#3121)

This commit is contained in:
Waleed
2026-02-02 23:40:18 -08:00
committed by GitHub
parent a9b7d75d87
commit 9c3fd1f7af
36 changed files with 110 additions and 139 deletions

View File

@@ -5,6 +5,7 @@ import {
hydrateUserFilesWithBase64,
} from '@/lib/uploads/utils/user-file-base64.server'
import { sanitizeInputFormat, sanitizeTools } from '@/lib/workflows/comparison/normalize'
import { validateBlockType } from '@/ee/access-control/utils/permission-check'
import {
BlockType,
buildResumeApiUrl,
@@ -31,7 +32,6 @@ import { streamingResponseFormatProcessor } from '@/executor/utils'
import { buildBlockExecutionError, normalizeError } from '@/executor/utils/errors'
import { isJSONString } from '@/executor/utils/json'
import { filterOutputForLog } from '@/executor/utils/output-filter'
import { validateBlockType } from '@/executor/utils/permission-check'
import type { VariableResolver } from '@/executor/variables/resolver'
import type { SerializedBlock } from '@/serializer/types'
import type { SubflowType } from '@/stores/workflows/workflow/types'

View File

@@ -6,6 +6,12 @@ import { createMcpToolId } from '@/lib/mcp/utils'
import { refreshTokenIfNeeded } from '@/app/api/auth/oauth/utils'
import { getAllBlocks } from '@/blocks'
import type { BlockOutput } from '@/blocks/types'
import {
validateBlockType,
validateCustomToolsAllowed,
validateMcpToolsAllowed,
validateModelProvider,
} from '@/ee/access-control/utils/permission-check'
import { AGENT, BlockType, DEFAULTS, REFERENCE, stripCustomToolPrefix } from '@/executor/constants'
import { memoryService } from '@/executor/handlers/agent/memory'
import type {
@@ -18,12 +24,6 @@ import type { BlockHandler, ExecutionContext, StreamingExecution } from '@/execu
import { collectBlockData } from '@/executor/utils/block-data'
import { buildAPIUrl, buildAuthHeaders } from '@/executor/utils/http'
import { stringifyJSON } from '@/executor/utils/json'
import {
validateBlockType,
validateCustomToolsAllowed,
validateMcpToolsAllowed,
validateModelProvider,
} from '@/executor/utils/permission-check'
import { executeProviderRequest } from '@/providers'
import { getProviderFromModel, transformBlockTool } from '@/providers/utils'
import type { SerializedBlock } from '@/serializer/types'

View File

@@ -4,11 +4,11 @@ import { createLogger } from '@sim/logger'
import { eq } from 'drizzle-orm'
import { refreshTokenIfNeeded } from '@/app/api/auth/oauth/utils'
import type { BlockOutput } from '@/blocks/types'
import { validateModelProvider } from '@/ee/access-control/utils/permission-check'
import { BlockType, DEFAULTS, EVALUATOR } from '@/executor/constants'
import type { BlockHandler, ExecutionContext } from '@/executor/types'
import { buildAPIUrl, buildAuthHeaders, extractAPIErrorMessage } from '@/executor/utils/http'
import { isJSONString, parseJSON, stringifyJSON } from '@/executor/utils/json'
import { validateModelProvider } from '@/executor/utils/permission-check'
import { calculateCost, getProviderFromModel } from '@/providers/utils'
import type { SerializedBlock } from '@/serializer/types'

View File

@@ -6,6 +6,7 @@ import { getBaseUrl } from '@/lib/core/utils/urls'
import { refreshTokenIfNeeded } from '@/app/api/auth/oauth/utils'
import { generateRouterPrompt, generateRouterV2Prompt } from '@/blocks/blocks/router'
import type { BlockOutput } from '@/blocks/types'
import { validateModelProvider } from '@/ee/access-control/utils/permission-check'
import {
BlockType,
DEFAULTS,
@@ -15,7 +16,6 @@ import {
} from '@/executor/constants'
import type { BlockHandler, ExecutionContext } from '@/executor/types'
import { buildAuthHeaders } from '@/executor/utils/http'
import { validateModelProvider } from '@/executor/utils/permission-check'
import { calculateCost, getProviderFromModel } from '@/providers/utils'
import type { SerializedBlock } from '@/serializer/types'

View File

@@ -1,229 +0,0 @@
import { db } from '@sim/db'
import { member, permissionGroup, permissionGroupMember } from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { and, eq } from 'drizzle-orm'
import { isOrganizationOnEnterprisePlan } from '@/lib/billing'
import { isAccessControlEnabled, isHosted } from '@/lib/core/config/feature-flags'
import {
type PermissionGroupConfig,
parsePermissionGroupConfig,
} from '@/lib/permission-groups/types'
import type { ExecutionContext } from '@/executor/types'
import { getProviderFromModel } from '@/providers/utils'
const logger = createLogger('PermissionCheck')
export class ProviderNotAllowedError extends Error {
constructor(providerId: string, model: string) {
super(
`Provider "${providerId}" is not allowed for model "${model}" based on your permission group settings`
)
this.name = 'ProviderNotAllowedError'
}
}
export class IntegrationNotAllowedError extends Error {
constructor(blockType: string) {
super(`Integration "${blockType}" is not allowed based on your permission group settings`)
this.name = 'IntegrationNotAllowedError'
}
}
export class McpToolsNotAllowedError extends Error {
constructor() {
super('MCP tools are not allowed based on your permission group settings')
this.name = 'McpToolsNotAllowedError'
}
}
export class CustomToolsNotAllowedError extends Error {
constructor() {
super('Custom tools are not allowed based on your permission group settings')
this.name = 'CustomToolsNotAllowedError'
}
}
export class InvitationsNotAllowedError extends Error {
constructor() {
super('Invitations are not allowed based on your permission group settings')
this.name = 'InvitationsNotAllowedError'
}
}
export async function getUserPermissionConfig(
userId: string
): Promise<PermissionGroupConfig | null> {
if (!isHosted && !isAccessControlEnabled) {
return null
}
const [membership] = await db
.select({ organizationId: member.organizationId })
.from(member)
.where(eq(member.userId, userId))
.limit(1)
if (!membership) {
return null
}
const isEnterprise = await isOrganizationOnEnterprisePlan(membership.organizationId)
if (!isEnterprise) {
return null
}
const [groupMembership] = await db
.select({ config: permissionGroup.config })
.from(permissionGroupMember)
.innerJoin(permissionGroup, eq(permissionGroupMember.permissionGroupId, permissionGroup.id))
.where(
and(
eq(permissionGroupMember.userId, userId),
eq(permissionGroup.organizationId, membership.organizationId)
)
)
.limit(1)
if (!groupMembership) {
return null
}
return parsePermissionGroupConfig(groupMembership.config)
}
export async function getPermissionConfig(
userId: string | undefined,
ctx?: ExecutionContext
): Promise<PermissionGroupConfig | null> {
if (!userId) {
return null
}
if (ctx) {
if (ctx.permissionConfigLoaded) {
return ctx.permissionConfig ?? null
}
const config = await getUserPermissionConfig(userId)
ctx.permissionConfig = config
ctx.permissionConfigLoaded = true
return config
}
return getUserPermissionConfig(userId)
}
export async function validateModelProvider(
userId: string | undefined,
model: string,
ctx?: ExecutionContext
): Promise<void> {
if (!userId) {
return
}
const config = await getPermissionConfig(userId, ctx)
if (!config || config.allowedModelProviders === null) {
return
}
const providerId = getProviderFromModel(model)
if (!config.allowedModelProviders.includes(providerId)) {
logger.warn('Model provider blocked by permission group', { userId, model, providerId })
throw new ProviderNotAllowedError(providerId, model)
}
}
export async function validateBlockType(
userId: string | undefined,
blockType: string,
ctx?: ExecutionContext
): Promise<void> {
if (blockType === 'start_trigger') {
return
}
if (!userId) {
return
}
const config = await getPermissionConfig(userId, ctx)
if (!config || config.allowedIntegrations === null) {
return
}
if (!config.allowedIntegrations.includes(blockType)) {
logger.warn('Integration blocked by permission group', { userId, blockType })
throw new IntegrationNotAllowedError(blockType)
}
}
export async function validateMcpToolsAllowed(
userId: string | undefined,
ctx?: ExecutionContext
): Promise<void> {
if (!userId) {
return
}
const config = await getPermissionConfig(userId, ctx)
if (!config) {
return
}
if (config.disableMcpTools) {
logger.warn('MCP tools blocked by permission group', { userId })
throw new McpToolsNotAllowedError()
}
}
export async function validateCustomToolsAllowed(
userId: string | undefined,
ctx?: ExecutionContext
): Promise<void> {
if (!userId) {
return
}
const config = await getPermissionConfig(userId, ctx)
if (!config) {
return
}
if (config.disableCustomTools) {
logger.warn('Custom tools blocked by permission group', { userId })
throw new CustomToolsNotAllowedError()
}
}
/**
* Validates if the user is allowed to send invitations.
* Also checks the global feature flag.
*/
export async function validateInvitationsAllowed(userId: string | undefined): Promise<void> {
const { isInvitationsDisabled } = await import('@/lib/core/config/feature-flags')
if (isInvitationsDisabled) {
logger.warn('Invitations blocked by feature flag')
throw new InvitationsNotAllowedError()
}
if (!userId) {
return
}
const config = await getUserPermissionConfig(userId)
if (!config) {
return
}
if (config.disableInvitations) {
logger.warn('Invitations blocked by permission group', { userId })
throw new InvitationsNotAllowedError()
}
}