to-be 29: a node has operator accounts, and the mesh owns what lives under a home
The mesh models machines but not the people on them — a node record holds no username, and no module places anything under a home. So who you are on each node (jochens/ace/jochen) is unknown to the mesh, and nothing owns ~/.ssh, dotfiles or ~/.config. HAL knew it; the nox mesh dropped it. Proposes the account as a node fact and a home-scoped resource class (the ~/ mirror of ADR 0112's /var/lib placement), with the login key staying the operator's (ADR 0051). Not urgent — HAL's generators still run — load-bearing at node-by-node retirement. Found generating ~/.ssh/config from HAL's registry, which nox has no equivalent for.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
---
|
||||
layer: to-be
|
||||
status: proposed
|
||||
code: []
|
||||
updated: 2026-09-27
|
||||
decisions:
|
||||
- 02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md
|
||||
- 02-DECISIONS/0051-shared-data-is-the-operators.md
|
||||
---
|
||||
|
||||
# 29 — A node has operator accounts, and the mesh owns what lives under a home
|
||||
|
||||
**The mesh models machines but not the people on them.** A node record holds its name, its
|
||||
address, its mode — and nothing about *who a person is* on it: `jochens` on novox, `ace` on ace,
|
||||
`jochen` on shanks and g14. That username is not incidental. It decides who a file under `~` is
|
||||
owned by, who a user service runs as, and — the case that surfaced this — which account `ssh
|
||||
<node>` logs in as. The predecessor knew it (its per-node `user:`, and the modules that wrote a
|
||||
person's `~/.ssh/config`, `~/.zshrc`, `~/.config`); the mesh, taking those over, kept the machine
|
||||
facts and dropped the human one.
|
||||
|
||||
Two things are missing, and they are one idea:
|
||||
|
||||
## 1. The account is a node fact
|
||||
|
||||
A node has one or more **operator accounts**: the human logins on it. At minimum a name; the
|
||||
mesh already knows the node and its address, so `<account>@<node>` is then a complete answer to
|
||||
"who am I, where." It is the mesh's to hold because everything below is derived from it, and
|
||||
because it is exactly the fact that was silently lost — `ssh ace` failed to `ace` because nothing
|
||||
in the mesh said ace's account is `ace`.
|
||||
|
||||
It is **not** a credential. The account names a login; the key that authorises it is the
|
||||
operator's, placed as a secret or an operator-owned file, never minted by the mesh (ADR 0051).
|
||||
|
||||
## 2. A resource may live under a home, owned by its account
|
||||
|
||||
[ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md) placed a
|
||||
module's *system* data — `<root>/<module>`, owned by the module. It has no analog for the other
|
||||
half of the filesystem: the things that belong under a person's home and are owned by that
|
||||
person. `~/.ssh/config`, `~/.ssh/config.d/mesh`, `~/.zshrc`, `~/.config/hal` — every one of these
|
||||
is a resource the mesh should be able to place and own, resolved against **the account's home**
|
||||
rather than a system root, and chowned to **the account** rather than to root or a module uid.
|
||||
|
||||
This is the same move as `${dir:…}`, one level over: a resource says `home: <account>` (or names
|
||||
an account requirement), and the mesh resolves the home directory and the owning uid on the node
|
||||
that account lives on. A module that writes operator config — the eventual replacements for
|
||||
`hal/terminal`, `hal/claude-code`, `hal/secrets` — declares its files this way and names no
|
||||
`/home/...` path, exactly as a system module now names no `/var/lib` path.
|
||||
|
||||
## Why now, and why not yet
|
||||
|
||||
**Why it matters:** when HAL retires, the generators that keep `~/.ssh/config`, shell config and
|
||||
the operator's `~/.config/hal` current retire with it. Without this, adding a node stops adding
|
||||
its ssh alias, and a fresh machine has no operator dotfiles at all — the mesh would run every
|
||||
service and leave the human unable to work on the box. The account is also load-bearing for
|
||||
correctness already: `ssh <node>` (issue 122's cousin), user-scoped systemd units, and any file a
|
||||
person rather than a daemon must own.
|
||||
|
||||
**Why not build it reflexively:** it is a real addition to the node model and the resource model,
|
||||
and it must be gotten right, not smuggled in beside a firewall fix. Open questions to settle
|
||||
first:
|
||||
|
||||
- **One account or several per node?** A workstation has one human; a shared box might have more.
|
||||
The model should allow more than one without forcing the common case to name it.
|
||||
- **Where the login key lives.** An operator-owned file (ADR 0051) or an accepted secret — never
|
||||
minted. The account fact and the key that authorises it are separate, and only the first is the
|
||||
mesh's to generate.
|
||||
- **The boundary with `sshd`.** The `sshd` module (server side) already exists. This is the
|
||||
*client* and *identity* side: the account a node offers, and the home-scoped files an operator
|
||||
needs. They meet at the account but are not the same module.
|
||||
- **Multi-operator.** Today there is one human. The model should not assume it, but the first
|
||||
cut may serve one and leave the shape open.
|
||||
|
||||
**Not urgent, not blocking.** ssh and dotfiles work today because HAL's generators still run as
|
||||
the substrate. This becomes load-bearing in the node-by-node retirement phase, not before — which
|
||||
is the right time to build it, once the account model is decided here.
|
||||
|
||||
## References
|
||||
|
||||
- The gap was found generating `~/.ssh/config` from the *HAL* registry (`hal/terminal`'s
|
||||
postConfigure hook), which the nox mesh has no equivalent for.
|
||||
- [ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md) — the
|
||||
system-path placement this mirrors for home paths.
|
||||
- [ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md) — why the login key stays
|
||||
the operator's, never minted.
|
||||
Reference in New Issue
Block a user