# 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 `deploy/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-<id>`
  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`
