Skip to content

Commit 1fdb0df

Browse files
committed
fix(security): advisory lock for env first-insert race; handle all BodyInit types in pinnedFetch
1 parent b7d57af commit 1fdb0df

2 files changed

Lines changed: 15 additions & 12 deletions

File tree

apps/sim/app/api/workspaces/[id]/environment/route.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ export const PUT = withRouteHandler(
104104
).then((entries) => Object.fromEntries(entries))
105105

106106
const { existingEncrypted, merged } = await db.transaction(async (tx) => {
107-
await tx.execute(
108-
sql`SELECT id FROM workspace_environment WHERE workspace_id = ${workspaceId} FOR UPDATE`
109-
)
107+
// Advisory lock serialises all writes for this workspaceId, including concurrent
108+
// first-inserts where no row exists yet and FOR UPDATE would acquire nothing.
109+
await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext(${workspaceId}))`)
110110

111111
const [existingRow] = await tx
112112
.select()
@@ -191,9 +191,7 @@ export const DELETE = withRouteHandler(
191191
const { keys } = parsed.data.body
192192

193193
const result = await db.transaction(async (tx) => {
194-
await tx.execute(
195-
sql`SELECT id FROM workspace_environment WHERE workspace_id = ${workspaceId} FOR UPDATE`
196-
)
194+
await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext(${workspaceId}))`)
197195

198196
const [existingRow] = await tx
199197
.select()

apps/sim/lib/a2a/utils.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,17 @@ export async function createA2AClient(agentUrl: string, apiKey?: string): Promis
8383

8484
let body: string | Buffer | Uint8Array | undefined
8585
if (init?.body !== undefined && init.body !== null) {
86-
body =
87-
typeof init.body === 'string' || Buffer.isBuffer(init.body)
88-
? (init.body as string | Buffer)
89-
: init.body instanceof Uint8Array
90-
? (init.body as Uint8Array)
91-
: undefined
86+
if (typeof init.body === 'string' || Buffer.isBuffer(init.body)) {
87+
body = init.body as string | Buffer
88+
} else if (init.body instanceof Uint8Array) {
89+
body = init.body
90+
} else if (init.body instanceof ArrayBuffer) {
91+
body = new Uint8Array(init.body)
92+
} else {
93+
// URLSearchParams, Blob, ReadableStream, FormData — read as text via Response
94+
const text = await new Response(init.body as BodyInit).text()
95+
if (text) body = text
96+
}
9297
} else if (input instanceof Request && !input.bodyUsed) {
9398
const text = await input.text()
9499
if (text) body = text

0 commit comments

Comments
 (0)