Skip to content

Commit 742ae70

Browse files
committed
fix(webhooks): restore NEXT_PUBLIC_APP_URL in emailbison tests, dedupe strict-delete warning log
Test env var mutation was never restored, risking cross-file leakage in single-threaded vitest runs. Strict-mode deleteSubscription failures were logged twice (once at the throw site with context, once generically by the outer catch); the outer catch now skips its own log for errors already logged at the throw site.
1 parent 0c4d6f3 commit 742ae70

2 files changed

Lines changed: 23 additions & 7 deletions

File tree

apps/sim/lib/webhooks/providers/emailbison.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @vitest-environment node
33
*/
44
import { inputValidationMock, inputValidationMockFns } from '@sim/testing'
5-
import { beforeEach, describe, expect, it, vi } from 'vitest'
5+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
66

77
vi.mock('@/lib/core/security/input-validation.server', () => inputValidationMock)
88

@@ -38,6 +38,10 @@ describe('emailBisonHandler createSubscription', () => {
3838
process.env.NEXT_PUBLIC_APP_URL = 'https://app.example.com'
3939
})
4040

41+
afterEach(() => {
42+
process.env.NEXT_PUBLIC_APP_URL = undefined
43+
})
44+
4145
it('rejects an apiBaseUrl that resolves to a blocked address before making a request', async () => {
4246
inputValidationMockFns.mockValidateUrlWithDNS.mockResolvedValue({
4347
isValid: false,

apps/sim/lib/webhooks/providers/emailbison.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ export const emailBisonHandler: WebhookProviderHandler = {
219219
hasApiBaseUrl: Boolean(apiBaseUrl),
220220
hasExternalId: Boolean(externalId),
221221
})
222-
if (ctx.strict) throw new Error('Missing Email Bison webhook cleanup configuration')
222+
if (ctx.strict)
223+
throw new AlreadyLoggedError('Missing Email Bison webhook cleanup configuration')
223224
return
224225
}
225226

@@ -233,7 +234,8 @@ export const emailBisonHandler: WebhookProviderHandler = {
233234
logger.warn(`[${requestId}] Invalid Email Bison Instance URL: ${urlValidation.error}`, {
234235
webhookId: webhook.id,
235236
})
236-
if (ctx.strict) throw new Error('Email Bison Instance URL could not be validated.')
237+
if (ctx.strict)
238+
throw new AlreadyLoggedError('Email Bison Instance URL could not be validated.')
237239
return
238240
}
239241

@@ -248,7 +250,8 @@ export const emailBisonHandler: WebhookProviderHandler = {
248250
status: response.status,
249251
response: responseBody,
250252
})
251-
if (ctx.strict) throw new Error(`Failed to delete Email Bison webhook: ${response.status}`)
253+
if (ctx.strict)
254+
throw new AlreadyLoggedError(`Failed to delete Email Bison webhook: ${response.status}`)
252255
return
253256
}
254257

@@ -258,14 +261,23 @@ export const emailBisonHandler: WebhookProviderHandler = {
258261
webhookId: webhook.id,
259262
})
260263
} catch (error) {
261-
logger.warn(`[${requestId}] Error deleting Email Bison webhook`, {
262-
message: toError(error).message,
263-
})
264+
if (!(error instanceof AlreadyLoggedError)) {
265+
logger.warn(`[${requestId}] Error deleting Email Bison webhook`, {
266+
message: toError(error).message,
267+
})
268+
}
264269
if (ctx.strict) throw error
265270
}
266271
},
267272
}
268273

274+
/**
275+
* Marks an error whose failure reason has already been logged with full context
276+
* at the throw site, so the outer catch in `deleteSubscription` does not emit
277+
* a second, redundant warning for the same failure.
278+
*/
279+
class AlreadyLoggedError extends Error {}
280+
269281
async function parseJsonResponse(
270282
response: SecureFetchResponse
271283
): Promise<Record<string, unknown> | null> {

0 commit comments

Comments
 (0)