# 沙箱

HakoRun 每次執行都把 runtime 包進作業系統原生的沙箱：Linux 用 Bubblewrap，macOS 用 seatbelt。

## Linux：systemd-run + bwrap

指令由 `internal/sandbox/command_linux.go` 組成：`systemd-run --scope --user --quiet --slice=hakorun.slice -- bwrap ... -- <runtime> /wrapper.<ext>`。

| 面向 | 設定 |
|------|------|
| 命名空間 | `--unshare-all`、`--unshare-net`（無網路） |
| 權限 | `--cap-drop ALL`、`--new-session`、`--die-with-parent` |
| 檔案系統 | 唯讀掛載 `/usr`、`/lib`、`/lib64` 與 wrapper；`/tmp`、`/home/sandbox` 為 tmpfs；`/proc`、`/dev` 為新實例 |
| 工作目錄 | `/tmp` |
| 環境變數 | `HOME=/home/sandbox`、`PATH=/usr/local/bin:/usr/bin:/bin`、`TMPDIR=/tmp`、`LANG=C.UTF-8`；移除 `LD_PRELOAD`、`LD_LIBRARY_PATH` |
| TypeScript 額外 | 唯讀掛載專案根目錄，`NODE_PATH` 指向其 `node_modules` |

因為只掛載 `/usr`，全域 `tsx` 必須安裝在 `/usr` 底下（npm 預設 prefix `/usr/local` 即可）；系統缺 `/lib64` 時 `bwrap` 無法啟動。

## macOS：sandbox-exec

指令為 `sandbox-exec -p <profile> <runtime> <wrapper>`，profile 由 `seatbeltProfile()` 產生：

```scheme
(version 1)
(deny default)
(allow process-exec)
(allow process-fork)
(allow sysctl-read)
(allow mach-lookup)
(allow signal)
(allow ipc-posix*)
(allow file-read*)
(allow file-write* (subpath "<HOME>"))
(allow network*)
```

## 兩平台對照

| 面向 | Linux | macOS |
|------|-------|-------|
| 網路 | 停用 | 允許 |
| 寫入 | 僅 tmpfs | 僅 `$HOME` |
| 讀取 | 僅掛載路徑 | 全域 |
| 資源上限 | `hakorun.slice` | 無 |
| 環境變數 | 重設 | 繼承伺服器 |

macOS 沙箱的邊界明顯較寬，適合開發；對外提供服務請部署在 Linux。

## 相關頁面

- [資源上限](/zh/resource-limits)
- [腳本執行環境](/zh/script-runtime)
