# Session handoff — next: execute uid-collapse plan The hardening refactor landed and was verified on `left4.me` earlier in this session day. A follow-up question surfaced — the two-user model (`left4me` + `l4d2-sandbox`) is inconsistent now that systemd hardening covers the same-uid attack surface. The asymmetry was hashed out and **Option C** (collapse to one user) chosen. A plan was written but **not executed**. The next session picks it up. ## What just landed (committed + pushed earlier today) The hardening refactor — full directive composition deployed to `left4.me`. server@1 went 7.5 → 1.3 systemd-analyze; web 8.7 → 4.1; all Test 8 attack vectors blocked. See the prior session-handoff content in this file's git history (`git log --oneline -- this-file`) and the close-out commits. ## What's next: execute `2026-05-15-uid-collapse.md` Plan: `docs/superpowers/plans/2026-05-15-uid-collapse.md`. Approved in plan-mode this session; not executed. Scope (10 steps; see plan for detail): 1. Strip the idmap block from `scripts/libexec/left4me-script-sandbox` (~30 lines deleted), change `User=l4d2-sandbox` → `User=left4me`, `BindPaths="${STAGING}:/overlay"` → `BindPaths="${OVERLAY_DIR}:/overlay"`. Keep the `nsenter` self-wrap (it's about namespace escape, not uid — unaffected). 2. Update `scripts/tests/test_script_sandbox.py` — assertion changes + delete the `test_script_sandbox_uses_idmap_staging` test. 3. Update two inline comments referencing `l4d2-sandbox`. 4-6. Doc updates: mark `2026-05-15-build-time-idmap.md` and `2026-05-14-overlay-idmap.md` superseded; revise the user-uid-split superseded header to say "1 user" instead of "2"; one-line notes in the hardening specs. 7. Remove `l4d2-sandbox` from `~/Projekte/ckn-bw/bundles/left4me/items.py` (users + groups dicts). Tighten `/var/lib/left4me` mode from `0711` → `0755`. 8. **On-host pre-flight**: `ssh left4.me` + `sudo find -uid 981`, chown any stragglers to `left4me` BEFORE applying. ckn-bw won't remove a user whose files (or processes) are still on disk gracefully. 9. Push both repos; `bw apply ovh.left4me`. 10. Verify: `getent passwd l4d2-sandbox` empty, no uid-981 files, sandbox build runs as left4me end-to-end via the web UI. Rollback path documented in the plan (git revert + bw apply recreates the user). ## Why we're doing this The two-user setup was the inconsistent middle ground: - Server + web run as `left4me` because hardening covers the threat — uid split would be 1-2 days of cross-repo migration for marginal kernel-enforcement benefit. - Sandbox runs as `l4d2-sandbox` for historical reasons — the build-time-idmap design baked it in. The hardening composition on the sandbox unit (which the script-sandbox helper applies via `systemd-run -p ...`) already gives the same protection profile as the gameserver unit. The separate uid is defense-in-depth only. Picking one principle: - **C** (collapse to one): cheap, deletes ~30 lines of helper code, removes the build-time-idmap concern entirely. Architecture simpler. Consistent with the web/server hardening-only decision. - A (status quo): inconsistent. Documented but not principled. - B (split fully): 1-2 days of work; we already rejected this for server/web. Operator picked C. ## Decision-relevant context already on the host - After the hardening refactor + bw apply earlier, `left4me-server@*` and `left4me-web` are running with the full hardening profile. `kernel.yama.ptrace_scope=2` is set system-wide via the bundle. - The sandbox unit is currently inactive (it's transient — only exists during a build). Per the build-time-idmap plan, the staging path lives at `/var/lib/left4me/tmp/sandbox-idmap-` during a build. - ckn-bw's `users` bundle handles the removal mechanically; no custom dance needed beyond the pre-flight chown. ## Open questions to clarify with the operator before/during execution - Whether to expand the pre-flight `find -uid 981` from `/var/lib/left4me` + `/opt/left4me` to all of `/` for paranoia. Probably not needed; flag for the implementer's judgement. - Whether to combine left4me + ckn-bw into a single PR-equivalent cross-repo commit pair, or push left4me first then ckn-bw. Plan assumes both pushed before `bw apply`. ## What's NOT next - **`build-overlay-unit` refactor** (`docs/superpowers/specs/2026-05-15-build-overlay-unit-design.md`). Sequenced after this; will inherit `User=left4me` cleanly. - **Broader configmgmt responsibility reshape** (drop-ins owned by left4me, ckn-bw as thin file-shipper). Framed as a brainstorming session at `docs/superpowers/specs/2026-05-15-handoff-deployment-responsibility.md`; sequenced after uid-collapse lands. - **Stale RCON port app bug** flagged in the earlier executor's handoff. Separate scope. - Renaming `left4me` to anything else. Cosmetic. ## Pointers - The plan to execute: `docs/superpowers/plans/2026-05-15-uid-collapse.md` - Hardening refactor that just landed: `docs/superpowers/plans/2026-05-15-hardening-refactor.md` - Hardening threat model + defenses survey + test plan (commit `461b8d0` recorded the test results inline): `docs/superpowers/specs/2026-05-15-hardening-{threat-model,defenses-survey,test-plan}.md` - Build-time-idmap plan (about to be marked superseded): `docs/superpowers/plans/2026-05-15-build-time-idmap.md` - uid-split spec (also affected — answer revises from "stay at 2" to "collapse to 1"): `docs/superpowers/specs/2026-05-15-user-uid-split-design.md` - Live source for unit emission: `~/Projekte/ckn-bw/bundles/left4me/metadata.py` - Live source for users/groups: `~/Projekte/ckn-bw/bundles/left4me/items.py`