fix(worker): keep-id compat, zombie tmux clients, nvm in box image
- Box init + chownInBox exec explicitly as root: under podman keep-id the container's default user is the mapped uid, which cannot useradd/chown. - Init renames an existing uid-1000 passwd entry (podman keep-id injects one named after the HOST user) instead of adding a duplicate that would win the getpwuid lookup and make whoami report the wrong name. - Terminal connections tag their shell with a per-connection marker and reap the process group on WebSocket close: closing the attach socket never killed the exec'd shell, so every disconnect leaked an attached tmux client (session stuck at the smallest zombie's size; enough dead clients starve tmux rendering for live ones). - Job image: nvm 0.39.5 at /usr/local/nvm (user-writable) with /etc/profile.d/nvm.sh, matching what user dotfiles expect; docs for the box user + ownership model.
This commit is contained in:
@@ -108,6 +108,31 @@ Docker mode. Prod (Docker socket mounted) works as-is.
|
||||
is intended for the single-user self-hosted deployment; do not expose the
|
||||
worker domain without TLS, and keep the deployment single-tenant.
|
||||
|
||||
## The box user
|
||||
|
||||
Terminals and agent turns run as a named non-root user (uid 1000), not root —
|
||||
Claude Code refuses some operations as root, and a real machine has a named
|
||||
account. The Linux username mirrors your Spoon username (lowercased/sanitized;
|
||||
the passwd entry may differ from the home folder name), the hostname is
|
||||
`<user>-box`, and the account is in `wheel`.
|
||||
|
||||
**sudo & password:** with no password set, sudo works without prompting (a
|
||||
NOPASSWD drop-in at `/etc/sudoers.d/spoon-box`). Set a password from the
|
||||
**/machine → Box user** card: it is stored encrypted in Convex, applied live to
|
||||
a running box (`chpasswd` over stdin via `POST /box/set-password`), and
|
||||
re-applied at every box creation — at which point the NOPASSWD drop-in is
|
||||
removed and wheel membership makes sudo prompt. Clearing the password reverts
|
||||
to passwordless sudo. Passwords are 8-128 chars and write-only (the UI only
|
||||
ever learns whether one is set).
|
||||
|
||||
**File ownership:** the worker writes into homes from the host (clones,
|
||||
dotfiles, the file editor). Under dev rootless podman the box runs with
|
||||
`--userns=keep-id:uid=1000,gid=1000` so the host user IS the box user and
|
||||
ownership just works (`SPOON_AGENT_BOX_USERNS` overrides; empty disables).
|
||||
Under prod rootful docker the worker repairs ownership with targeted
|
||||
`chown -R 1000:1000` execs after each host-side write, plus a one-time
|
||||
marker-guarded (`~/.spoon/chown-v1`) home chown at first box creation.
|
||||
|
||||
## Tools in the shell
|
||||
|
||||
The box image ships `bash`, `tmux`, `neovim`, `git`, `ripgrep`, `jq`, `python3`,
|
||||
|
||||
Reference in New Issue
Block a user