feat: Sandboxed function execution via FUNCTIONS_DRIVER=docker

Each invoke runs in an ephemeral locked-down container — no network,
read-only rootfs, 128MiB/0.5CPU/64-pid caps, non-root, cap-drop ALL.
Source travels as base64 in the container env and materializes in the
tmpfs, so no bind mount is needed (Docker Desktop / remote daemons work).
Timeout force-removes the named container.

exec driver stays the default; the trust-model docs now describe both.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-24 20:45:33 +02:00
1 parent edef002beb
commit 9ae1c22af0
8 files changed
+246 -9

No files matched your search

+12 -2
View File
@@ -48,8 +48,11 @@ type Config struct {
S3Prefix string
S3PathStyle bool
// Functions runtime: binary name/path ("auto" resolves per-function
// runtime from PATH — "bun" or "deno"), timeout and output cap.
// Functions runtime: driver "exec" (runtime binary on the backend host)
// or "docker" (ephemeral locked-down container), binary name/path for
// exec ("auto" resolves per-function runtime from PATH), timeout and
// output cap.
FunctionsDriver string
FunctionsRuntime string
FunctionsTimeout time.Duration
FunctionsMaxBytes int64
@@ -89,6 +92,7 @@ func Load() (Config, error) {
S3SecretAccessKey: os.Getenv("S3_SECRET_ACCESS_KEY"),
S3PublicEndpoint: os.Getenv("S3_PUBLIC_ENDPOINT"),
S3Prefix: os.Getenv("S3_PREFIX"),
FunctionsDriver: getenv("FUNCTIONS_DRIVER", "exec"),
FunctionsRuntime: getenv("FUNCTIONS_RUNTIME", "auto"),
FunctionsMaxBytes: 65536,
}
@@ -135,6 +139,12 @@ func Load() (Config, error) {
}
cfg.FunctionsTimeout = time.Duration(fnTimeout) * time.Second
switch cfg.FunctionsDriver {
case "exec", "docker":
default:
return Config{}, fmt.Errorf("FUNCTIONS_DRIVER %q must be exec or docker", cfg.FunctionsDriver)
}
var missing []string
if cfg.DatabaseURL == "" {
missing = append(missing, "DATABASE_URL")