Skip to content

Commit a3d3f57

Browse files
committed
fix(supabase): scope Edge Function method/body/headers to invoke_function
Prevents a stale `method` value (e.g. from the Edge Function field) from leaking into other operations' params. The tool executor lets `params.method` override a tool's static verb (tools/utils.ts), so an unscoped value could turn a read into DELETE/POST against PostgREST. Now method/body/headers are only passed for the invoke_function operation. Adds a block-level regression test.
1 parent 78c3b4e commit a3d3f57

2 files changed

Lines changed: 71 additions & 6 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it } from 'vitest'
5+
import { SupabaseBlock } from '@/blocks/blocks/supabase'
6+
7+
describe('SupabaseBlock', () => {
8+
const buildParams = SupabaseBlock.tools.config.params!
9+
const selectTool = SupabaseBlock.tools.config.tool!
10+
11+
it('maps each operation to its tool id', () => {
12+
expect(selectTool({ operation: 'query' })).toBe('supabase_query')
13+
expect(selectTool({ operation: 'invoke_function' })).toBe('supabase_invoke_function')
14+
expect(selectTool({ operation: 'delete' })).toBe('supabase_delete')
15+
})
16+
17+
it('does not leak the Edge Function method onto other operations', () => {
18+
// A stale `method` from the Edge Function field must never reach a tool with a
19+
// static verb — otherwise the executor would let it override e.g. GET with DELETE.
20+
const params = buildParams({
21+
operation: 'query',
22+
projectId: 'proj',
23+
apiKey: 'key',
24+
table: 'users',
25+
method: 'DELETE',
26+
})
27+
28+
expect(params).not.toHaveProperty('method')
29+
expect(params).not.toHaveProperty('body')
30+
expect(params).not.toHaveProperty('headers')
31+
})
32+
33+
it('passes method, body, and headers through for invoke_function', () => {
34+
const params = buildParams({
35+
operation: 'invoke_function',
36+
projectId: 'proj',
37+
apiKey: 'key',
38+
functionName: 'hello-world',
39+
method: 'POST',
40+
functionBody: '{"name":"world"}',
41+
functionHeaders: '{"x-trace":"1"}',
42+
})
43+
44+
expect(params.method).toBe('POST')
45+
expect(params.body).toEqual({ name: 'world' })
46+
expect(params.headers).toEqual({ 'x-trace': '1' })
47+
})
48+
49+
it('rejects non-object Edge Function headers', () => {
50+
expect(() =>
51+
buildParams({
52+
operation: 'invoke_function',
53+
projectId: 'proj',
54+
apiKey: 'key',
55+
functionName: 'hello-world',
56+
functionHeaders: '["a","b"]',
57+
})
58+
).toThrow('Edge Function headers must be a JSON object')
59+
})
60+
})

apps/sim/blocks/blocks/supabase.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,7 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
10261026
fileData,
10271027
functionBody,
10281028
functionHeaders,
1029+
method,
10291030
...rest
10301031
} = params
10311032

@@ -1169,12 +1170,16 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
11691170
result.params = parsedRpcParams
11701171
}
11711172

1172-
if (parsedFunctionBody !== undefined) {
1173-
result.body = parsedFunctionBody
1174-
}
1175-
1176-
if (parsedFunctionHeaders !== undefined) {
1177-
result.headers = parsedFunctionHeaders
1173+
if (operation === 'invoke_function') {
1174+
if (method !== undefined) {
1175+
result.method = method
1176+
}
1177+
if (parsedFunctionBody !== undefined) {
1178+
result.body = parsedFunctionBody
1179+
}
1180+
if (parsedFunctionHeaders !== undefined) {
1181+
result.headers = parsedFunctionHeaders
1182+
}
11781183
}
11791184

11801185
if (parsedPaths !== undefined) {

0 commit comments

Comments
 (0)