left4me/docs/superpowers/specs/2026-05-15-session-handoff.md
mwiegand 2834ad4911
deploy: move scripts/{libexec,sbin}/ into deploy/scripts/
Layout consistency: everything ckn-bw deploys to the host now lives
under deploy/. ckn-bw's install_left4me_scripts copy-action goes away
in lockstep with this commit and is replaced by target-side symlinks.

Also updates all path references in docs, tests (conftest.py parents[]
depth, test_overlay_helper.py HELPER_SOURCE), and deploy/README.md.

Part of 2026-05-15-deployment-responsibility-design.md migration step 4.
2026-05-15 19:38:42 +02:00

5.6 KiB

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-sandboxUser=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.
  4. Remove l4d2-sandbox from ~/Projekte/ckn-bw/bundles/left4me/items.py (users + groups dicts). Tighten /var/lib/left4me mode from 07110755.
  5. 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.
  6. Push both repos; bw apply ovh.left4me.
  7. 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