Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import { formatDuration } from './QueryPerformance.utils'
import { calculatePercentilesFromHistogram } from './WithMonitor/WithMonitor.utils'

describe('formatDuration', () => {
it('should format seconds', () => {
Expand All @@ -22,3 +23,23 @@ describe('formatDuration', () => {
expect(formatDuration(90061000)).toBe('1d 1h 1m 1s')
})
})

describe('calculatePercentilesFromHistogram', () => {
it('should return zero for empty histogram', () => {
const result = calculatePercentilesFromHistogram([])
expect(result.p95).toBe(0)
})

it('should return valid p95 for typical distribution', () => {
const result = calculatePercentilesFromHistogram([10, 20, 30, 20, 10, 10])
expect(result.p95).toBeGreaterThan(0)
expect(result.p95).toBeGreaterThanOrEqual(result.p50)
})

it('should return consistent p95 for same input', () => {
const histogram = [10, 20, 30, 20, 10, 10]
const result1 = calculatePercentilesFromHistogram(histogram)
const result2 = calculatePercentilesFromHistogram(histogram)
expect(result1.p95).toBe(result2.p95)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Loader2 } from 'lucide-react'
import { ComposedChart } from 'components/ui/Charts/ComposedChart'
import type { MultiAttribute } from 'components/ui/Charts/ComposedChart.utils'
import type { ChartDataPoint } from './WithMonitor/WithMonitor.utils'
import { calculatePercentilesFromHistogram } from './WithMonitor/WithMonitor.utils'

interface QueryPerformanceChartProps {
dateRange?: {
Expand Down Expand Up @@ -61,12 +62,38 @@ export const QueryPerformanceChart = ({

switch (selectedMetric) {
case 'query_latency': {
const avgP95 = chartData.reduce((sum, d) => sum + d.p95_time, 0) / chartData.length
let trueP95: number = 0

if (parsedLogs && parsedLogs.length > 0) {
const bucketCount = parsedLogs[0]?.resp_calls?.length || 50
const combinedHistogram = new Array(bucketCount).fill(0)

parsedLogs.forEach((log) => {
if (log.resp_calls && Array.isArray(log.resp_calls)) {
log.resp_calls.forEach((count: number, index: number) => {
if (index < combinedHistogram.length) {
combinedHistogram[index] += count
}
})
}
})

// [kemal]: this might need a revisit
const percentiles = calculatePercentilesFromHistogram(combinedHistogram)
trueP95 = percentiles.p95
} else {
// [kemal]: fallback to weighted average
const totalCalls = chartData.reduce((sum, d) => sum + d.calls, 0)
trueP95 =
totalCalls > 0
? chartData.reduce((sum, d) => sum + d.p95_time * d.calls, 0) / totalCalls
: 0
}

return [
{
label: 'Average p95',
value: avgP95 >= 100 ? `${(avgP95 / 1000).toFixed(2)}s` : `${Math.round(avgP95)}ms`,
value: `${Math.round(trueP95)}ms`,
},
]
}
Expand Down
2 changes: 1 addition & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ services:
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
# https://github.com/supabase/cli/issues/14
KONG_DNS_ORDER: LAST,A,CNAME
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
SUPABASE_ANON_KEY: ${ANON_KEY}
Expand Down
42 changes: 42 additions & 0 deletions docker/volumes/api/kong.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,48 @@ services:
allow:
- admin

## Block access to /api/mcp
- name: mcp-blocker
_comment: 'Block direct access to /api/mcp'
url: http://studio:3000/api/mcp
routes:
- name: mcp-blocker-route
strip_path: true
paths:
- /api/mcp
plugins:
- name: request-termination
config:
status_code: 403
message: "Access is forbidden."

## MCP endpoint - local access
- name: mcp
_comment: 'MCP: /mcp -> http://studio:3000/api/mcp (local access)'
url: http://studio:3000/api/mcp
routes:
- name: mcp
strip_path: true
paths:
- /mcp
plugins:
# Block access to /mcp by default
- name: request-termination
config:
status_code: 403
message: "Access is forbidden."
# Enable local access (danger zone!)
# 1. Comment out the 'request-termination' section above
# 2. Uncomment the entire section below, including 'deny'
# 3. Add your local IPs to the 'allow' list
#- name: cors
#- name: ip-restriction
# config:
# allow:
# - 127.0.0.1
# - ::1
# deny: []

## Protected Dashboard - catch all remaining routes
- name: dashboard
_comment: 'Studio: /* -> http://studio:3000/*'
Expand Down
Loading