Skip to content

Commit 908617f

Browse files
committed
fix(selectors): redact email path segments from provider failure logs; correct table timeout guidance
1 parent 3d8996f commit 908617f

3 files changed

Lines changed: 33 additions & 8 deletions

File tree

‎apps/sim/lib/selectors/server/providers/http.test.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getMockLogger } from '@sim/testing/mocks/logger.mock'
12
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
23
import {
34
SelectorConnectionUnavailableError,
@@ -96,4 +97,23 @@ describe('provider HTTP selector boundary', () => {
9697
expect(cancel).toHaveBeenCalledOnce()
9798
}
9899
)
100+
101+
it('logs a failed provider call without its query string, search text, or email path segments', async () => {
102+
mockFetch.mockResolvedValueOnce(new Response('{}', { status: 404 }))
103+
104+
await expect(
105+
fetchProviderJson(
106+
"https://www.googleapis.com/calendar/v3/calendars/jane%40example.com/root/search(q='payroll')?access_token=secret"
107+
)
108+
).rejects.toBeInstanceOf(SelectorOptionsUnavailableError)
109+
110+
expect(getMockLogger('SelectorProviderHttp').warn).toHaveBeenCalledWith(
111+
'Selector provider request failed',
112+
{
113+
endpoint: 'www.googleapis.com/calendar/v3/calendars/{redacted}/root/search()',
114+
reason: 'status',
115+
status: 404,
116+
}
117+
)
118+
})
99119
})

‎apps/sim/lib/selectors/server/providers/http.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,17 @@ async function readBoundedBody(response: Response): Promise<string> {
4848
}
4949

5050
/**
51-
* Host and path of a provider request. The query string is dropped and OData-style path
52-
* arguments (`search(q='...')`) are blanked, since both can carry tokens or a user's search text.
51+
* Host and path of a provider request, with the parts that can carry user data removed: the query
52+
* string (tokens, filters), OData-style path arguments (`search(q='...')` holds search text), and
53+
* any segment holding an email address (a Google calendar id is usually its owner's address).
5354
*/
5455
function providerEndpoint(input: RequestInfo | URL): string | undefined {
5556
try {
5657
const url = new URL(input instanceof Request ? input.url : input)
57-
return `${url.host}${url.pathname.replace(/\([^/]*\)/g, '()')}`
58+
const path = url.pathname
59+
.replace(/\([^/]*\)/g, '()')
60+
.replace(/[^/]*(?:@|%40)[^/]*/gi, '{redacted}')
61+
return `${url.host}${path}`
5862
} catch {
5963
return undefined
6064
}

‎apps/sim/lib/table/application/rows.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -506,17 +506,18 @@ async function throwValidationResponse(
506506
}
507507

508508
/**
509-
* A structured row query cancelled by its own `statement_timeout`: the query shape costs more than
510-
* the table's size allows. Sorting or range-filtering on a stored column reads every row's data, so it is the
511-
* caller's to narrow, and retrying the same query only times out again.
509+
* A structured row query cancelled by its own `statement_timeout`. Sorting, range-filtering, or
510+
* counting on a stored column reads every row's full data, so on a large table the query only
511+
* finishes when that data happens to be cached. The fix is the caller's (narrow the query), so this
512+
* is a 400 with an actionable message rather than an opaque 500.
512513
*/
513514
function rethrowReadQueryError(error: unknown, tableId: string): never {
514515
if (getPostgresCancellationReason(error) === 'statement_timeout') {
515516
logger.warn('Table read hit its statement timeout', { tableId })
516517
throw new TableRowsValidationError(
517518
`The query took longer than ${READ_STATEMENT_TIMEOUT_MS / 1000} seconds and was stopped. ` +
518-
'Sorting or range-filtering on a column reads every row in the table, which is too slow ' +
519-
'at this table size. Sort by createdAt, add an equality filter, or keep ' +
519+
'Sorting, range-filtering, or counting on a column reads every row in the table, which ' +
520+
'is too slow at this table size. Sort by createdAt, add an equality filter, or keep ' +
520521
'fewer rows (an Expiration column deletes old rows automatically).',
521522
{ code: 'TABLE_QUERY_TIMEOUT' }
522523
)

0 commit comments

Comments
 (0)