- Status: Proposed; empty-host + FS/exec/network denial + host-side UDS EOF
exit + cgroup attach/OOM classification + framed host dispatch (
sys.ping,sys.execmock) + TUI debug HostSession + sandboxed Luau runtime smoke implemented; plugin loading and the capability API remain pending - Date: 2026-10-31
- Related: ADR-0001, ADR-0002, ADR-0007, ADR-0011
The editor must never execute plugin code in-process. A plugin host needs its own process, kernel sandbox, capability token, and clean lifecycle. The Go gateway policy-checks requests but is not the plugin sandbox.
0.1.1 starts with this boundary. No plugin runtime is exposed until all acceptance checks below pass.
- One host process per plugin; no host serves multiple plugins.
- The host is in a new process group/session and is not a child of the gateway.
- The editor owns the host lifecycle and never loads plugin code.
- Host crash, timeout, or sandbox setup failure disables that plugin only.
- No fallback to an unsandboxed process.
Applied before plugin VM initialization:
no_new_privs.- Landlock: read-only runtime files needed by the VM; workspace access only for granted paths. Landlock network rules are used only on kernels that support them (>= 6.7); on 5.13-6.6 network denial is a seccomp responsibility, not a Landlock claim.
- seccomp: checks
seccomp_data.archagainst the native ABI;socket/socketpairallow onlyAF_UNIX; other domains returnEPERM, so TCP/UDP cannot be created. Non-native ABIs and x32 (nr & 0x4000_0000) are rejected. UDS stream operations remain allowed. Broader namespace/mount/ptrace filtering is pending. - Landlock handles
EXECUTE; no path is granted execute after startup. - RLIMIT/cgroup pids, memory, fds, and output caps. cgroup setup verifies the cgroup2 superblock and opens existing control files without creating them.
- The host starts with a minimal environment; no inherited editor/gateway FDs.
- Editor generates a fresh 32-byte token per host.
- Editor registers
(plugin_id, sha256(token), workspace, grants)with the gateway before spawn. - Token is delivered through a dedicated inherited pipe/FD, never argv, env, or a world-readable file.
- The host reads and closes the FD before plugin code loads.
- Gateway token is one-shot and bound to the first successful handshake.
- A host cannot reuse another plugin's token; token hash and peer credentials are both checked.
editor.sockandgateway.socklive in a private per-session runtime directory with mode0700; socket mode0600.- The host connects only after sandbox setup; editor and gateway verify
SO_PEERCRED. - Malformed frame, stale token, or wrong peer closes the connection and disables the plugin.
Start:
- Validate manifest and grants.
- Register token hash with gateway.
- Spawn host in a new process group.
- Pass token FD.
- Host applies sandbox, connects, handshakes.
- Any failure: kill group, revoke token, delete runtime state.
Stop/reload:
- Stop accepting plugin requests.
- Cancel in-flight work.
- Send EOF, wait with timeout, kill process group if needed.
- Revoke token and delete host runtime state.
- Start a new host with a new token if requested.
- Outside-workspace read/write is denied.
- Symlink and
..escape are denied. - Network, mount, namespace, ptrace, and unallowlisted exec are denied.
- Plugin cannot read editor/gateway token or reuse another plugin's token.
- Host cannot inherit gateway/editor FDs.
- Plugin crash does not terminate editor, gateway, or other plugins.
- Reload leaves no orphan process, socket, cgroup, or token.
- Sandbox setup failure never starts plugin code.
Positive:
- Plugin compromise is contained by process + kernel + capability boundaries.
- Gateway remains a policy point, not a false sandbox claim.
Negative:
- One process per plugin increases memory/startup cost.
- Lua/QuickJS runtime files must be packaged read-only.
- Reload requires explicit token revocation and process-group cleanup.
- First runtime: Lua or QuickJS (must not add ambient native modules).
- Whether the host is Rust-native or embeds an existing VM.
- Exact editor.sock
editor.*schema remains a separate API decision.