Files
platform/docs
pastilhasandClaude Opus 5 ea0d2396f7 linux accounts use the chosen username, and refuse to take one over
Two changes, and the second is what makes the first safe.

The officer_ prefix is gone: a member's account is the username the owner typed, so
whoami says who they are and a commit from their checkout is attributed to something
recognisable. Measured first — useradd on this host accepts everything
validateUsername permits, including dots, hyphens, underscores and uppercase.

The prefix was also load-bearing, though, and not for looks. ensureOsUser REUSES an
existing account, which is what makes it re-runnable, and that was safe by
construction while only we created officer_* names. Unprefixed, adoption becomes the
dangerous path: a platform account named root would have found root in passwd, and
every runAs for that member would have been a root shell. So adoption now requires
the existing account's passwd home to be exactly the home we are about to confine —
that is what makes it ours — and any uid below 1000 is refused outright.

Verified: root and daemon refused as system accounts, and the owner's own username
refused by name with its real home quoted back.

Also, the ancestor trap from the first real install. A member's home is under
DATA_PATH, which is under the OWNER'S home, and /home/<owner> is 750 on Debian and
Ubuntu — so every mode bit on the account tree was right, the directory existed, and
the member still could not reach it for want of x four levels up. It surfaced as
"ssh-keygen: Could not stat …/.ssh: Permission denied", which points at the wrong
thing entirely. firstUntraversableAncestor now walks the chain as the member before
anything uses the home, and the error names the directory and the chmod.

The dev machine was already 751, and the probe used /tmp, so it never crossed the
ancestor that mattered. Worth remembering as a shape of mistake.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 17:46:01 +00:00
..