Skip to content

Commit 031a295

Browse files
authored
fix(gmail-poller): resolve OAuth credential provider aliases (#5770)
1 parent 4d76385 commit 031a295

2 files changed

Lines changed: 47 additions & 7 deletions

File tree

apps/sim/lib/webhooks/deploy.test.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
11
/**
22
* @vitest-environment node
33
*/
4+
import { credential } from '@sim/db/schema'
45
import { beforeEach, describe, expect, it, vi } from 'vitest'
56
import type { SubBlockConfig } from '@/blocks/types'
67
import type { BlockState } from '@/stores/workflows/workflow/types'
78

9+
const { mockEq, mockFrom, mockLimit, mockSelect, mockWhere } = vi.hoisted(() => ({
10+
mockEq: vi.fn((left: unknown, right: unknown) => ({ left, right })),
11+
mockFrom: vi.fn(),
12+
mockLimit: vi.fn(),
13+
mockSelect: vi.fn(),
14+
mockWhere: vi.fn(),
15+
}))
16+
17+
vi.mock('@sim/db', () => ({ db: { select: mockSelect } }))
18+
vi.mock('drizzle-orm', () => ({
19+
and: vi.fn((...conditions: unknown[]) => ({ conditions })),
20+
eq: mockEq,
21+
inArray: vi.fn((...args: unknown[]) => ({ args })),
22+
isNull: vi.fn((value: unknown) => ({ value })),
23+
or: vi.fn((...conditions: unknown[]) => ({ conditions })),
24+
}))
25+
826
// deploy.ts pulls in the trigger/block/provider registries at module load; none are exercised by
927
// buildProviderConfig (a pure function), so stub them to keep this unit test fast and isolated.
1028
vi.mock('@/blocks', () => ({ getBlock: vi.fn() }))
@@ -22,7 +40,7 @@ vi.mock('@/lib/webhooks/pending-verification', () => ({
2240
PendingWebhookVerificationTracker: vi.fn(),
2341
}))
2442

25-
import { buildProviderConfig } from '@/lib/webhooks/deploy'
43+
import { buildProviderConfig, resolveTriggerCredentialId } from '@/lib/webhooks/deploy'
2644

2745
const trigger = (subBlocks: Partial<SubBlockConfig>[]): { subBlocks: SubBlockConfig[] } => ({
2846
subBlocks: subBlocks as SubBlockConfig[],
@@ -59,16 +77,22 @@ function makeBlock(
5977
} as unknown as BlockState
6078
}
6179

62-
describe('buildProviderConfig canonical collapse', () => {
63-
beforeEach(() => vi.clearAllMocks())
80+
beforeEach(() => {
81+
vi.clearAllMocks()
82+
mockSelect.mockReturnValue({ from: mockFrom })
83+
mockFrom.mockReturnValue({ where: mockWhere })
84+
mockWhere.mockReturnValue({ limit: mockLimit })
85+
mockLimit.mockResolvedValue([{ id: 'credential-1' }])
86+
})
6487

88+
describe('buildProviderConfig canonical collapse', () => {
6589
it('writes the basic value under the canonical key in basic mode', () => {
6690
const block = makeBlock('google_drive_poller', { folderId: 'BASIC' })
6791
const { providerConfig } = buildProviderConfig(block, 'google_drive_poller', driveTrigger)
6892
expect(providerConfig.folderId).toBe('BASIC')
6993
})
7094

71-
it('returns the credential reference and canonical OAuth service for deploy validation', () => {
95+
it('returns the credential reference and OAuth service for deploy validation', () => {
7296
const block = makeBlock('google_drive_poller', { triggerCredentials: 'credential-1' })
7397
const result = buildProviderConfig(block, 'google_drive_poller', driveTrigger)
7498

@@ -132,3 +156,15 @@ describe('buildProviderConfig canonical collapse', () => {
132156
expect(providerConfig.tableId).toBe('ACTIVE')
133157
})
134158
})
159+
160+
describe('resolveTriggerCredentialId', () => {
161+
it('canonicalizes an OAuth service alias at the credential lookup boundary', async () => {
162+
await resolveTriggerCredentialId('credential-1', 'workspace-1', 'gmail')
163+
164+
expect(mockEq).toHaveBeenCalledWith(credential.workspaceId, 'workspace-1')
165+
expect(mockEq).toHaveBeenCalledWith(credential.type, 'oauth')
166+
expect(mockEq).toHaveBeenCalledWith(credential.providerId, 'google-email')
167+
expect(mockEq).toHaveBeenCalledWith(credential.id, 'credential-1')
168+
expect(mockEq).toHaveBeenCalledWith(credential.accountId, 'credential-1')
169+
})
170+
})

apps/sim/lib/webhooks/deploy.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getErrorMessage } from '@sim/utils/errors'
55
import { generateShortId } from '@sim/utils/id'
66
import { and, eq, inArray, isNull, or } from 'drizzle-orm'
77
import type { NextRequest } from 'next/server'
8+
import { getProviderIdFromServiceId } from '@/lib/oauth'
89
import { WebhookPathClaimConflictError } from '@/lib/webhooks/path-claims'
910
import { PendingWebhookVerificationTracker } from '@/lib/webhooks/pending-verification'
1011
import {
@@ -334,21 +335,24 @@ export function buildProviderConfig(
334335

335336
/**
336337
* Resolves a trigger credential reference to its canonical platform credential ID while enforcing
337-
* that the credential belongs to the deployed workflow's workspace and OAuth service.
338+
* that the credential belongs to the deployed workflow's workspace and OAuth provider.
339+
*
340+
* Exported for unit testing the service-to-provider boundary; not part of the public deploy API.
338341
*/
339-
async function resolveTriggerCredentialId(
342+
export async function resolveTriggerCredentialId(
340343
credentialReference: string,
341344
workspaceId: string,
342345
serviceId: string
343346
): Promise<string | null> {
347+
const providerId = getProviderIdFromServiceId(serviceId)
344348
const [resolvedCredential] = await db
345349
.select({ id: credential.id })
346350
.from(credential)
347351
.where(
348352
and(
349353
eq(credential.workspaceId, workspaceId),
350354
eq(credential.type, 'oauth'),
351-
eq(credential.providerId, serviceId),
355+
eq(credential.providerId, providerId),
352356
or(eq(credential.id, credentialReference), eq(credential.accountId, credentialReference))
353357
)
354358
)

0 commit comments

Comments
 (0)