Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/sim/lib/integrations/credential-display.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const EXPECTED_COVERAGE: Record<string, string[]> = {
'attio-service-account': ['attio'],
'box-service-account': ['box'],
'calcom-service-account': ['cal-com'],
'claude-platform-service-account': [],
'claude-platform-service-account': ['claude-managed-agents'],
'clickup-service-account': ['clickup'],
'coda-service-account': ['coda'],
'github-app-installation': ['github'],
Expand Down
78 changes: 47 additions & 31 deletions apps/sim/lib/integrations/credential-visibility.server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,40 +67,56 @@ describe('integration credential visibility', () => {
])
})

it('exposes Coda token credentials without OAuth while honoring integration policy and visibility', () => {
const catalog = resolveIntegrationAvailability({})
expect(catalog.find((entry) => entry.type === 'coda')).toMatchObject({
state: 'ready',
oauthAvailable: false,
serviceAccountAvailable: true,
})
getIntegrationAvailabilityMock.mockReturnValue(catalog)
const service: OAuthServiceMetadata = {
it.each([
{
serviceId: 'coda',
providerId: 'coda',
serviceAccountProviderId: 'coda-service-account',
authType: 'service_account',
providerId: 'coda-service-account',
blockType: 'coda',
name: 'Coda',
description: 'Coda token',
baseProvider: 'coda',
}
const identity = { providerId: 'coda-service-account', type: 'service_account' } as const
const visibility = (allowed: ReadonlySet<string> | null, disabled: boolean) =>
createIntegrationCredentialVisibility({
allowedIntegrationTypes: allowed,
oauthServices: [service],
blockVisibility: {
revealed: new Set(),
previewTagged: new Set(),
disabled: new Set(disabled ? ['coda'] : []),
},
},
{
serviceId: 'claude-platform',
providerId: 'claude-platform-service-account',
blockType: 'managed_agent',
name: 'Claude Platform',
},
])(
'exposes $name token credentials without OAuth while honoring integration policy and visibility',
({ serviceId, providerId, blockType, name }) => {
const catalog = resolveIntegrationAvailability({})
expect(catalog.find((entry) => entry.type === blockType)).toMatchObject({
state: 'ready',
oauthAvailable: false,
serviceAccountAvailable: true,
})
expect(visibility(new Set(['coda']), false).isCredentialVisible(identity)).toBe(true)
expect(visibility(new Set(['slack_v2']), false).isCredentialVisible(identity)).toBe(false)
expect(visibility(null, true).isCredentialVisible(identity)).toBe(false)
getBlockMock.mockReturnValue({ type: 'coda', preview: true } as never)
expect(visibility(null, false).isCredentialVisible(identity)).toBe(false)
})
getIntegrationAvailabilityMock.mockReturnValue(catalog)
const service: OAuthServiceMetadata = {
serviceId,
providerId: serviceId,
serviceAccountProviderId: providerId,
authType: 'service_account',
name,
description: `${name} token`,
baseProvider: serviceId,
}
const identity = { providerId, type: 'service_account' } as const
const visibility = (allowed: ReadonlySet<string> | null, disabled: boolean) =>
createIntegrationCredentialVisibility({
allowedIntegrationTypes: allowed,
oauthServices: [service],
blockVisibility: {
revealed: new Set(),
previewTagged: new Set(),
disabled: new Set(disabled ? [blockType] : []),
},
})
expect(visibility(new Set([blockType]), false).isCredentialVisible(identity)).toBe(true)
expect(visibility(new Set(['slack_v2']), false).isCredentialVisible(identity)).toBe(false)
expect(visibility(null, true).isCredentialVisible(identity)).toBe(false)
getBlockMock.mockReturnValue({ type: blockType, preview: true } as never)
expect(visibility(null, false).isCredentialVisible(identity)).toBe(false)
}
)

it('applies the integration allowlist to OAuth and service-account credentials', () => {
const visibility = createIntegrationCredentialVisibility({
Expand Down
7 changes: 5 additions & 2 deletions packages/deployment-config/src/integration-availability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ const deploymentGatedIntegrationTypes = new Set(
const integrationTypesByOAuthServiceId = new Map<string, readonly string[]>()
/** Search authorization shares GitHub's integration policy while its workflow tools retain PAT auth. */
integrationTypesByOAuthServiceId.set('github-repositories', ['github_v2'])
/** Coda's stored API-token credential is available without a deployment OAuth client. */
const tokenCredentialIntegrationTypes = new Map([['coda', 'coda']])
/** Stored API-token credentials for api-key blocks are available without a deployment OAuth client. */
const tokenCredentialIntegrationTypes = new Map([
['coda', 'coda'],
['claude-platform', 'managed_agent'],
])
for (const [serviceId, integrationType] of tokenCredentialIntegrationTypes) {
integrationTypesByOAuthServiceId.set(serviceId, [integrationType])
}
Expand Down
Loading