mirror of
https://github.com/supabase/supabase.git
synced 2026-06-29 03:50:30 -04:00
9bdb757b6a
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Refactor / security hardening — continues the analytics SQL provenance-tracking series (PR 8). ## What is the current behavior? - `generateRegexpWhere` (unsafe: interpolates user-controlled filter keys/values without escaping) still exists alongside `generateRegexpWhereSafe` and its tests only cover the old function. - `usePostgrestOverviewMetrics` builds a SQL query string with plain string interpolation and calls the analytics endpoint directly via `get()`. - `edge-functions-last-hour-stats-query` builds a SQL query with `functionIds` escaped via Postgres-only `quoteLiteral` and calls the analytics endpoint directly via `post()`. - `executeAnalyticsSql` has no way to pass a `key` query-string param for network-tool identification. - `rawSql('minute')` / `rawSql('hour')` / `rawSql('day')` and `rawSql(value ? 'true' : 'false')` are used for static strings that could be expressed with the `safeSql` template tag. ## What is the new behavior? - `generateRegexpWhere` is deleted; its tests are replaced with `generateRegexpWhereSafe` coverage including injection-attempt cases (`level OR id IS NOT NULL`, `request.method); DROP TABLE edge_logs; --`) that verify predicates are silently dropped rather than emitted. - `usePostgrestOverviewMetrics` returns `SafeLogSqlFragment` from its SQL builder and routes through `executeAnalyticsSql`. - `edge-functions-last-hour-stats-query` uses `analyticsLiteral` (BigQuery/ClickHouse-correct escaping) instead of `quoteLiteral` (Postgres-only) and routes through `executeAnalyticsSql`. - `executeAnalyticsSql` accepts an optional `key?: string` forwarded as a query-string param on both GET and POST requests; `key: 'last-hour-stats'` is restored on the edge-functions query. - Static `rawSql('...')` calls replaced with `safeSql\`...\`` template literals throughout. ## Additional context <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Bug Fixes - Removed legacy unsafe SQL-filter utility from Reports ## Chores - Enhanced analytics SQL execution infrastructure with improved error handling - Added optional request identification parameter to analytics query execution - Refined SQL filtering mechanisms in reporting features <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46466?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
/**
|
|
* Wire-boundary for analytics SQL execution.
|
|
*
|
|
* This is the analytics-path analog of pg-meta's `executeSql`. It accepts only
|
|
* `SafeLogSqlFragment` — plain strings are rejected at compile time — so any
|
|
* value flowing from URL parameters, UI inputs, or LLM output must pass through
|
|
* a sanitization helper in safe-analytics-sql.ts before reaching the wire.
|
|
*
|
|
* See .claude/skills/safe-sql-execution/SKILL.md for the full security model.
|
|
*/
|
|
import type { SafeLogSqlFragment } from './safe-analytics-sql'
|
|
import { get, handleError, post } from '@/data/fetchers'
|
|
|
|
/**
|
|
* Analytics endpoints that accept `{ sql, iso_timestamp_start, iso_timestamp_end }`
|
|
* either as a POST body or GET query string. Extend this union as additional
|
|
* endpoints are migrated to the safe-analytics-sql pattern.
|
|
*/
|
|
export type AnalyticsSqlEndpoint =
|
|
| '/platform/projects/{ref}/analytics/endpoints/logs.all'
|
|
| '/platform/projects/{ref}/analytics/endpoints/logs.all.otel'
|
|
|
|
export interface ExecuteAnalyticsSqlVariables {
|
|
projectRef: string
|
|
endpoint: AnalyticsSqlEndpoint
|
|
/** Must carry the `SafeLogSqlFragment` brand — plain strings are rejected at compile time. */
|
|
sql: SafeLogSqlFragment
|
|
iso_timestamp_start: string
|
|
iso_timestamp_end: string
|
|
/** Defaults to 'post'. Use 'get' to preserve wire behavior when migrating legacy GET callers. */
|
|
method?: 'get' | 'post'
|
|
/**
|
|
* Optional query-string key for network-tool identification.
|
|
* Not part of the OpenAPI schema; accepted by the server and visible in DevTools.
|
|
*/
|
|
key?: string
|
|
signal?: AbortSignal
|
|
headers?: HeadersInit
|
|
}
|
|
|
|
export async function executeAnalyticsSql({
|
|
projectRef,
|
|
endpoint,
|
|
sql,
|
|
iso_timestamp_start,
|
|
iso_timestamp_end,
|
|
method = 'post',
|
|
key,
|
|
signal,
|
|
headers: headersInit,
|
|
}: ExecuteAnalyticsSqlVariables) {
|
|
const headers = headersInit !== undefined ? new Headers(headersInit) : undefined
|
|
|
|
if (method === 'get') {
|
|
const { data, error } = await get(endpoint, {
|
|
params: {
|
|
path: { ref: projectRef },
|
|
query: { sql, iso_timestamp_start, iso_timestamp_end, ...(key ? { key } : {}) },
|
|
},
|
|
signal,
|
|
headers,
|
|
})
|
|
if (error) handleError(error)
|
|
return data
|
|
}
|
|
|
|
const { data, error } = await post(endpoint, {
|
|
// @ts-ignore key is not in the OpenAPI schema; included only for network-tool identification
|
|
params: { path: { ref: projectRef }, ...(key ? { query: { key } } : {}) },
|
|
body: { sql, iso_timestamp_start, iso_timestamp_end },
|
|
signal,
|
|
headers,
|
|
})
|
|
if (error) handleError(error)
|
|
return data
|
|
}
|