left4me/docs/superpowers/specs/2026-05-15-session-handoff.md
mwiegand 9a2ab974e6
spec: session handoff pointing next session at uid-split
Short companion to the existing topic-specific handoff docs. Captures
the situationally-fresh state at the end of the 2026-05-15
deploy-dir-rethink + janitorial sweep so a fresh session can pick
up cold: what just landed, what's next (uid-split), what's NOT next
(build-overlay-unit, until uid-split decides), and the
decision-relevant signals that emerged during this session — mostly
that the 2-uid model was freshly load-bearing in the build-time-idmap
work and that srcds hardening already covers most of what a
gameserver-uid split would add.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 12:17:55 +02:00

5.1 KiB

Session handoff — next: uid-split decision

Short handoff for the session that follows the 2026-05-15 deploy-dir rethink + janitorial sweep. The full project context is in CLAUDE.md and the per-topic specs/plans linked below; this doc covers only what's situationally fresh.

What just landed

Four commits since e38b844, pushed to origin/master:

  • 5284e28 — privileged helpers moved out of deploy/files/usr/local/{libexec,sbin}/ into top-level scripts/{libexec,sbin}/. deploy/ is now reference material (README + example configs + curated example units). Dead static artifacts deleted: left4me-apply-cake, left4me-cake.service, left4me-nft-mark.service, cake.env, left4me-mark.nft, the superseded deploy-test-server.sh.
  • 160911f — plan landed at docs/superpowers/plans/2026-05-15-deploy-dir-rethink.md; adjacent specs marked resolved.
  • 8f30dd7 — janitorial item 6 (bubblewrap doc-drift) corrected.
  • 4aa69c2 — janitorial items 8 and 9 verified on ovh.left4me (141.95.32.8) and marked resolved.

Companion change in ckn-bw is committed (91b7265) but not yet pushed. Verified against the test host via bw apply ovh.left4me; the working-tree-as-applied was committed afterwards. Pushing it is safe and idempotent (deployed bytes already match).

Janitorial spec status: items 1, 2 (partial), 3, 4, 5, 6, 8, 9 closed. Items 7 and 10 remain (item 7 is conditional on the build-overlay-unit refactor; item 10 is a calendar reminder for SM 1.13 in late 2026).

What's next: uid-split

Existing handoff: docs/superpowers/specs/2026-05-15-user-uid-split-design.md. Read that first. The decision is whether left4me should have 1, 2, or 3 system users; today it has 2 (left4me + l4d2-sandbox).

This is a decision task, not a migration. Likely outcome: settle the question with a short plan and either a memory entry / spec resolution (if status quo wins) or a follow-up implementation plan (if "split to 3" or "collapse to 1" wins). Time-box the decision to one session; defer any migration work to a follow-up plan.

Decision-relevant context that emerged this session

  • The 2-uid model is freshly load-bearing. The build-time-idmap work (commits 2f6a9cf + 9053186, plan docs/superpowers/plans/2026-05-15-build-time-idmap.md) explicitly used "sandbox escape could see web.env / DB / running gameservers" as the argument for keeping l4d2-sandbox as a separate uid. That argument cuts the "collapse to 1" option hard.
  • Verified clean on the host: left4me-server@{1,2}.service are both running as left4me today (janitorial item 8 diagnostic). No orphan idmap binds; the 2-uid invariants hold.
  • Files-overlay invariant verified: overlay 8 (Optimized Settings, files-type) is left4me:left4me end-to-end with no l4d2-sandbox-owned files (janitorial item 9). This means files overlays would not be affected by a gameserver-uid split — the Python web app writes them directly as left4me.
  • The hardening floor is high. srcds already runs with NoNewPrivileges=true, ProtectSystem=strict, PrivateDevices=true, ReadOnlyPaths=...installation...overlays, RestrictSUIDSGID=true, LockPersonality=true (see deploy/files/usr/local/lib/systemd/system/left4me-server@.service). Most exfil paths a gameserver-uid split would close are already closed by systemd hardening. The case for "split to 3" is defense-in-depth, not a missing primary control.
  • Sudoers / cross-repo cost. A new uid would need additions in ckn-bw's bundles/left4me/items.py (users dict) and in the sudoers grants. Both are in the right state to receive that change cleanly; deploy-dir-rethink already pinned where each lives.

Downstream consequence

Whatever uid-split decides constrains the build-overlay-unit refactor that follows (docs/superpowers/specs/2026-05-15-build-overlay-unit-design.md). The systemd template unit replacing left4me-script-sandbox encodes the idmap mapping l4d2-sandbox<target uid>. Settling the uid question first means build-overlay-unit composes against a final foundation rather than retouching.

Pointers

  • Source-of-truth spec: docs/superpowers/specs/2026-05-15-user-uid-split-design.md
  • Build-time-idmap plan (the load-bearing security argument): docs/superpowers/plans/2026-05-15-build-time-idmap.md
  • Live unit files for srcds hardening review: deploy/files/usr/local/lib/systemd/system/left4me-server@.service
  • ckn-bw users definition: ~/Projekte/ckn-bw/bundles/left4me/items.py (the users = {...} dict near the top)
  • Sandbox helper that does the idmap mapping today: scripts/libexec/left4me-script-sandbox

What's NOT next

  • Build-overlay-unit refactor. Wait for uid-split.
  • Janitorial item 7 (_sandbox_script_dir cleanup). Conditional on build-overlay-unit Option B landing.
  • Mako template duplication in ckn-bw. Separate cleanup; the templates legitimately need bw's metadata access.
  • Pushing the ckn-bw 91b7265 commit. Safe but not blocking.