Skip to content

Commit 13259cb

Browse files
committed
fix(ee): case-fold the stored integration allowlist
ee/access-control re-implemented the allowlist intersection instead of calling intersectIntegrationAllowlists, and lost the case-folding: normalization only happened on the envAllowlist !== null branch, so with ALLOWED_INTEGRATIONS unset a stored config went through untouched. Callers compare against blockType.toLowerCase(), so a stored 'Slack' failed to match 'slack' and the block was denied. The access-control UI writes block.type directly and block types are lowercase, so this is not reachable from the UI — but allowedIntegrations is a bare z.array(z.string()) on the wire, so any API client can store mixed case. Replaces the fork with the shared helper. Adds two tests; the first fails against the old code.
1 parent 87ed366 commit 13259cb

2 files changed

Lines changed: 26 additions & 18 deletions

File tree

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,20 @@ describe('validateBlockType', () => {
446446
it('always allows start_trigger', async () => {
447447
await validateBlockType(undefined, undefined, 'start_trigger')
448448
})
449+
450+
it('case-folds a stored allowlist so a mixed-case entry still matches', async () => {
451+
queueGroupResolution([{ config: { allowedIntegrations: ['Slack'] } }])
452+
453+
await validateBlockType('user-123', 'workspace-1', 'slack')
454+
})
455+
456+
it('still rejects a block absent from a mixed-case stored allowlist', async () => {
457+
queueGroupResolution([{ config: { allowedIntegrations: ['Slack'] } }])
458+
459+
await expect(validateBlockType('user-123', 'workspace-1', 'discord')).rejects.toThrow(
460+
IntegrationNotAllowedError
461+
)
462+
})
449463
})
450464

451465
describe('when env allowlist is configured', () => {

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

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
isPublicApiDisabled,
1313
} from '@/lib/core/config/env-flags'
1414
import { isBlockTypeAccessControlExempt } from '@/lib/permission-groups/block-access'
15+
import { intersectIntegrationAllowlists } from '@/lib/permission-groups/integration-allowlist'
1516
import {
1617
DEFAULT_PERMISSION_GROUP_CONFIG,
1718
type PermissionGroupConfig,
@@ -108,29 +109,22 @@ export class ChatDeployAuthNotAllowedError extends Error {
108109

109110
/**
110111
* Merges the env allowlist into a permission config.
111-
* If `config` is null and no env allowlist is set, returns null.
112-
* If `config` is null but env allowlist is set, returns a default config with only allowedIntegrations set.
113-
* If both are set, intersects the two allowlists.
112+
*
113+
* Returns null only when neither layer restricts anything. Otherwise the group's
114+
* own allowlist is intersected with the env one by
115+
* {@link intersectIntegrationAllowlists}, which case-folds both sides — callers
116+
* compare against a lowercased block type, and a stored config reaches here
117+
* straight off the wire, where the contract permits any casing.
114118
*/
115119
function mergeEnvAllowlist(config: PermissionGroupConfig | null): PermissionGroupConfig | null {
116120
const envAllowlist = getAllowedIntegrationsFromEnv()
121+
if (config === null && envAllowlist === null) return null
117122

118-
if (envAllowlist === null) {
119-
return config
120-
}
121-
122-
if (config === null) {
123-
return { ...DEFAULT_PERMISSION_GROUP_CONFIG, allowedIntegrations: envAllowlist }
123+
const base = config ?? DEFAULT_PERMISSION_GROUP_CONFIG
124+
return {
125+
...base,
126+
allowedIntegrations: intersectIntegrationAllowlists(base.allowedIntegrations, envAllowlist),
124127
}
125-
126-
const merged =
127-
config.allowedIntegrations === null
128-
? envAllowlist
129-
: config.allowedIntegrations
130-
.map((i) => i.toLowerCase())
131-
.filter((i) => envAllowlist.includes(i))
132-
133-
return { ...config, allowedIntegrations: merged }
134128
}
135129

136130
/**

0 commit comments

Comments
 (0)