Features: state the honest boundary a member runs inside (#184)
Several settings on this page look like security controls. They are not, and the reason is the same for all of them: a member runs as the same OS user as the lead. That fact was written nowhere an operator reads, so people read the settings and concluded a member was contained. Adds one entry giving the per-channel truth, the proven path a member takes to the operator's ssh key, and the point that no meaningful boundary exists inside one uid. Names the recurring shape: a gate written after an incident closes only the direction that incident came from.
+38
@@ -3113,6 +3113,44 @@ describes the wrong account and only the configured `memberLoginShell:` is read.
|
||||
`memberHerdrSocket` and leave `memberLoginShell` unset, the shell reads as `<unset>`, counts as
|
||||
non-zsh, and **every spawn is refused**. The refusal message says so, but it is cheaper to know first.
|
||||
|
||||
## What a member can actually reach — the honest boundary
|
||||
|
||||
**What.** This is not a feature. It is the frame every credential setting on this page sits inside,
|
||||
and it has been missing, so people have read those settings and concluded more than the settings say.
|
||||
|
||||
**A member runs as the same OS user as the lead. That is a trust model, not a sandbox.** Inside one
|
||||
uid, ordinary Unix file permissions give no confidentiality boundary. A member that can run commands
|
||||
can read any file this user can read.
|
||||
|
||||
What each control actually does:
|
||||
|
||||
| Channel | Control today | What it really buys |
|
||||
|---|---|---|
|
||||
| Environment | `memberCredentials` + the `ZDOTDIR` scrub | **Real**, for what the member *inherits*. It does not protect the values — the member can source the same files again. |
|
||||
| Files | worktree provisioning neutralizes some config files | **Not a boundary.** File modes do not separate processes with the same uid. A member can read the original by absolute path. |
|
||||
| Sockets | `sshAuthSock: block` | **Not a boundary.** It omits one variable. It does not revoke access to the socket, and it cannot remove a readable key file. |
|
||||
| Git config | the worktree's HTTPS rewrite + cleared `credential.helper` | **Routing, not enforcement.** Normal git commands go the intended way; a member can still call `ssh` directly. |
|
||||
| Process table | secrets kept out of argv | **No boundary.** argv is visible to any local user, and a different uid would not fix that. |
|
||||
|
||||
**Why it exists.** The proven path is short: the scrub blanks `SSH_AUTH_SOCK` → git starts ssh → ssh
|
||||
reads the user's config → it opens an `IdentityFile` that is readable and has no passphrase → the
|
||||
forge accepts the operator's key. Measured on 2026-08-28: a member with the socket blanked pushed
|
||||
successfully. The gate closes lead → child environment inheritance. It never closed member →
|
||||
filesystem → credential.
|
||||
|
||||
That is worth naming as a shape, because it keeps recurring here: **a gate written after an incident
|
||||
closes only the direction that incident came from.** Ask which states open it, not just which it
|
||||
blocked.
|
||||
|
||||
**The gotcha: no meaningful boundary exists inside one uid.** Environment scrubbing, worktrees and
|
||||
config rewrites reduce **accidents**, and that is worth having. They do not contain a member that
|
||||
chooses to look. A real boundary needs a different OS user (`memberHerdrSocket`, above) or OS-level
|
||||
confinement such as a container or VM — a different execution model, not a longer name list. Even a
|
||||
different user does not protect argv, and does not protect shared git objects where `worktreeGroup`
|
||||
grants access to them.
|
||||
|
||||
Open work, ranked, is on #184.
|
||||
|
||||
## `leadSeats` reports the seat the lead itself holds
|
||||
|
||||
**What.** For a `subscription: true` profile, `fleet_list`'s row carries a `leadSeats` field when the
|
||||
|
||||
Reference in New Issue
Block a user