mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
fix(logs): route the unified logs export through the safe SQL boundary
`retrieveUnifiedLogs` built its SQL with a plain template literal, which stringifies the `SafeLogSqlFragment` returned by the query builder and drops the brand, then posted it with a raw `post()` call. It was the one place in the logs data layer that bypassed `executeAnalyticsSql`, the wire boundary that rejects unbranded SQL at compile time. Composes with `safeSql` and runs through `executeAnalyticsSql` instead, matching the row-list query in `unified-logs-infinite-query.ts`. Like the row list, it now also raises an error the endpoint reports inside a successful response, instead of silently exporting an empty file. No behaviour change for valid input. The limit goes through `analyticsLiteral`, which rejects a non-finite value rather than emitting `LIMIT NaN` — not reachable from the download dialog, which offers 100/500/1000, but the previous code would have sent it verbatim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2cb70302b0
commit
f8fcdb0c27
1 file changed
+16
-7
@@ -2,13 +2,15 @@ import { useMutation } from '@tanstack/react-query'
|
||||
import { useFlag } from 'common'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { executeAnalyticsSql } from './execute-analytics-sql'
|
||||
import { logsAllEndpointUrl, pickLogsQueryBuilder } from './logs-endpoint'
|
||||
import { analyticsLiteral, safeSql } from './safe-analytics-sql'
|
||||
import { getUnifiedLogsISOStartEnd } from './unified-logs-infinite-query'
|
||||
import { mapUnifiedLogRow, parseUnifiedLogsQueryRows } from './unified-logs.utils'
|
||||
import { getUnifiedLogsQuery } from '@/components/interfaces/UnifiedLogs/UnifiedLogs.queries'
|
||||
import { getUnifiedLogsQuery as getUnifiedLogsQueryBq } from '@/components/interfaces/UnifiedLogs/UnifiedLogs.queries.bq'
|
||||
import { QuerySearchParamsType } from '@/components/interfaces/UnifiedLogs/UnifiedLogs.types'
|
||||
import { handleError, post } from '@/data/fetchers'
|
||||
import { handleError } from '@/data/fetchers'
|
||||
import type { ResponseError, UseCustomMutationOptions } from '@/types'
|
||||
|
||||
export type getUnifiedLogsVariables = {
|
||||
@@ -32,15 +34,22 @@ export async function retrieveUnifiedLogs({
|
||||
|
||||
const { isoTimestampStart, isoTimestampEnd } = getUnifiedLogsISOStartEnd(search, hoursAgo)
|
||||
const buildQuery = pickLogsQueryBuilder(useOtel, getUnifiedLogsQuery, getUnifiedLogsQueryBq)
|
||||
const sql = `${buildQuery(search)} ORDER BY timestamp DESC, id DESC LIMIT ${limit}`
|
||||
// `safeSql` (not a plain template literal) keeps the SafeLogSqlFragment brand
|
||||
// intact, and `analyticsLiteral` rejects a non-finite limit instead of
|
||||
// emitting `LIMIT NaN`. Mirrors the row-list query in
|
||||
// `unified-logs-infinite-query.ts`.
|
||||
const sql = safeSql`${buildQuery(search)} ORDER BY timestamp DESC, id DESC LIMIT ${analyticsLiteral(limit)}`
|
||||
|
||||
const endpoint = logsAllEndpointUrl(useOtel)
|
||||
const { data, error } = await post(endpoint, {
|
||||
params: { path: { ref: projectRef } },
|
||||
body: { iso_timestamp_start: isoTimestampStart, iso_timestamp_end: isoTimestampEnd, sql },
|
||||
const data = await executeAnalyticsSql({
|
||||
projectRef,
|
||||
endpoint: logsAllEndpointUrl(useOtel),
|
||||
sql,
|
||||
iso_timestamp_start: isoTimestampStart,
|
||||
iso_timestamp_end: isoTimestampEnd,
|
||||
})
|
||||
|
||||
if (error) handleError(error)
|
||||
// The endpoint can report a query error inside a successful response.
|
||||
if (data?.error) handleError(new Error(data.error as string))
|
||||
|
||||
const resultData = parseUnifiedLogsQueryRows(data?.result)
|
||||
const result = resultData.map(mapUnifiedLogRow)
|
||||
|
||||
Reference in new issue
Block a user