Sandbox
How go-faas isolates multi-language user code on Linux and macOS.
Platform Strategy
| Platform | Entry command | Isolation |
|---|---|---|
| Linux | systemd-run + bwrap |
User slice resource caps + Bubblewrap namespaces |
| darwin | sandbox-exec |
Seatbelt profile (dev-oriented) |
Production hardening targets Linux. macOS support exists so the API can be developed on Apple hosts.
Linux: systemd Slice
On startup, sandbox.NewSlice() writes ~/.config/systemd/user/go-faas-slice and reloads user systemd:
| Setting | Source | Default |
|---|---|---|
CPUQuota |
MAX_CPUS * 100 percent |
100% (1 core) |
MemoryMax |
MAX_MEMORY |
128M |
MemorySwapMax |
fixed | 0 |
Each run uses systemd-run --scope --user --quiet --slice=go-faas-slice -- bwrap ....
Linux: Bubblewrap
SandboxCommand (linux build) assembles bwrap flags including:
- Read-only binds for
/usr,/lib,/lib64 - Read-only bind of the language wrapper into
/wrapper.{py,js,ts} --tmpfs /tmp,--proc,--dev--unshare-all,--unshare-net(no host network)--cap-drop ALL,--die-with-parent,--new-session- Clean
HOME/PATH/TMPDIR/LANG; unsetLD_PRELOAD/LD_LIBRARY_PATH - TypeScript: additional ro-bind of working directory and
NODE_PATHtonode_modules
Python runs as python3 -u /wrapper.py; JS/TS as node|tsx /wrapper.*.
macOS: sandbox-exec
Darwin build generates a seatbelt profile that:
- Denies by default
- Allows process exec/fork, limited sysctl/mach/signal/IPC
- Allows broad file-read; write only under
$HOME - Allows network (looser than Linux bwrap — development trade-off)
NewSlice() is a no-op on darwin.
Process I/O Contract
Regardless of platform, the child process:
- Reads one JSON payload on stdin:
code+inputstrings - Writes intermediate logs and final JSON result on stdout
- Writes failures on stderr (SSE path treats stderr as fatal)
Handlers own timeouts via context.WithTimeout around exec.CommandContext.
Dependency Checker
Linux checker.CheckPackage() may install bubblewrap, nodejs, npm, and python3 through apt/dnf/pacman/apk when Node, TypeScript (tsc), esbuild, or Python are missing. Darwin checker is a no-op.