/** * Tests for function execution API route * * @vitest-environment node */ import { spawnSync } from 'node:child_process' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { createMockRequest, envFlagsMock, hybridAuthMockFns, resetEnvFlagsMock, workflowsUtilsMock, } from '@sim/testing' import { NextRequest } from 'next/server' import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest' import { INTERNAL_EXECUTION_DEADLINE_HEADER } from '@/lib/execution/execution-deadline-header' import { MOUNTED_WORKSPACE_FILES_PROVENANCE_KEY, PRIVATE_SECRET_PROVENANCE_BUNDLE_V1, PRIVATE_SECRET_PROVENANCE_FIELD, PRIVATE_SECRET_PROVENANCE_HEADER, } from '@/lib/execution/private-tool-metadata' import { MAX_SANDBOX_OUTPUT_BYTES, SandboxOutputFileError, SandboxOutputLimitError, } from '@/lib/execution/remote-sandbox/output-limits' function grantedAccess(workspaceId: string) { return { exists: true, hasAccess: true, canWrite: true, canAdmin: false, workspace: { id: workspaceId }, permission: 'admin', } } const { mockExecuteInSandbox, mockExecuteInIsolatedVM, mockExecuteShellInSandbox, mockFetchWorkspaceFileBuffer, mockDecryptSecret, mockEncryptSecret, mockGetWorkspaceFile, mockResolveWorkspaceFileReference, mockUpdateWorkspaceFileContent, mockUploadFile, mockValidateWorkspaceFileWriteTarget, mockWriteWorkspaceFileByPath, mockCheckWorkspaceAccess, mockResolveWorkspaceAccess, } = vi.hoisted(() => ({ mockExecuteInSandbox: vi.fn(), mockExecuteInIsolatedVM: vi.fn(), mockExecuteShellInSandbox: vi.fn(), mockFetchWorkspaceFileBuffer: vi.fn(), mockDecryptSecret: vi.fn(async (value: string) => ({ decrypted: value === 'encrypted:mounted-secret' ? 'mounted-secret' : value, })), mockEncryptSecret: vi.fn(async (value: string) => ({ encrypted: `encrypted:${value}`, iv: 'iv', })), mockGetWorkspaceFile: vi.fn(), mockResolveWorkspaceFileReference: vi.fn(), mockUpdateWorkspaceFileContent: vi.fn(), mockUploadFile: vi.fn(), mockValidateWorkspaceFileWriteTarget: vi.fn(), mockWriteWorkspaceFileByPath: vi.fn(), mockCheckWorkspaceAccess: vi.fn(), mockResolveWorkspaceAccess: vi.fn(), })) vi.mock('@/lib/workspaces/permissions/utils', () => ({ checkWorkspaceAccess: mockCheckWorkspaceAccess, resolveWorkspaceAccess: mockResolveWorkspaceAccess, })) vi.mock('@/lib/core/security/encryption', () => ({ decryptSecret: mockDecryptSecret, encryptSecret: mockEncryptSecret, })) vi.mock('@/lib/execution/isolated-vm', () => ({ executeInIsolatedVM: mockExecuteInIsolatedVM, })) vi.mock('@/lib/execution/remote-sandbox', () => ({ executeInSandbox: mockExecuteInSandbox, executeShellInSandbox: mockExecuteShellInSandbox, SIM_RESULT_PREFIX: '__SIM_RESULT__=', })) vi.mock('@/lib/copilot/request/tools/files', () => ({ FORMAT_TO_CONTENT_TYPE: { json: 'application/json', csv: 'text/csv', txt: 'text/plain', md: 'text/markdown', html: 'text/html', }, normalizeOutputWorkspaceFileName: vi.fn((p: string) => p.replace(/^files\//, '')), resolveOutputFormat: vi.fn(() => 'json'), getOutputFileDeclarations: vi.fn((params: Record) => { if (Array.isArray(params.outputs?.files)) { return params.outputs.files.map((file: Record) => ({ path: file.path, mode: file.mode === 'overwrite' ? 'overwrite' : 'create', sandboxPath: file.sandboxPath, mimeType: file.mimeType, format: file.format, })) } return params.outputPath ? [ { path: params.overwriteFileId || params.outputPath, mode: params.overwriteFileId ? 'overwrite' : 'create', sandboxPath: params.outputSandboxPath, mimeType: params.outputMimeType, format: params.outputFormat, formatPath: params.outputPath, overwriteFileId: params.overwriteFileId, }, ] : [] }), })) vi.mock('@/lib/copilot/vfs/resource-writer', () => ({ validateWorkspaceFileWriteTarget: mockValidateWorkspaceFileWriteTarget, writeWorkspaceFileByPath: mockWriteWorkspaceFileByPath, })) vi.mock('@/lib/uploads/contexts/workspace/workspace-file-manager', () => ({ fetchWorkspaceFileBuffer: mockFetchWorkspaceFileBuffer, getWorkspaceFile: mockGetWorkspaceFile, resolveWorkspaceFileReference: mockResolveWorkspaceFileReference, updateWorkspaceFileContent: mockUpdateWorkspaceFileContent, uploadWorkspaceFile: vi.fn(), })) vi.mock('@/lib/uploads', () => ({ StorageService: { uploadFile: mockUploadFile, }, })) vi.mock('@/lib/workflows/utils', () => workflowsUtilsMock) import { validateProxyUrl } from '@/lib/core/security/input-validation' import { clearLargeValueCacheForTests } from '@/lib/execution/payloads/cache' import { isLargeArrayManifest } from '@/lib/execution/payloads/large-array-manifest-metadata' import { isLargeValueRef } from '@/lib/execution/payloads/large-value-ref' import { POST } from '@/app/api/function/execute/route' afterAll(resetEnvFlagsMock) describe('Function Execute API Route', () => { beforeEach(() => { vi.clearAllMocks() envFlagsMock.isRemoteSandboxEnabled = false envFlagsMock.isMothershipSandboxEnabled = false hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValue({ success: true, userId: 'user-123', authType: 'internal_jwt', }) mockCheckWorkspaceAccess.mockImplementation(async (id: string) => grantedAccess(id)) mockResolveWorkspaceAccess.mockImplementation(async (id: string) => grantedAccess(id)) mockExecuteInIsolatedVM.mockResolvedValue({ result: 'test', stdout: '' }) mockUploadFile.mockImplementation(async ({ customKey }) => ({ key: customKey })) clearLargeValueCacheForTests() mockExecuteInSandbox.mockResolvedValue({ result: 'e2b success', stdout: 'e2b output', sandboxId: 'test-sandbox-id', }) mockExecuteShellInSandbox.mockResolvedValue({ result: null, stdout: '', sandboxId: 'test-shell-sandbox-id', }) mockGetWorkspaceFile.mockResolvedValue({ id: 'wf_existing', name: 'existing.png', size: 10, type: 'image/png', url: '/api/files/view/existing', key: 'workspace/existing.png', }) mockUpdateWorkspaceFileContent.mockResolvedValue({ id: 'wf_existing', name: 'existing.png', size: 20, type: 'image/png', url: '/api/files/view/existing', key: 'workspace/existing.png', }) mockResolveWorkspaceFileReference.mockResolvedValue(null) mockFetchWorkspaceFileBuffer.mockResolvedValue(Buffer.alloc(0)) mockValidateWorkspaceFileWriteTarget.mockImplementation(async ({ target }) => ({ mode: target.mode, vfsPath: target.path, })) mockWriteWorkspaceFileByPath.mockImplementation(async ({ target, buffer }) => ({ id: `wf_${String(target.path).split('/').pop()?.replace(/\W+/g, '_') || 'file'}`, name: String(target.path).split('/').pop() || 'file', vfsPath: target.path, downloadUrl: `/api/files/view/${encodeURIComponent(target.path)}`, mode: target.mode, size: buffer.length, contentType: target.mimeType || 'application/octet-stream', })) }) describe('Security Tests', () => { it('should reject unauthorized requests', async () => { hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: false, error: 'Unauthorized', }) const req = createMockRequest('POST', { code: 'return "test"', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(401) expect(data).toHaveProperty('error', 'Unauthorized') }) it('rejects a body-supplied workspaceId the acting user is not a member of', async () => { mockCheckWorkspaceAccess.mockResolvedValue({ exists: true, hasAccess: false, canWrite: false, canAdmin: false, workspace: { id: 'workspace-victim' }, permission: null, }) const req = createMockRequest('POST', { code: 'return "test"', workspaceId: 'workspace-victim', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(403) expect(data).toHaveProperty('error', 'Workspace access denied') expect(mockCheckWorkspaceAccess).toHaveBeenCalledWith('workspace-victim', 'user-123') expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() }) it('rejects a sandbox output export into a workspace the acting user cannot write to', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/tmp/out.txt': 'owned by attacker' }, }) const readOnly = { exists: true, hasAccess: true, canWrite: false, canAdmin: false, workspace: { id: 'workspace-victim' }, permission: 'read', } mockCheckWorkspaceAccess.mockResolvedValue(readOnly) mockResolveWorkspaceAccess.mockResolvedValue(readOnly) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-victim', outputs: { files: [{ path: 'files/README.md', mode: 'overwrite', sandboxPath: '/tmp/out.txt' }], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(403) expect(data).toHaveProperty('error', 'Workspace access denied') expect(mockValidateWorkspaceFileWriteTarget).not.toHaveBeenCalled() expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('rejects an export whose workspace is derived from a body-supplied workflowId', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/tmp/out.txt': 'owned by attacker' }, }) workflowsUtilsMock.getWorkflowById.mockResolvedValueOnce({ id: 'workflow-victim', workspaceId: 'workspace-victim', }) mockResolveWorkspaceAccess.mockResolvedValue({ exists: true, hasAccess: false, canWrite: false, canAdmin: false, workspace: { id: 'workspace-victim' }, permission: null, }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workflowId: 'workflow-victim', outputs: { files: [{ path: 'files/README.md', mode: 'overwrite', sandboxPath: '/tmp/out.txt' }], }, }) const response = await POST(req) expect(response.status).toBe(403) expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('runs import-free JavaScript in isolated-vm without a remote provider', async () => { const req = createMockRequest('POST', { code: 'return "test"', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(data.output.result).toBe('test') expect(mockExecuteInIsolatedVM).toHaveBeenCalledTimes(1) expect(mockExecuteInSandbox).not.toHaveBeenCalled() expect(mockExecuteShellInSandbox).not.toHaveBeenCalled() }) it('does not accept a Mothership sandbox profile from the request body', async () => { const req = createMockRequest('POST', { code: 'return "test"', sandboxProfile: 'mothership', }) const response = await POST(req) expect(response.status).toBe(200) expect(mockExecuteInIsolatedVM).toHaveBeenCalledTimes(1) expect(mockExecuteInSandbox).not.toHaveBeenCalled() }) it('fails closed when a trusted Mothership call has no configured image', async () => { hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: true, userId: 'user-123', authType: 'internal_jwt', sandboxProfile: 'mothership', }) const response = await POST( createMockRequest('POST', { code: 'return "test"', language: 'javascript' }) ) expect(response.status).toBe(503) await expect(response.json()).resolves.toMatchObject({ success: false, error: 'Mothership code sandbox is not configured', }) expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() expect(mockExecuteInSandbox).not.toHaveBeenCalled() }) it.each([ { language: 'javascript', code: 'return 42' }, { language: 'python', code: '__sim_result__ = 42' }, ])( 'runs trusted Mothership $language in the Mothership sandbox image', async ({ language, code }) => { envFlagsMock.isMothershipSandboxEnabled = true hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: true, userId: 'user-123', authType: 'internal_jwt', sandboxProfile: 'mothership', }) const response = await POST(createMockRequest('POST', { code, language })) expect(response.status).toBe(200) expect(mockExecuteInSandbox).toHaveBeenCalledWith( expect.objectContaining({ language, sandboxKind: 'mothership', }) ) expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() } ) it('runs trusted Mothership Shell in the Mothership sandbox image', async () => { envFlagsMock.isMothershipSandboxEnabled = true hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: true, userId: 'user-123', authType: 'internal_jwt', sandboxProfile: 'mothership', }) const response = await POST( createMockRequest('POST', { code: 'echo ready', language: 'shell' }) ) expect(response.status).toBe(200) expect(mockExecuteShellInSandbox).toHaveBeenCalledWith( expect.objectContaining({ sandboxKind: 'mothership' }) ) }) it.each([ { language: 'javascript', code: 'return 42' }, { language: 'python', code: '__sim_result__ = 42' }, ])( 'runs trusted Mothership $language in the selected Function-based Sim sandbox', async ({ language, code }) => { envFlagsMock.isRemoteSandboxEnabled = true hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: true, userId: 'user-123', authType: 'internal_jwt', sandboxProfile: 'mothership', }) const response = await POST( createMockRequest('POST', { code, language, workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) ) expect(response.status).toBe(200) const request = mockExecuteInSandbox.mock.calls.at(-1)?.[0] expect(request).toMatchObject({ language, workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) expect(request).not.toHaveProperty('sandboxKind') } ) it('runs trusted Mothership Shell in the selected Sim sandbox', async () => { envFlagsMock.isRemoteSandboxEnabled = true hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: true, userId: 'user-123', authType: 'internal_jwt', sandboxProfile: 'mothership', }) const response = await POST( createMockRequest('POST', { code: 'kubectl version --client', language: 'shell', workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) ) expect(response.status).toBe(200) const request = mockExecuteShellInSandbox.mock.calls.at(-1)?.[0] expect(request).toMatchObject({ workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) expect(request).not.toHaveProperty('sandboxKind') }) it('does not treat the Mothership base as a fallback for a selected Sim sandbox', async () => { envFlagsMock.isMothershipSandboxEnabled = true hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValueOnce({ success: true, userId: 'user-123', authType: 'internal_jwt', sandboxProfile: 'mothership', }) const response = await POST( createMockRequest('POST', { code: 'return 42', language: 'javascript', workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) ) expect(response.status).toBe(503) await expect(response.json()).resolves.toMatchObject({ error: 'The Function code sandbox is not configured', }) expect(mockExecuteInSandbox).not.toHaveBeenCalled() expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() }) it('forces import-free JavaScript into the remote runtime when a Sim sandbox is selected', async () => { envFlagsMock.isRemoteSandboxEnabled = true const response = await POST( createMockRequest('POST', { code: 'return 42', language: 'javascript', workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) ) expect(response.status).toBe(200) expect(mockExecuteInSandbox).toHaveBeenCalledWith( expect.objectContaining({ language: 'javascript', workspaceId: 'workspace-1', sandboxId: 'sandbox-1', }) ) expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() }) it('should prevent VM escape via constructor chain', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: undefined, stdout: '' }) const req = createMockRequest('POST', { code: 'return this.constructor.constructor("return process")().env', }) const response = await POST(req) const data = await response.json() if (response.status === 422 || response.status === 500) { expect(data.success).toBe(false) } else { const result = data.output?.result expect(result === undefined || result === null).toBe(true) } }) it.concurrent('should prevent access to require via constructor chain', async () => { const req = createMockRequest('POST', { code: ` const proc = this.constructor.constructor("return process")(); const fs = proc.mainModule.require("fs"); return fs.readFileSync("/etc/passwd", "utf8"); `, }) const response = await POST(req) const data = await response.json() if (response.status === 200) { const result = data.output?.result if (result !== undefined && result !== null && typeof result === 'string') { expect(result).not.toContain('root:') } } }) it('should not expose process object', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'undefined', stdout: '' }) const req = createMockRequest('POST', { code: 'return typeof process', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.output.result).toBe('undefined') }) it('should not expose require function', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'undefined', stdout: '' }) const req = createMockRequest('POST', { code: 'return typeof require', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.output.result).toBe('undefined') }) it.concurrent('should block SSRF attacks through secure fetch wrapper', async () => { expect(validateProxyUrl('http://169.254.169.254/latest/meta-data/').isValid).toBe(false) expect(validateProxyUrl('http://127.0.0.1:8080/admin').isValid).toBe(true) expect(validateProxyUrl('http://192.168.1.1/config').isValid).toBe(false) expect(validateProxyUrl('http://10.0.0.1/internal').isValid).toBe(false) }) it.concurrent('should allow legitimate external URLs', async () => { expect(validateProxyUrl('https://api.github.com/user').isValid).toBe(true) expect(validateProxyUrl('https://httpbin.org/get').isValid).toBe(true) expect(validateProxyUrl('https://example.com/api').isValid).toBe(true) }) it.concurrent('should block dangerous protocols', async () => { expect(validateProxyUrl('file:///etc/passwd').isValid).toBe(false) expect(validateProxyUrl('ftp://internal.server/files').isValid).toBe(false) expect(validateProxyUrl('gopher://old.server/menu').isValid).toBe(false) }) }) describe('Basic Function Execution', () => { it.concurrent('should execute simple JavaScript code successfully', async () => { const req = createMockRequest('POST', { code: 'return "Hello World"', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(data.output).toHaveProperty('result') expect(data.output).toHaveProperty('executionTime') }) it('compacts large array result fields to manifests when execution context is durable', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: { rows: Array.from({ length: 120_000 }, (_, index) => ({ key: `SIM-${index}`, payload: 'x'.repeat(100), })), }, stdout: '', }) const req = createMockRequest('POST', { code: 'return rows', workflowId: 'workflow-1', workspaceId: 'workspace-1', executionId: 'execution-1', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(isLargeArrayManifest(data.output.result.rows)).toBe(true) expect(data.output.result.rows).toMatchObject({ __simLargeArrayManifest: true, kind: 'array', totalCount: 120_000, }) }) it('keeps large string result fields as generic large value refs', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: { text: 'x'.repeat(9 * 1024 * 1024), }, stdout: '', }) const req = createMockRequest('POST', { code: 'return text', workflowId: 'workflow-1', workspaceId: 'workspace-1', executionId: 'execution-1', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(isLargeValueRef(data.output.result.text)).toBe(true) }) it('captures secret provenance before a large result is compacted', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: { text: `${'x'.repeat(9 * 1024 * 1024)}secret-at-the-end` }, stdout: '', }) const response = await POST( createMockRequest( 'POST', { code: 'return {{API_KEY}}', envVars: { API_KEY: 'secret-at-the-end' }, workflowId: 'workflow-1', workspaceId: 'workspace-1', executionId: 'execution-1', }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const data = await response.json() expect(isLargeValueRef(data.output.result.text)).toBe(true) expect(data.__resolvedSecretNames).toEqual(['API_KEY']) }) it('exports multiple declared sandbox output files', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/chart.png': 'iVBORw0KGgo=', '/home/user/summary.json': '{"ok":true}', }, }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/reports/chart.png', mode: 'create', sandboxPath: '/home/user/chart.png', mimeType: 'image/png', }, { path: 'files/reports/summary.json', mode: 'overwrite', sandboxPath: '/home/user/summary.json', mimeType: 'application/json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(mockExecuteInSandbox).toHaveBeenCalledWith( expect.objectContaining({ outputSandboxPaths: ['/home/user/chart.png', '/home/user/summary.json'], }) ) expect(mockValidateWorkspaceFileWriteTarget).toHaveBeenCalledTimes(2) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledTimes(2) expect(mockWriteWorkspaceFileByPath).toHaveBeenNthCalledWith( 1, expect.objectContaining({ target: expect.objectContaining({ path: 'files/reports/chart.png', mode: 'create' }), }) ) expect(mockWriteWorkspaceFileByPath).toHaveBeenNthCalledWith( 2, expect.objectContaining({ target: expect.objectContaining({ path: 'files/reports/summary.json', mode: 'overwrite', }), }) ) expect(data.output.result.files).toHaveLength(2) expect(data.resources).toEqual([ expect.objectContaining({ path: 'files/reports/chart.png' }), expect.objectContaining({ path: 'files/reports/summary.json' }), ]) }) it('atomically classifies text exports and acknowledges the durable v2 capability', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/secret.txt': 'Bearer secret-value' }, }) const response = await POST( createMockRequest( 'POST', { code: 'print("{{API_KEY}}")', language: 'python', workspaceId: 'workspace-1', envVars: { API_KEY: 'secret-value' }, outputs: { files: [ { path: 'files/secret.txt', sandboxPath: '/home/user/secret.txt', mimeType: 'text/plain', }, ], }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-durable-files-v2', } ) ) const data = await response.json() expect(response.status).toBe(200) expect(response.headers.get('x-sim-private-tool-metadata')).toBe( 'resolved-secret-names-durable-files-v2' ) expect(data).not.toHaveProperty('__resolvedSecretFileNames') expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ secretProvenance: { status: 'exact', entries: [ { name: 'API_KEY', encryptedValue: 'encrypted:secret-value', sourceUserId: 'user-123', sourceWorkspaceId: 'workspace-1', }, ], }, }) ) }) it('classifies text exports against private mounted-file provenance', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/copied.txt': 'Bearer mounted-secret' }, }) const response = await POST( createMockRequest( 'POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/copied.txt', sandboxPath: '/home/user/copied.txt', mimeType: 'text/plain', }, ], }, [PRIVATE_SECRET_PROVENANCE_FIELD]: { version: 1, complete: true, selections: [ { key: MOUNTED_WORKSPACE_FILES_PROVENANCE_KEY, provenance: { version: 1, complete: true, entries: [{ encryptedValue: 'encrypted:mounted-secret' }], scope: { userId: 'user-123', workspaceId: 'workspace-1' }, }, }, ], }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-durable-files-v2', [PRIVATE_SECRET_PROVENANCE_HEADER]: PRIVATE_SECRET_PROVENANCE_BUNDLE_V1, } ) ) expect(response.status).toBe(200) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ secretProvenance: { status: 'exact', entries: [ { name: 'MOUNTED_FILE_SECRET', encryptedValue: 'encrypted:mounted-secret', sourceUserId: 'user-123', sourceWorkspaceId: 'workspace-1', }, ], }, }) ) }) it('rejects a partial mounted-file provenance envelope before execution', async () => { const response = await POST( createMockRequest('POST', { code: 'return 1', [PRIVATE_SECRET_PROVENANCE_FIELD]: { version: 1, complete: true, selections: [ { key: MOUNTED_WORKSPACE_FILES_PROVENANCE_KEY, provenance: { version: 1, complete: true, entries: [] }, }, ], }, }) ) expect(response.status).toBe(400) expect(await response.json()).toEqual({ success: false, error: 'Mounted file secret provenance is invalid', }) expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() expect(mockExecuteInSandbox).not.toHaveBeenCalled() }) it('runs with authenticated incomplete mount provenance and marks exported bytes unknown', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'raw result', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/output.txt': 'raw output' }, }) const response = await POST( createMockRequest( 'POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/output.txt', sandboxPath: '/home/user/output.txt', mimeType: 'text/plain', }, ], }, [PRIVATE_SECRET_PROVENANCE_FIELD]: { version: 1, complete: false, selections: [], }, }, { [PRIVATE_SECRET_PROVENANCE_HEADER]: PRIVATE_SECRET_PROVENANCE_BUNDLE_V1 } ) ) expect(response.status).toBe(200) expect((await response.json()).output.result).toEqual( expect.objectContaining({ fileId: 'wf_output_txt', vfsPath: 'files/output.txt' }) ) expect(mockExecuteInSandbox).toHaveBeenCalledOnce() expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ buffer: Buffer.from('raw output'), secretProvenance: { status: 'unknown' }, }) ) }) it('does not rewrite a static export path that happens to equal a resolved secret', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/report.txt': 'safe content' }, }) const response = await POST( createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', envVars: { API_KEY: 'secret-value' }, outputs: { files: [ { path: 'files/report-secret-value.txt', sandboxPath: '/home/user/report.txt', mimeType: 'text/plain', }, ], }, }) ) const data = await response.json() expect(response.status).toBe(200) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ target: expect.objectContaining({ path: 'files/report-secret-value.txt' }), secretProvenance: { status: 'exact', entries: [] }, }) ) expect(JSON.stringify(data)).toContain('files/report-secret-value.txt') }) it('classifies a binary export exact-empty when no secret was in scope', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/small.jpg': '/9j/4AAQ' }, }) const response = await POST( createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/small.jpg', sandboxPath: '/home/user/small.jpg', mimeType: 'image/jpeg', }, ], }, }) ) expect(response.status).toBe(200) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ secretProvenance: { status: 'exact', entries: [] } }) ) }) it('classifies a binary export exact-empty when ordinary files were mounted without secret provenance', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/small.jpg': '/9j/4AAQ' }, }) const response = await POST( createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', _sandboxFiles: [{ path: '/home/user/in.bin', content: 'mounted bytes' }], outputs: { files: [ { path: 'files/small.jpg', sandboxPath: '/home/user/small.jpg', mimeType: 'image/jpeg', }, ], }, }) ) expect(response.status).toBe(200) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ secretProvenance: { status: 'exact', entries: [] } }) ) }) it('keeps a binary export unknown when a mounted input file carried a secret', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/small.jpg': '/9j/4AAQ' }, }) const response = await POST( createMockRequest( 'POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/small.jpg', sandboxPath: '/home/user/small.jpg', mimeType: 'image/jpeg', }, ], }, [PRIVATE_SECRET_PROVENANCE_FIELD]: { version: 1, complete: true, selections: [ { key: MOUNTED_WORKSPACE_FILES_PROVENANCE_KEY, provenance: { version: 1, complete: true, entries: [{ encryptedValue: 'encrypted:mounted-secret' }], scope: { userId: 'user-123', workspaceId: 'workspace-1' }, }, }, ], }, }, { [PRIVATE_SECRET_PROVENANCE_HEADER]: PRIVATE_SECRET_PROVENANCE_BUNDLE_V1, } ) ) expect(response.status).toBe(200) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ secretProvenance: { status: 'unknown' } }) ) }) it('marks binary exports unknown without failing the Function execution', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: '', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/archive.zip': 'UEsDBA==' }, }) const response = await POST( createMockRequest('POST', { code: 'print("{{API_KEY}}")', language: 'python', workspaceId: 'workspace-1', envVars: { API_KEY: 'secret-value' }, outputs: { files: [ { path: 'files/archive.zip', sandboxPath: '/home/user/archive.zip', mimeType: 'application/zip', }, ], }, }) ) expect(response.status).toBe(200) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ secretProvenance: { status: 'unknown' } }) ) }) it('rejects one oversized sandbox output before creating a workspace file buffer', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/report.json': 'x'.repeat(MAX_SANDBOX_OUTPUT_BYTES + 1), }, }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/report.json', sandboxPath: '/home/user/report.json', mimeType: 'application/json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(400) expect(data.error).toBe(`Sandbox output files exceed ${MAX_SANDBOX_OUTPUT_BYTES} bytes total`) expect(mockValidateWorkspaceFileWriteTarget).not.toHaveBeenCalled() expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('rejects cumulative sandbox output size before validating workspace destinations', async () => { envFlagsMock.isRemoteSandboxEnabled = true const fileSize = MAX_SANDBOX_OUTPUT_BYTES / 2 + 1 mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/first.json': 'x'.repeat(fileSize), '/home/user/second.json': 'y'.repeat(fileSize), }, }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/first.json', sandboxPath: '/home/user/first.json', mimeType: 'application/json', }, { path: 'files/second.json', sandboxPath: '/home/user/second.json', mimeType: 'application/json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(400) expect(data.error).toBe(`Sandbox output files exceed ${MAX_SANDBOX_OUTPUT_BYTES} bytes total`) expect(mockValidateWorkspaceFileWriteTarget).not.toHaveBeenCalled() expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('preserves output-limit classification from provider-side size inspection', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockRejectedValueOnce( new SandboxOutputLimitError(MAX_SANDBOX_OUTPUT_BYTES + 1) ) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/report.json', sandboxPath: '/home/user/report.json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(400) expect(data.error).toBe(`Sandbox output files exceed ${MAX_SANDBOX_OUTPUT_BYTES} bytes total`) expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('rejects non-regular sandbox output paths as a client error', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockRejectedValueOnce(new SandboxOutputFileError('/out/link.json')) const response = await POST( createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [{ path: 'files/report.json', sandboxPath: '/out/link.json' }], }, }) ) const data = await response.json() expect(response.status).toBe(400) expect(data.error).toContain('must reference a regular file') expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('prevalidates all sandbox output destinations before writing any files', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/first.json': '{"first":true}', '/home/user/second.json': '{"second":true}', }, }) mockValidateWorkspaceFileWriteTarget .mockResolvedValueOnce({ mode: 'create', vfsPath: 'files/first.json' }) .mockRejectedValueOnce(new Error('Directory not yet created: files/missing')) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/first.json', mode: 'create', sandboxPath: '/home/user/first.json', }, { path: 'files/missing/second.json', mode: 'create', sandboxPath: '/home/user/second.json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(400) expect(data.success).toBe(false) expect(data.error).toContain('Directory not yet created') expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('rejects duplicate sandbox output destinations before writing files', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/first.json': '{"first":true}', '/home/user/second.json': '{"second":true}', }, }) mockValidateWorkspaceFileWriteTarget.mockResolvedValue({ mode: 'create', vfsPath: 'files/dupe.json', }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/dupe.json', mode: 'create', sandboxPath: '/home/user/first.json', }, { path: 'files/dupe.json', mode: 'create', sandboxPath: '/home/user/second.json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(400) expect(data.success).toBe(false) expect(data.error).toContain('Duplicate sandbox output destination') expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('returns a targeted error when a declared sandbox output is missing', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: {}, }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/missing.json', mode: 'create', sandboxPath: '/home/user/missing.json', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(500) expect(data.success).toBe(false) expect(data.error).toContain('Sandbox file "/home/user/missing.json" was not found') expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('rejects sandboxPath outputs when the call would run in isolated-vm (E2B enabled, JS without imports)', async () => { envFlagsMock.isRemoteSandboxEnabled = true const req = createMockRequest('POST', { code: 'return "content"', language: 'javascript', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/doc.md', mode: 'overwrite', sandboxPath: '/home/user/doc.md', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toContain('no sandbox filesystem') expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() expect(mockExecuteInSandbox).not.toHaveBeenCalled() expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled() }) it('rejects sandbox file mounts when the call would run in isolated-vm', async () => { const req = createMockRequest('POST', { code: 'return 1', language: 'javascript', workspaceId: 'workspace-1', _sandboxFiles: [{ path: '/home/user/files/data.csv', content: 'a,b\n1,2' }], }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) // No remote sandbox is enabled in this test, so the remediation must name // that cause instead of suggesting python (which would also fail without one). expect(data.error).toContain('No remote code sandbox is enabled') expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() }) it('flags an overwrite export whose bytes are identical to the current file content as unchanged', async () => { envFlagsMock.isRemoteSandboxEnabled = true const staleContent = '# doc\nunchanged mounted content\n' mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/doc.md': staleContent }, }) mockResolveWorkspaceFileReference.mockResolvedValue({ id: 'wf_doc', name: 'doc.md', size: Buffer.byteLength(staleContent, 'utf-8'), key: 'workspace/doc.md', }) mockFetchWorkspaceFileBuffer.mockResolvedValue(Buffer.from(staleContent, 'utf-8')) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/doc.md', mode: 'overwrite', sandboxPath: '/home/user/doc.md', mimeType: 'text/markdown', }, ], }, }) const response = await POST(req) const data = await response.json() // Idempotent overwrites (retries, unchanged regenerations) must not fail; // the write proceeds and the receipt carries the loud unchanged signal so // the model can tell its "new content" never reached the sandbox file. expect(response.status).toBe(200) expect(data.success).toBe(true) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledTimes(1) expect(data.output.result.unchanged).toBe(true) expect(data.output.result.message).toContain('byte-identical to the previous version') expect(data.output.result.message).toContain('/home/user/doc.md') }) it('reports size, previousSize, and sha256 receipts on a successful overwrite export', async () => { envFlagsMock.isRemoteSandboxEnabled = true const newContent = '# doc\nnew content\n' mockExecuteInSandbox.mockResolvedValueOnce({ result: 'done', stdout: 'ok', sandboxId: 'sandbox-123', exportedFiles: { '/home/user/doc.md': newContent }, }) mockResolveWorkspaceFileReference.mockResolvedValue({ id: 'wf_doc', name: 'doc.md', size: 36728, key: 'workspace/doc.md', }) const req = createMockRequest('POST', { code: 'print("done")', language: 'python', workspaceId: 'workspace-1', outputs: { files: [ { path: 'files/doc.md', mode: 'overwrite', sandboxPath: '/home/user/doc.md', mimeType: 'text/markdown', }, ], }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) // Sizes differ, so the current content is never downloaded for comparison. expect(mockFetchWorkspaceFileBuffer).not.toHaveBeenCalled() expect(data.output.result.size).toBe(Buffer.byteLength(newContent, 'utf-8')) expect(data.output.result.previousSize).toBe(36728) expect(data.output.result.sha256).toMatch(/^[0-9a-f]{64}$/) expect(data.output.result.unchanged).toBe(false) expect(data.output.result.message).toContain('replaced 36728 bytes') expect(data.output.result.message).toContain('sha256:') // The python wrapper prints the marker with a leading \n so it always // starts a fresh line even after non-newline-terminated user output. const e2bCode = mockExecuteInSandbox.mock.calls[0][0].code as string expect(e2bCode).toContain("print('\\n__SIM_RESULT__=' + json.dumps(__sim_result__))") }) it('runs complete Python modules without nesting their main guard inside a function', async () => { envFlagsMock.isRemoteSandboxEnabled = true const source = [ 'import subprocess', '', 'def main():', ' subprocess.run(["bq", "version"], check=True)', '', 'if __name__ == "__main__":', ' main()', ].join('\n') const response = await POST( createMockRequest('POST', { code: source, language: 'python', workspaceId: 'workspace-1', }) ) expect(response.status).toBe(200) const e2bCode = mockExecuteInSandbox.mock.calls[0][0].code as string expect(e2bCode).toContain('compile(__sim_source__, "", "exec")') expect(e2bCode).toContain('__sim_exec_globals__["__name__"] = "__main__"') expect(e2bCode).toContain(JSON.stringify(source)) expect(e2bCode).not.toContain('def __sim_main__():\n import subprocess') }) it('supports a Fellows-style Python module that invokes bq and exports a deterministic archive', async () => { envFlagsMock.isRemoteSandboxEnabled = true const archiveBase64 = 'UEsDBBQAAAAIAAAAIQAcWyFBIAAAAB8AAAAMAAAAcHJldmlldy5odG1ss8kwtHNLzcnJLy9WcM4vzUvOzFEIT03Nzqm00QdKAQBQSwECFAMUAAAACAAAACEAHFshQSAAAAAfAAAADAAAAAAAAAAAAAAAgAEAAAAAcHJldmlldy5odG1sUEsFBgAAAAABAAEAOgAAAEoAAAAAAA==' const source = readFileSync( resolve(process.cwd(), 'lib/execution/remote-sandbox/fixtures/fellows-council-weekly.py'), 'utf8' ) mockExecuteInSandbox.mockResolvedValueOnce({ result: null, stdout: 'generated 1 preview', sandboxId: 'sandbox-123', exportedFiles: { '/tmp/fellows-previews.zip': archiveBase64 }, }) const response = await POST( createMockRequest('POST', { code: source, language: 'python', workspaceId: 'workspace-1', sandboxId: 'fellows-sandbox', envVars: { AIRTABLE_PAT: 'stub-airtable-token', ANTHROPIC_API_KEY: 'stub-anthropic-key', GOOGLE_SERVICE_ACCOUNT_JSON: '{"type":"service_account","project_id":"fixture-project"}', NCBI_API_KEY: 'stub-ncbi-key', }, outputs: { files: [ { path: 'files/fellows-previews.zip', sandboxPath: '/tmp/fellows-previews.zip', mimeType: 'application/zip', }, ], }, }) ) expect(response.status).toBe(200) const sandboxRequest = mockExecuteInSandbox.mock.calls[0][0] expect(sandboxRequest.code).toContain("['bq', 'query'") expect(sandboxRequest.code).toContain('__sim_exec_globals__["__name__"] = "__main__"') expect(sandboxRequest.sandboxId).toBe('fellows-sandbox') expect(sandboxRequest.outputSandboxPaths).toEqual(['/tmp/fellows-previews.zip']) expect(mockWriteWorkspaceFileByPath).toHaveBeenCalledWith( expect.objectContaining({ buffer: Buffer.from(archiveBase64, 'base64'), target: expect.objectContaining({ path: 'files/fellows-previews.zip' }), }) ) }) it('retains Function-body return semantics for Python snippets', async () => { envFlagsMock.isRemoteSandboxEnabled = true await POST( createMockRequest('POST', { code: 'value = 41\nreturn value + 1', language: 'python', workspaceId: 'workspace-1', }) ) const e2bCode = mockExecuteInSandbox.mock.calls[0][0].code as string expect(e2bCode).toContain('"outside function" not in str(__sim_compile_error__)') expect(e2bCode).toContain('__sim_result__ = __sim_exec_globals__["__sim_main__"]()') }) it.each([ { reason: 'timeout', status: 408, message: 'timed out' }, { reason: 'user', status: 499, message: 'cancelled' }, ])('keeps $reason aborts distinct', async ({ reason, status, message }) => { envFlagsMock.isRemoteSandboxEnabled = true const controller = new AbortController() const req = new NextRequest('http://localhost:3000/api/function/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: 'print("running")', language: 'python', workspaceId: 'workspace-1', timeout: 30_000, }), signal: controller.signal, }) mockExecuteInSandbox.mockImplementationOnce(async () => { controller.abort(new DOMException(reason, 'AbortError')) throw controller.signal.reason }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(status) expect(data.error).toContain(message) }) it.each([ { termination: 'timeout' as const, errorName: 'TimeoutError', status: 408, message: 'timed out', }, { termination: 'cancelled' as const, errorName: 'AbortError', status: 499, message: 'cancelled', }, ])( 'classifies trusted isolated-vm $termination results consistently with remote runtimes', async ({ termination, errorName, status, message }) => { const partialStdout = `partial output before ${termination}` mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: partialStdout, error: { name: errorName, message: `${errorName} from isolated-vm` }, termination, }) const response = await POST( createMockRequest('POST', { code: 'return true', language: 'javascript', timeout: 30_000, }) ) const data = await response.json() expect(response.status).toBe(status) expect(data.error).toContain(message) expect(data.output.stdout).toBe(partialStdout) } ) it.each(['TimeoutError', 'AbortError'])( 'keeps a user-thrown %s as an ordinary code error', async (errorName) => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: 'partial output before user error', error: { name: errorName, message: `User threw ${errorName}` }, }) const response = await POST( createMockRequest('POST', { code: `const error = new Error('user error'); error.name = '${errorName}'; throw error`, language: 'javascript', timeout: 30_000, }) ) const data = await response.json() expect(response.status).toBe(422) expect(data.output.stdout).toBe('partial output before user error') expect(data.debug.errorType).toBe(errorName) } ) it('enforces the explicit Function timeout with a server-owned abort signal', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockImplementationOnce( ({ signal }: { signal: AbortSignal }) => new Promise((_resolve, reject) => { signal.addEventListener('abort', () => reject(signal.reason), { once: true }) }) ) const response = await POST( createMockRequest('POST', { code: 'print("running")', language: 'python', workspaceId: 'workspace-1', timeout: 1, }) ) const data = await response.json() expect(response.status).toBe(408) expect(data.error).toContain('timed out after 1ms') }) it('uses the remaining workflow deadline when no block timeout is supplied', async () => { envFlagsMock.isRemoteSandboxEnabled = true const remainingBudgetMs = 10 * 60_000 const req = new NextRequest('http://localhost:3000/api/function/execute', { method: 'POST', headers: { 'Content-Type': 'application/json', [INTERNAL_EXECUTION_DEADLINE_HEADER]: String(Date.now() + remainingBudgetMs), }, body: JSON.stringify({ code: 'print("running")', language: 'python', workspaceId: 'workspace-1', }), }) const response = await POST(req) expect(response.status).toBe(200) const sandboxRequest = mockExecuteInSandbox.mock.calls[0][0] expect(sandboxRequest.timeoutMs).toBeGreaterThan(9 * 60_000) expect(sandboxRequest.timeoutMs).toBeLessThanOrEqual(remainingBudgetMs) }) it('classifies a client abort at the propagated execution deadline as a timeout', async () => { envFlagsMock.isRemoteSandboxEnabled = true const controller = new AbortController() const req = new NextRequest('http://localhost:3000/api/function/execute', { method: 'POST', headers: { 'Content-Type': 'application/json', [INTERNAL_EXECUTION_DEADLINE_HEADER]: String(Date.now() - 1_000), }, body: JSON.stringify({ code: 'print("running")', language: 'python', workspaceId: 'workspace-1', timeout: 30_000, }), signal: controller.signal, }) mockExecuteInSandbox.mockImplementationOnce(async (sandboxRequest) => { expect(sandboxRequest.timeoutMs).toBe(1) controller.abort(new DOMException('The operation was aborted.', 'AbortError')) throw controller.signal.reason }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(408) expect(data.error).toContain('timed out') }) it('should return computed result for multi-line code', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 10, stdout: '' }) const req = createMockRequest('POST', { code: 'const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;\nreturn a + b + c + d;', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(data.output.result).toBe(10) }) it.concurrent('should handle missing code parameter', async () => { const req = createMockRequest('POST', { timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(400) expect(data).toHaveProperty('error') }) it.concurrent('should use default timeout when not provided', async () => { const req = createMockRequest('POST', { code: 'return "test"', }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) }) it('rejects large refs in runtimes without ref-native helpers', async () => { envFlagsMock.isRemoteSandboxEnabled = true const req = createMockRequest('POST', { code: 'echo "$__blockRef_0"', language: 'shell', contextVariables: { __blockRef_0: { __simLargeValueRef: true, version: 1, id: 'lv_ABCDEFGHIJKL', kind: 'array', size: 12 * 1024 * 1024, executionId: 'execution-1', }, }, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(500) expect(data.success).toBe(false) expect(data.error).toContain( 'Large execution values require the JavaScript isolated-vm runtime' ) }) it('registers manifest array read broker for isolated-vm execution', async () => { const req = createMockRequest('POST', { code: 'return await sim.values.readArray(__blockRef_0)', language: 'javascript', contextVariables: { __blockRef_0: { __simLargeArrayManifest: true, version: 2, kind: 'array', totalCount: 1, chunkCount: 1, byteSize: 16, chunks: [ { ref: { __simLargeValueRef: true, version: 1, id: 'lv_ABCDEFGHIJKL', kind: 'array', size: 16, executionId: 'execution-1', }, count: 1, byteSize: 16, }, ], preview: [{ id: 1 }], }, }, }) const response = await POST(req) const data = await response.json() const [, options] = mockExecuteInIsolatedVM.mock.calls.at(-1) ?? [] expect(response.status).toBe(200) expect(data.success).toBe(true) expect(options?.brokers).toHaveProperty('sim.values.readArray') }) }) describe('Template Variable Resolution', () => { it('should resolve environment variables with {{var_name}} syntax', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'secret-key-123', stdout: '' }) const req = createMockRequest( 'POST', { code: 'return {{API_KEY}}', envVars: { API_KEY: 'secret-key-123', }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.__resolvedSecretNames).toEqual(['API_KEY']) }) it('keeps an exact-name/exact-value JavaScript secret out of source and returns its raw runtime value with private provenance', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'Test', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'return {{Test}}', language: 'javascript', envVars: { Test: 'Test' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const data = await response.json() const [request] = mockExecuteInIsolatedVM.mock.calls.at(-1) ?? [] const bindingEntries = Object.entries(request.contextVariables) expect(response.status).toBe(200) expect(request.code).not.toContain('Test') expect(request.code).not.toContain('{{Test}}') expect(request.code).not.toContain('__var_') expect(bindingEntries).toHaveLength(1) expect(bindingEntries[0]?.[0]).toMatch(/^__sim_code_\d+_binding_\d+$/) expect(bindingEntries[0]?.[1]).toBe('Test') expect(data.output.result).toBe('Test') expect(data.__resolvedSecretNames).toEqual(['Test']) expect(JSON.stringify(data)).not.toContain('__sim_code_') expect(JSON.stringify(data)).not.toContain('__var_') }) it('keeps an exact-name/exact-value Python secret out of source and supplies it only through private runtime input', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteInSandbox.mockResolvedValueOnce({ result: 'Test', stdout: '', sandboxId: 'test-sandbox-id', }) const response = await POST( createMockRequest( 'POST', { code: 'return {{Test}}', language: 'python', envVars: { Test: 'Test' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const data = await response.json() const [request] = mockExecuteInSandbox.mock.calls.at(-1) ?? [] const runtimeInput = request.privateInputs.find( (input: { environmentVariable: string }) => input.environmentVariable === '__SIM_RUNTIME_PAYLOAD_PATH' ) const runtimePayload = JSON.parse(runtimeInput?.content ?? '{}') const secretBinding = runtimePayload.contextVariables.find( (entry: { value?: unknown }) => entry.value === 'Test' ) expect(response.status).toBe(200) expect(request.code).not.toContain('Test') expect(request.code).not.toContain('{{Test}}') expect(request.code).not.toContain('__var_') expect(runtimePayload.environmentVariables).toEqual({ Test: 'Test' }) expect(secretBinding).toMatchObject({ kind: 'json', value: 'Test' }) expect(secretBinding.name).toMatch(/^__sim_code_\d+_binding_\d+__$/) expect(request.code).toContain(secretBinding.name) expect(data.output.result).toBe('Test') expect(data.__resolvedSecretNames).toEqual(['Test']) expect(JSON.stringify(data)).not.toContain('__sim_code_') expect(JSON.stringify(data)).not.toContain('__var_') }) it('compiles legacy bare and quoted Custom Tool placeholders into opaque VM bindings', async () => { const secret = 'quote" slash\\ newline\n{{OTHER}} true 123' mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: [secret, secret, `Bearer ${secret}`], stdout: '', }) const response = await POST( createMockRequest( 'POST', { code: [ 'const bare = {{API_KEY}}', 'const quoted = "{{API_KEY}}"', 'return [bare, quoted, "Bearer {{API_KEY}}"]', ].join('\n'), isCustomTool: true, envVars: { API_KEY: secret, OTHER: 'must-not-resolve' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const [request] = mockExecuteInIsolatedVM.mock.calls.at(-1) ?? [] expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual(['API_KEY']) expect(request.code).not.toContain(secret) expect(request.code).not.toContain('__var_') expect(request.code).toContain('__sim_code_') expect(request.code).not.toContain('globalThis[') expect(Object.values(request.contextVariables)).toContain(secret) expect(Object.keys(request.contextVariables)).not.toContain('API_KEY') }) it('installs regex constructors as opaque runtime bindings before isolated user code', async () => { const response = await POST( createMockRequest('POST', { code: [ 'RegExp.prototype.constructor = null', 'return /^{{PATTERN}}$/.test("candidate")', ].join('\n'), envVars: { PATTERN: 'secret' }, }) ) const [request] = mockExecuteInIsolatedVM.mock.calls.at(-1) ?? [] const [runtimeBinding] = request.runtimeBindings expect(response.status).toBe(200) expect(runtimeBinding.kind).toBe('javascript-runtime') expect(request.code).toContain(`new ${runtimeBinding.name}.RegExp`) expect(request.code).not.toContain('secret') }) it('captures regex constructors in the remote preload before static imports execute', async () => { envFlagsMock.isRemoteSandboxEnabled = true const response = await POST( createMockRequest('POST', { code: ['import "side-effect-module"', 'return /^{{PATTERN}}$/.test("candidate")'].join( '\n' ), language: 'javascript', envVars: { PATTERN: 'secret' }, }) ) const [sandboxRequest] = mockExecuteInSandbox.mock.calls.at(-1) ?? [] const runtimeBindingName = /new (__sim_code_\d+_runtime_\d+)\.RegExp/.exec( sandboxRequest.code )?.[1] expect(response.status).toBe(200) expect(runtimeBindingName).toBeDefined() expect(sandboxRequest.runtimeBindings).toContainEqual({ name: runtimeBindingName, kind: 'javascript-runtime', }) expect(JSON.stringify(sandboxRequest.runtimeBindings)).not.toContain('secret') }) it('allocates remote runtime helpers against decoded JavaScript identifiers', async () => { envFlagsMock.isRemoteSandboxEnabled = true const escapedAlias = String.raw`\u005f\u005fsim_runtime_read_0` const response = await POST( createMockRequest('POST', { code: [ `import { basename as ${escapedAlias} } from "node:path"`, `return ["{{KEY}}", ${escapedAlias}("/tmp/file.txt")]`, ].join('\n'), language: 'javascript', envVars: { KEY: 'secret' }, }) ) const [sandboxRequest] = mockExecuteInSandbox.mock.calls.at(-1) ?? [] const syntaxCheck = spawnSync(process.execPath, ['--input-type=module', '--check'], { encoding: 'utf8', input: sandboxRequest.code, }) expect(response.status).toBe(200) expect(sandboxRequest.code).toContain('readFileSync as __sim_runtime_read_1') expect(sandboxRequest.code).not.toContain('readFileSync as __sim_runtime_read_0') expect(syntaxCheck.stderr).toBe('') expect(syntaxCheck.status).toBe(0) }) it('keeps comments and missing placeholders unchanged without secret provenance', async () => { const response = await POST( createMockRequest( 'POST', { code: '// {{COMMENT_ONLY}}\nreturn "{{MISSING}}"', envVars: { COMMENT_ONLY: 'must-not-bind' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const [request] = mockExecuteInIsolatedVM.mock.calls.at(-1) ?? [] expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual([]) expect(request.code).toContain('// {{COMMENT_ONLY}}') expect(request.code).toContain('"{{MISSING}}"') expect(Object.values(request.contextVariables)).not.toContain('must-not-bind') }) it('does not infer provenance from an unused low-entropy environment value', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'Box eSign', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'return "Box eSign"', envVars: { SERVICENOW_PASSWORD: 'x' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const data = await response.json() expect(response.status).toBe(200) expect(data.output.result).toBe('Box eSign') expect(data.__resolvedSecretNames).toEqual([]) }) it('does not build provenance matchers for unused oversized environment values', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'safe', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'return "safe"', envVars: { UNUSED: 'x'.repeat(65 * 1024) }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual([]) }) it('conservatively reports only compiled secrets when bounded output classification is exceeded', async () => { const result = Array.from({ length: 100_001 }, () => 'ordinary') mockExecuteInIsolatedVM.mockResolvedValueOnce({ result, stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'const key = {{API_KEY}}; return params.items', params: { items: result }, envVars: { API_KEY: 'secret-value', UNUSED: 'x' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const data = await response.json() expect(response.status).toBe(200) expect(response.headers.get('x-sim-private-tool-metadata')).toBe('resolved-secret-names-v1') expect(data.output.result).toHaveLength(100_001) expect(data.output.result[0]).toBe('ordinary') expect(data.__resolvedSecretNames).toEqual(['API_KEY']) }) it('conservatively reports a compiled secret whose value exceeds matcher capacity', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'ordinary', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'const key = {{OVERSIZED_SECRET}}; return "ordinary"', envVars: { OVERSIZED_SECRET: 's'.repeat(64 * 1024 + 1), UNUSED: 'x' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const data = await response.json() expect(response.status).toBe(200) expect(data.output.result).toBe('ordinary') expect(data.__resolvedSecretNames).toEqual(['OVERSIZED_SECRET']) }) it('tracks only compiled names when configured secrets share the same value', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'true', stdout: '' }) const oneResponse = await POST( createMockRequest( 'POST', { code: 'return {{SECOND}}', envVars: { FIRST: 'true', SECOND: 'true' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'true', stdout: '' }) const bothResponse = await POST( createMockRequest( 'POST', { code: 'const first = {{FIRST}}; return {{SECOND}}', envVars: { FIRST: 'true', SECOND: 'true' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) expect((await oneResponse.json()).__resolvedSecretNames).toEqual(['SECOND']) expect((await bothResponse.json()).__resolvedSecretNames).toEqual(['FIRST', 'SECOND']) }) it('lowers missing shell placeholders while preserving comments and heredoc delimiters', async () => { envFlagsMock.isRemoteSandboxEnabled = true const response = await POST( createMockRequest( 'POST', { code: [ '# {{COMMENT_ONLY}}', 'printf \'%s\\n\' "before{{MISSING}}after"', "cat <<'{{DELIMITER}}'", 'literal body', '{{DELIMITER}}', ].join('\n'), language: 'shell', envVars: { COMMENT_ONLY: 'must-not-bind' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const [request] = mockExecuteShellInSandbox.mock.calls.at(-1) ?? [] expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual([]) expect(request.code).toContain('# {{COMMENT_ONLY}}') expect(request.code).toContain('"beforeafter"') expect(request.code).toContain("cat <<'{{DELIMITER}}'") expect(request.code).toContain('\n{{DELIMITER}}') expect(request.code).not.toContain('{{MISSING}}') }) it.each([ { language: 'javascript', code: 'import path from "node:path"\nreturn "{{API_KEY}}"', }, { language: 'python', code: 'return "{{API_KEY}}"' }, ])( 'keeps $language runtime values out of remote generated source', async ({ language, code }) => { envFlagsMock.isRemoteSandboxEnabled = true const secret = 'remote"\\\nsecret' const response = await POST( createMockRequest('POST', { code, language, envVars: { API_KEY: secret }, params: { input: 'value' }, contextVariables: { __blockRef_0: 'context' }, }) ) const [sandboxRequest] = mockExecuteInSandbox.mock.calls.at(-1) ?? [] expect(response.status).toBe(200) expect(sandboxRequest.code).not.toContain(secret) expect(sandboxRequest.code).not.toContain('__var_') expect(sandboxRequest.privateInputs).toHaveLength(1) const payload = JSON.parse(sandboxRequest.privateInputs[0].content) expect(payload.environmentVariables.API_KEY).toBe(secret) expect(payload.params.input).toBe('value') expect(payload.contextVariables).toContainEqual({ name: '__blockRef_0', kind: 'json', value: 'context', }) } ) it('routes quoted shell heredocs through private sandbox input files', async () => { envFlagsMock.isRemoteSandboxEnabled = true const secret = 'shell"\\\n{{OTHER}}' mockExecuteShellInSandbox.mockResolvedValueOnce({ result: null, stdout: `Bearer ${secret}\n$UNRELATED \`touch /tmp/nope\``, sandboxId: 'test-shell-sandbox-id', }) const response = await POST( createMockRequest( 'POST', { code: [ "cat <<'PAYLOAD'", 'Bearer {{API_KEY}}', '$UNRELATED `touch /tmp/nope`', 'PAYLOAD', ].join('\n'), language: 'shell', envVars: { API_KEY: secret, OTHER: 'must-not-resolve' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) const [sandboxRequest] = mockExecuteShellInSandbox.mock.calls.at(-1) ?? [] expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual(['API_KEY']) expect(sandboxRequest.code).not.toContain(secret) expect(sandboxRequest.code).not.toContain('$UNRELATED') expect(sandboxRequest.privateInputs).toHaveLength(1) expect(sandboxRequest.privateInputs[0].content).toContain(secret) expect(sandboxRequest.privateInputs[0].content).toContain('$UNRELATED `touch /tmp/nope`') }) it('does not report a reference when validation rejects before code resolution', async () => { const response = await POST( createMockRequest( 'POST', { code: 'return {{API_KEY}}', envVars: { API_KEY: 'secret-value' }, outputs: { files: Array.from({ length: 21 }, (_, index) => ({ path: `files/output-${index}.json`, sandboxPath: `/home/user/output-${index}.json`, })), }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) const data = await response.json() expect(response.status).toBe(400) expect(data.error).toContain('Too many sandbox output files requested') expect(data.__resolvedSecretNames).toEqual([]) expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled() expect(mockExecuteInSandbox).not.toHaveBeenCalled() }) it('reports exact secret values returned through placeholders without inferring direct environment reads', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'secret-valueother-secret', stdout: '', }) const envResponse = await POST( createMockRequest( 'POST', { code: 'return {{SHARED}} + {{ENV_ONLY}} + {{MISSING}}', params: { SHARED: 'param-value', MISSING: 'ordinary-param' }, envVars: { SHARED: 'secret-value', ENV_ONLY: 'other-secret' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) const envData = await envResponse.json() mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'secret-value', stdout: '' }) const directResponse = await POST( createMockRequest( 'POST', { code: 'return environmentVariables.API_KEY + params.API_KEY', params: { API_KEY: 'ordinary-param' }, envVars: { API_KEY: 'secret-value' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) const directData = await directResponse.json() expect(envData.__resolvedSecretNames).toEqual(['ENV_ONLY', 'SHARED']) expect(directData.output.result).toBe('secret-value') expect(directData.__resolvedSecretNames).toEqual([]) }) it.each([ { name: 'numeric', secret: '123', result: 123 }, { name: 'boolean', secret: 'true', result: true }, ])( 'preserves a typed $name value returned through legacy direct environment access without inferred provenance', async ({ secret, result }) => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result, stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'return environmentVariables.API_KEY', envVars: { API_KEY: secret }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) const data = await response.json() expect(data.output.result).toBe(result) expect(data.__resolvedSecretNames).toEqual([]) } ) it('reports placeholder output without inferring provenance from legacy shell environment access', async () => { envFlagsMock.isRemoteSandboxEnabled = true mockExecuteShellInSandbox.mockResolvedValueOnce({ result: null, stdout: 'secret-value', sandboxId: 'test-shell-sandbox-id', }) const referencedResponse = await POST( createMockRequest( 'POST', { code: 'printf "%s" "{{API_KEY}}"', language: 'shell', envVars: { API_KEY: 'secret-value' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) const referencedData = await referencedResponse.json() mockExecuteShellInSandbox.mockResolvedValueOnce({ result: null, stdout: 'secret-value', sandboxId: 'test-shell-sandbox-id', }) const directResponse = await POST( createMockRequest( 'POST', { code: 'printf "%s" "$API_KEY"', language: 'shell', envVars: { API_KEY: 'secret-value' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) const directData = await directResponse.json() expect(referencedData.__resolvedSecretNames).toEqual(['API_KEY']) expect(directData.output.stdout).toBe('secret-value') expect(directData.__resolvedSecretNames).toEqual([]) }) it('returns nonzero shell stderr as a visible 422 error and diagnostic output', async () => { envFlagsMock.isRemoteSandboxEnabled = true const stderr = "error: unknown flag: --short\nSee 'kubectl version --help' for usage." mockExecuteShellInSandbox.mockResolvedValueOnce({ result: null, stdout: stderr, error: stderr, sandboxId: 'test-shell-sandbox-id', }) const response = await POST( createMockRequest('POST', { code: 'kubectl version --client --short', language: 'shell', }) ) const data = await response.json() expect(response.status).toBe(422) expect(data).toMatchObject({ success: false, error: stderr, output: { result: null, stdout: stderr }, }) }) it('keeps execution available when the scoped catalog exceeds provenance matcher bounds', async () => { const response = await POST( createMockRequest( 'POST', { code: 'return "ok"', envVars: { OVERSIZED_SECRET: 's'.repeat(64 * 1024 + 1) }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual([]) expect(response.headers.get('x-sim-private-tool-metadata')).toBe('resolved-secret-names-v1') expect(mockExecuteInIsolatedVM).toHaveBeenCalled() }) it('reports only substitutions allowed by the Function secret scope', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'allowed-secret', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'return {{ALLOWED}} + {{BLOCKED}}', envVars: { ALLOWED: 'allowed-secret', BLOCKED: 'blocked-secret' }, secretScope: 'selected', mountedSecrets: ['ALLOWED'], }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) expect((await response.json()).__resolvedSecretNames).toEqual(['ALLOWED']) }) it('resolves a selected __proto__ secret as an own environment key', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'secret-value', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'return "{{__proto__}}"', envVars: Object.fromEntries([['__proto__', 'secret-value']]), secretScope: 'selected', mountedSecrets: ['__proto__'], }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1', } ) ) expect(response.status).toBe(200) expect((await response.json()).__resolvedSecretNames).toEqual(['__proto__']) }) it('does not activate a referenced secret that does not cross the Function result', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: 'safe-result', stdout: '' }) const response = await POST( createMockRequest( 'POST', { code: 'const key = {{API_KEY}}; return "safe-result"', envVars: { API_KEY: 'secret-value' }, }, { 'x-sim-request-private-tool-metadata': 'resolved-secret-names-v1' } ) ) expect((await response.json()).__resolvedSecretNames).toEqual([]) }) it.concurrent('should resolve tag variables with syntax', async () => { const req = createMockRequest('POST', { code: 'return ', blockData: { 'block-123': { id: '123', subject: 'Test Email' }, }, blockNameMapping: { email: 'block-123', }, }) const response = await POST(req) expect(response.status).toBe(200) }) it.concurrent('should NOT treat email addresses as template variables', async () => { const req = createMockRequest('POST', { code: 'return "Email sent to user"', params: { email: { from: 'Dr. Shaw ', to: 'User ', }, }, }) const response = await POST(req) expect(response.status).toBe(200) }) it.concurrent('should only match valid variable names in angle brackets', async () => { const req = createMockRequest('POST', { code: 'return + "" + ', blockData: { 'block-1': 'hello', 'block-2': 'world', }, blockNameMapping: { validvar: 'block-1', another_valid: 'block-2', }, }) const response = await POST(req) expect(response.status).toBe(200) }) }) describe('Gmail Email Data Handling', () => { it.concurrent( 'should handle Gmail webhook data with email addresses containing angle brackets', async () => { const emailData = { id: '123', from: 'Dr. Shaw ', to: 'User ', subject: 'Test Email', bodyText: 'Hello world', } const req = createMockRequest('POST', { code: 'return ', blockData: { 'block-email': emailData, }, blockNameMapping: { email: 'block-email', }, }) const response = await POST(req) expect(response.status).toBe(200) const data = await response.json() expect(data.success).toBe(true) } ) it.concurrent( 'should properly serialize complex email objects with special characters', async () => { const emailData = { from: 'Test User ', bodyHtml: '
HTML content with "quotes" and \'apostrophes\'
', bodyText: 'Text with\nnewlines\tand\ttabs', } const req = createMockRequest('POST', { code: 'return ', blockData: { 'block-email': emailData, }, blockNameMapping: { email: 'block-email', }, }) const response = await POST(req) expect(response.status).toBe(200) } ) }) describe('Custom Tools', () => { it.concurrent('should handle custom tool execution with direct parameter access', async () => { const req = createMockRequest('POST', { code: 'return location + " weather is sunny"', params: { location: 'San Francisco', }, isCustomTool: true, }) const response = await POST(req) expect(response.status).toBe(200) }) }) describe('Security and Edge Cases', () => { it.concurrent('should handle malformed JSON in request body', async () => { const req = new NextRequest('http://localhost:3000/api/function/execute', { method: 'POST', body: 'invalid json{', headers: { 'Content-Type': 'application/json' }, }) const response = await POST(req) expect(response.status).toBe(400) }) it.concurrent('should handle timeout parameter', async () => { const req = createMockRequest('POST', { code: 'return "test"', timeout: 10000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(200) expect(data.success).toBe(true) expect(mockExecuteInIsolatedVM).toHaveBeenCalledWith( expect.objectContaining({ timeoutMs: 10000 }), expect.any(Object) ) }) it.concurrent('should handle empty parameters object', async () => { const req = createMockRequest('POST', { code: 'return "no params"', params: {}, }) const response = await POST(req) expect(response.status).toBe(200) }) }) describe('Enhanced Error Handling', () => { it('should provide detailed syntax error with line content', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: '', error: { message: 'Unexpected end of input', name: 'SyntaxError' }, }) const req = createMockRequest('POST', { code: 'const obj = {\n name: "test",\n description: "This has a missing closing quote\n};\nreturn obj;', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toBeTruthy() }) it('should provide detailed runtime error with line and column', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: '', error: { message: "Cannot read properties of null (reading 'someMethod')", name: 'TypeError', }, }) const req = createMockRequest('POST', { code: 'const obj = null;\nreturn obj.someMethod();', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toContain('Type Error') expect(data.error).toContain('Cannot read properties of null') }) it('should handle ReferenceError with enhanced details', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: '', error: { message: 'undefinedVariable is not defined', name: 'ReferenceError' }, }) const req = createMockRequest('POST', { code: 'const x = 42;\nreturn undefinedVariable + x;', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toContain('Reference Error') expect(data.error).toContain('undefinedVariable is not defined') }) it('should show original source code when resolved block references cause syntax errors', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: '', error: { message: 'Unexpected identifier "globalThis"', name: 'SyntaxError', line: 1, column: 7, lineContent: 'retur globalThis["__blockRef_0"]', }, }) const req = createMockRequest('POST', { code: 'retur globalThis["__blockRef_0"]', sourceCode: 'retur ', contextVariables: { __blockRef_0: 'value' }, timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toContain('Line 1: `retur `') expect(data.error).not.toContain('globalThis') expect(data.debug.lineContent).toBe('retur ') }) it('should handle thrown errors gracefully', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: '', error: { message: 'Custom error message', name: 'Error' }, }) const req = createMockRequest('POST', { code: 'throw new Error("Custom error message");', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toContain('Custom error message') }) it('should provide helpful suggestions for common syntax errors', async () => { mockExecuteInIsolatedVM.mockResolvedValueOnce({ result: null, stdout: '', error: { message: 'Unexpected end of input', name: 'SyntaxError' }, }) const req = createMockRequest('POST', { code: 'const obj = {\n name: "test"\n// Missing closing brace', timeout: 5000, }) const response = await POST(req) const data = await response.json() expect(response.status).toBe(422) expect(data.success).toBe(false) expect(data.error).toBeTruthy() }) }) describe('Utility Functions', () => { it.concurrent('should properly escape regex special characters', async () => { const req = createMockRequest('POST', { code: 'return {{special.chars+*?}}', envVars: { 'special.chars+*?': 'escaped-value', }, }) const response = await POST(req) expect(response.status).toBe(200) }) it.concurrent('should handle JSON serialization edge cases', async () => { const complexData = { special: 'chars"with\'quotes', unicode: '🎉 Unicode content', nested: { deep: { value: 'test', }, }, } const req = createMockRequest('POST', { code: 'return ', blockData: { 'block-complex': complexData, }, blockNameMapping: { complexdata: 'block-complex', }, }) const response = await POST(req) expect(response.status).toBe(200) }) }) })