Files
sim/apps/sim/scripts/build-function-e2b-template.ts
T
Vikhyath MondretiandSiddharth Ganesan 117fe3137b feat(code): cli sandboxes, enterprise timeouts, secrets projections, resolver lift, workflow exec cancellations (#6247)
* feat(code): cli sandboxes, enterprise timeouts, secrets projections, resolver lift

* fix(execution): harden compatibility and secret diagnostics

* fix(execution): harden generated JavaScript literals

* fix(execution): align timeout cleanup semantics

* fix(tables): decouple stale job cleanup

* fix(execution): drain stale workflow backlog

* test(sandbox): make deadline assertions timing-safe

* fix(execution): lock cleanup candidate batches

* fix(execution): preserve cleanup failure metrics

* cancel route fixes

* separate out mship template and func template

* fix

* fix(execution): harden secret projection and block runs

* fix(workflow): validate draft execution state

* run from block ui disabling

* feat(copilot): expose Sim sandboxes to mothership

* feat(copilot): expose sandbox capability catalog in VFS

* Updates

* fix legacy logs showing up

* fix(copilot): keep sandbox config visible

* fix model provenance issues

* fix lint'

* more lint

* more

* test(files): align provenance copy query order

* consolidate migrations, rollout compat

* integration projections

* update skills

* fix

* add provenance linters

* fix: address review and compatibility regressions

* fix: make tool boundary audit Bun 1.3 compatible

---------

Co-authored-by: Siddharth Ganesan <siddharthganesan@gmail.com>
2026-08-05 19:22:04 -07:00

115 lines
4.3 KiB
TypeScript

#!/usr/bin/env bun
/**
* Builds the dedicated E2B base used by Function JavaScript, Python, Shell, and
* content-addressed workspace sandbox layers.
*
* Usage:
* `E2B_API_KEY=... bun run apps/sim/scripts/build-function-e2b-template.ts [--name <name>] [--generation <monotonic-release-number>] [--base-template <name:build-id>] [--no-cache]`
*
* Configure the resulting exact build ref as `E2B_FUNCTION_TEMPLATE_ID`. There is
* intentionally no fallback to `MOTHERSHIP_E2B_TEMPLATE_ID`: the two images have
* independent owners and release cadences.
*
* Revisioned materializer tasks deploy alongside legacy and previous-revision
* bridges. Trigger.dev keeps a run waiting when its new task ID has not deployed
* yet, so either promotion order preserves the registry claim.
*/
import { defaultBuildLogger, Template, waitForTimeout } from '@e2b/code-interpreter'
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { immutableE2BTemplateRef, isValidE2BTemplateName } from '@sim/utils/sandbox-references'
import {
FUNCTION_SANDBOX_CPU_COUNT,
FUNCTION_SANDBOX_MEMORY_MB,
} from '@/lib/execution/remote-sandbox/function-resources'
import {
functionE2BBaseTemplate,
functionE2BReleaseGeneration,
} from '@/scripts/function-e2b-release'
import {
FUNCTION_APT_PACKAGES,
FUNCTION_COMMAND_ALIASES_ASSERT,
FUNCTION_COMMAND_ALIASES_SETUP,
FUNCTION_COMMANDS_ASSERT,
FUNCTION_E2B_PYTHON_PACKAGES,
FUNCTION_NODE_VERSION_ASSERT,
FUNCTION_NPM_CLI_PACKAGES,
FUNCTION_NPM_CLI_VERSIONS_ASSERT,
FUNCTION_PIP_CLI_PACKAGES,
FUNCTION_PIP_CLI_VERSIONS_ASSERT,
FUNCTION_PYTHON_IMPORTS_ASSERT,
FUNCTION_PYTHON_VERSION_ASSERT,
} from '@/scripts/function-sandbox-packages'
const logger = createLogger('BuildFunctionE2BTemplate')
const DEFAULT_TEMPLATE_NAME = 'sim-function'
const START_COMMAND = 'sleep infinity'
async function main(): Promise<void> {
if (!process.env.E2B_API_KEY) {
throw new Error('E2B_API_KEY is required')
}
const args = process.argv.slice(2)
const baseTemplate = functionE2BBaseTemplate(args)
const nameIndex = args.indexOf('--name')
const templateName = nameIndex !== -1 ? args[nameIndex + 1] : DEFAULT_TEMPLATE_NAME
if (!templateName) throw new Error('--name requires a template name')
if (!isValidE2BTemplateName(templateName)) {
throw new Error('--name must be an untagged E2B template name')
}
const releaseGeneration = functionE2BReleaseGeneration(
args,
process.env.E2B_FUNCTION_TEMPLATE_GENERATION
)
const skipCache = args.includes('--no-cache')
const functionTemplate = Template()
.fromTemplate(baseTemplate)
.aptInstall([...FUNCTION_APT_PACKAGES])
.pipInstall([...FUNCTION_E2B_PYTHON_PACKAGES, ...FUNCTION_PIP_CLI_PACKAGES])
.npmInstall([...FUNCTION_NPM_CLI_PACKAGES], { g: true })
.runCmd(FUNCTION_COMMAND_ALIASES_SETUP, { user: 'root' })
.runCmd(FUNCTION_NODE_VERSION_ASSERT, { user: 'root' })
.runCmd(FUNCTION_PYTHON_VERSION_ASSERT, { user: 'root' })
.runCmd(FUNCTION_COMMANDS_ASSERT, { user: 'root' })
.runCmd(FUNCTION_COMMAND_ALIASES_ASSERT, { user: 'root' })
.runCmd(FUNCTION_PIP_CLI_VERSIONS_ASSERT, { user: 'root' })
.runCmd(FUNCTION_NPM_CLI_VERSIONS_ASSERT, { user: 'root' })
.runCmd(FUNCTION_PYTHON_IMPORTS_ASSERT, { user: 'root' })
.setStartCmd(START_COMMAND, waitForTimeout(1_000))
logger.info('Building Function E2B template', {
templateName,
baseTemplate,
cpuCount: FUNCTION_SANDBOX_CPU_COUNT,
memoryMB: FUNCTION_SANDBOX_MEMORY_MB,
releaseGeneration,
skipCache,
})
const result = await Template.build(functionTemplate, templateName, {
cpuCount: FUNCTION_SANDBOX_CPU_COUNT,
memoryMB: FUNCTION_SANDBOX_MEMORY_MB,
onBuildLogs: defaultBuildLogger(),
...(skipCache ? { skipCache: true } : {}),
})
const immutableRef = immutableE2BTemplateRef(result.name, result.buildId)
logger.info('Built Function E2B template', {
templateName,
templateId: result.templateId,
buildId: result.buildId,
configuration: `E2B_FUNCTION_TEMPLATE_ID=${immutableRef}`,
releaseGeneration,
generationConfiguration: `E2B_FUNCTION_TEMPLATE_GENERATION=${releaseGeneration}`,
})
}
main().catch((error: unknown) => {
logger.error('Function E2B template build failed', { error: getErrorMessage(error) })
process.exitCode = 1
})