Skip to content

Commit 2d863f9

Browse files
committed
added tests, normalize to lower case
1 parent 5ec4e63 commit 2d863f9

File tree

10 files changed

+89
-16
lines changed

10 files changed

+89
-16
lines changed

apps/sim/app/api/settings/allowed-integrations/route.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { NextResponse } from 'next/server'
2+
import { getSession } from '@/lib/auth'
23
import { getAllowedIntegrationsFromEnv } from '@/lib/core/config/feature-flags'
34

45
export async function GET() {
6+
const session = await getSession()
7+
if (!session?.user?.id) {
8+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
9+
}
10+
511
return NextResponse.json({
612
allowedIntegrations: getAllowedIntegrationsFromEnv(),
713
})

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/integrations/integrations.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,8 @@ export function Integrations({ onOpenChange, registerCloseHandler }: Integration
223223
}
224224
}
225225

226-
// Group services by provider, filtering by permission config
227226
const groupedServices = services.reduce(
228227
(acc, service) => {
229-
// Filter based on allowedIntegrations
230-
// Normalize hyphens to underscores since service IDs use hyphens (e.g., "google-drive")
231-
// but block types in the allowlist use underscores (e.g., "google_drive")
232228
if (
233229
permissionConfig.allowedIntegrations !== null &&
234230
!permissionConfig.allowedIntegrations.includes(service.id.replace(/-/g, '_'))

apps/sim/ee/access-control/utils/permission-check.test.ts

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,57 @@ vi.doMock('@/providers/utils', () => ({
5252
getProviderFromModel: mockGetProviderFromModel,
5353
}))
5454

55-
const { IntegrationNotAllowedError, validateBlockType } = await import('./permission-check')
55+
const { IntegrationNotAllowedError, getUserPermissionConfig, validateBlockType } = await import(
56+
'./permission-check'
57+
)
58+
59+
describe('IntegrationNotAllowedError', () => {
60+
it.concurrent('creates error with correct name and message', () => {
61+
const error = new IntegrationNotAllowedError('discord')
62+
63+
expect(error).toBeInstanceOf(Error)
64+
expect(error.name).toBe('IntegrationNotAllowedError')
65+
expect(error.message).toContain('discord')
66+
})
67+
68+
it.concurrent('includes custom reason when provided', () => {
69+
const error = new IntegrationNotAllowedError('discord', 'blocked by server policy')
70+
71+
expect(error.message).toContain('blocked by server policy')
72+
})
73+
})
74+
75+
describe('getUserPermissionConfig', () => {
76+
beforeEach(() => {
77+
vi.clearAllMocks()
78+
})
79+
80+
it('returns null when no env allowlist is configured', async () => {
81+
mockGetAllowedIntegrationsFromEnv.mockReturnValue(null)
82+
83+
const config = await getUserPermissionConfig('user-123')
84+
85+
expect(config).toBeNull()
86+
})
87+
88+
it('returns config with env allowlist when configured', async () => {
89+
mockGetAllowedIntegrationsFromEnv.mockReturnValue(['slack', 'gmail'])
90+
91+
const config = await getUserPermissionConfig('user-123')
92+
93+
expect(config).not.toBeNull()
94+
expect(config!.allowedIntegrations).toEqual(['slack', 'gmail'])
95+
})
96+
97+
it('preserves default values for non-allowlist fields', async () => {
98+
mockGetAllowedIntegrationsFromEnv.mockReturnValue(['slack'])
99+
100+
const config = await getUserPermissionConfig('user-123')
101+
102+
expect(config!.disableMcpTools).toBe(false)
103+
expect(config!.allowedModelProviders).toBeNull()
104+
})
105+
})
56106

57107
describe('validateBlockType', () => {
58108
beforeEach(() => {
@@ -110,27 +160,46 @@ describe('validateBlockType', () => {
110160
it('includes reason in error for env-only enforcement', async () => {
111161
await expect(validateBlockType(undefined, 'discord')).rejects.toThrow(/ALLOWED_INTEGRATIONS/)
112162
})
163+
164+
it('does not include env reason when userId is provided', async () => {
165+
await expect(validateBlockType('user-123', 'discord')).rejects.toThrow(
166+
/permission group settings/
167+
)
168+
})
113169
})
114170
})
115171

116172
describe('service ID to block type normalization', () => {
117-
it('hyphenated service IDs match underscore block types after normalization', () => {
173+
it.concurrent('hyphenated service IDs match underscore block types after normalization', () => {
118174
const allowedBlockTypes = [
119175
'google_drive',
120176
'microsoft_excel',
121177
'microsoft_teams',
122178
'google_sheets',
179+
'google_docs',
180+
'google_calendar',
181+
'google_forms',
182+
'microsoft_planner',
183+
]
184+
const serviceIds = [
185+
'google-drive',
186+
'microsoft-excel',
187+
'microsoft-teams',
188+
'google-sheets',
189+
'google-docs',
190+
'google-calendar',
191+
'google-forms',
192+
'microsoft-planner',
123193
]
124-
const serviceIds = ['google-drive', 'microsoft-excel', 'microsoft-teams', 'google-sheets']
125194

126195
for (const serviceId of serviceIds) {
127196
const normalized = serviceId.replace(/-/g, '_')
128197
expect(allowedBlockTypes).toContain(normalized)
129198
}
130199
})
131200

132-
it('single-word service IDs are unaffected by normalization', () => {
133-
const serviceIds = ['slack', 'gmail', 'notion', 'discord']
201+
it.concurrent('single-word service IDs are unaffected by normalization', () => {
202+
const serviceIds = ['slack', 'gmail', 'notion', 'discord', 'jira', 'trello']
134203

135204
for (const serviceId of serviceIds) {
136205
const normalized = serviceId.replace(/-/g, '_')

apps/sim/lib/copilot/process-contents.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ async function processBlockMetadata(
352352
if (userId) {
353353
const permissionConfig = await getUserPermissionConfig(userId)
354354
const allowedIntegrations = permissionConfig?.allowedIntegrations
355-
if (allowedIntegrations != null && !allowedIntegrations.includes(blockId)) {
355+
if (allowedIntegrations != null && !allowedIntegrations.includes(blockId.toLowerCase())) {
356356
logger.debug('Block not allowed by permission group', { blockId, userId })
357357
return null
358358
}

apps/sim/lib/copilot/tools/server/blocks/get-block-config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ export const getBlockConfigServerTool: BaseServerTool<
441441
const permissionConfig = context?.userId ? await getUserPermissionConfig(context.userId) : null
442442
const allowedIntegrations = permissionConfig?.allowedIntegrations
443443

444-
if (allowedIntegrations != null && !allowedIntegrations.includes(blockType)) {
444+
if (allowedIntegrations != null && !allowedIntegrations.includes(blockType.toLowerCase())) {
445445
throw new Error(`Block "${blockType}" is not available`)
446446
}
447447

apps/sim/lib/copilot/tools/server/blocks/get-block-options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export const getBlockOptionsServerTool: BaseServerTool<
6161
const permissionConfig = context?.userId ? await getUserPermissionConfig(context.userId) : null
6262
const allowedIntegrations = permissionConfig?.allowedIntegrations
6363

64-
if (allowedIntegrations != null && !allowedIntegrations.includes(blockId)) {
64+
if (allowedIntegrations != null && !allowedIntegrations.includes(blockId.toLowerCase())) {
6565
throw new Error(`Block "${blockId}" is not available`)
6666
}
6767

apps/sim/lib/copilot/tools/server/blocks/get-blocks-and-tools.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export const getBlocksAndToolsServerTool: BaseServerTool<
3030
Object.entries(blockRegistry)
3131
.filter(([blockType, blockConfig]: [string, BlockConfig]) => {
3232
if (blockConfig.hideFromToolbar) return false
33-
if (allowedIntegrations != null && !allowedIntegrations.includes(blockType)) return false
33+
if (allowedIntegrations != null && !allowedIntegrations.includes(blockType.toLowerCase()))
34+
return false
3435
return true
3536
})
3637
.forEach(([blockType, blockConfig]: [string, BlockConfig]) => {

apps/sim/lib/copilot/tools/server/blocks/get-blocks-metadata-tool.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export const getBlocksMetadataServerTool: BaseServerTool<
116116

117117
const result: Record<string, CopilotBlockMetadata> = {}
118118
for (const blockId of blockIds || []) {
119-
if (allowedIntegrations != null && !allowedIntegrations.includes(blockId)) {
119+
if (allowedIntegrations != null && !allowedIntegrations.includes(blockId.toLowerCase())) {
120120
logger.debug('Block not allowed by permission group', { blockId })
121121
continue
122122
}

apps/sim/lib/copilot/tools/server/blocks/get-trigger-blocks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ export const getTriggerBlocksServerTool: BaseServerTool<
2828

2929
Object.entries(blockRegistry).forEach(([blockType, blockConfig]: [string, BlockConfig]) => {
3030
if (blockConfig.hideFromToolbar) return
31-
if (allowedIntegrations != null && !allowedIntegrations.includes(blockType)) return
31+
if (allowedIntegrations != null && !allowedIntegrations.includes(blockType.toLowerCase()))
32+
return
3233

3334
if (blockConfig.category === 'triggers') {
3435
triggerBlockIds.push(blockType)

apps/sim/lib/copilot/tools/server/workflow/edit-workflow/validation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ export function isBlockTypeAllowed(
657657
if (!permissionConfig || permissionConfig.allowedIntegrations === null) {
658658
return true
659659
}
660-
return permissionConfig.allowedIntegrations.includes(blockType)
660+
return permissionConfig.allowedIntegrations.includes(blockType.toLowerCase())
661661
}
662662

663663
/**

0 commit comments

Comments
 (0)