Skip to content

Commit d866849

Browse files
fix(tables): cap aggregate snapshot mounts
1 parent c04a28c commit d866849

2 files changed

Lines changed: 21 additions & 3 deletions

File tree

apps/sim/lib/copilot/tools/handlers/function-execute.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,21 @@ describe('executeFunctionExecute table mounts', () => {
650650
expect(mockGeneratePresignedDownloadUrl).not.toHaveBeenCalled()
651651
})
652652

653+
it('throws when cloud snapshots exceed the aggregate URL mount limit', async () => {
654+
mockGetTableById.mockImplementation(async (tableId: string) => ({ ...table, id: tableId }))
655+
mockGetOrCreateTableSnapshot.mockImplementation(async (mountedTable: typeof table) => ({
656+
key: `table-snapshots/ws_1/${mountedTable.id}/v5.csv`,
657+
size: 500 * 1024 * 1024,
658+
version: 5,
659+
}))
660+
const tableIds = Array.from({ length: 5 }, (_, index) => `tbl_${index}`)
661+
662+
await expect(
663+
executeFunctionExecute({ inputTables: tableIds }, context as never)
664+
).rejects.toThrow(/total mount limit/)
665+
expect(mockGeneratePresignedDownloadUrl).toHaveBeenCalledTimes(4)
666+
})
667+
653668
it('throws when a local snapshot exceeds the per-file mount limit', async () => {
654669
mockHasCloudStorage.mockReturnValue(false)
655670
mockGetOrCreateTableSnapshot.mockResolvedValue({

apps/sim/lib/copilot/tools/handlers/function-execute.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,20 +497,23 @@ export async function resolveInputFiles(
497497
}
498498

499499
if (hasCloudStorage()) {
500-
// Mount by reference: the sandbox fetches the snapshot straight from storage via a
501-
// presigned URL, so the bytes never pass through the web process — the only ceiling is
502-
// sandbox disk (enforced at materialization by SNAPSHOT_MAX_BYTES).
503500
if (snapshot.size > SNAPSHOT_MAX_BYTES) {
504501
throw new Error(
505502
`Input table "${tableId}" is ${Math.round(snapshot.size / 1024 / 1024)}MB, over the ${SNAPSHOT_MAX_BYTES / 1024 / 1024}MB table mount limit.`
506503
)
507504
}
505+
if (mounted.url + snapshot.size > MAX_TOTAL_URL_BYTES) {
506+
throw new Error(
507+
`Mounting "${tableId}" would exceed the ${MAX_TOTAL_URL_BYTES / 1024 / 1024 / 1024}GB total mount limit. Mount fewer or smaller files and tables.`
508+
)
509+
}
508510
const url = await generatePresignedDownloadUrl(
509511
snapshot.key,
510512
'execution',
511513
MOUNT_URL_TTL_SECONDS
512514
)
513515
sandboxFiles.push({ type: 'url', path: mountPath, url })
516+
mounted.url += snapshot.size
514517
continue
515518
}
516519

0 commit comments

Comments
 (0)