No description
Find a file
mwiegand 461b8d028f
spec(hardening): test plan executed on left4.me — results recorded
Ran the 11-test plan against left4me-server@1 (canary) and left4me-web
on left4.me / Debian 13 / systemd 257. Cleaned up all unit drop-ins;
kept the Test 9 sysctl (kernel.yama.ptrace_scope=2) per spec.

Outcomes:
- server@1 systemd-analyze: 7.5 EXPOSED → 1.3 OK
- left4me-web systemd-analyze: 8.7 EXPOSED → 4.1 OK
- All 8 attack vectors in Test 8 (D1.a-c, D2.a-c, D3, D5) blocked
- Test 6 (MemoryDenyWriteExecute) fails as predicted — Source engine
  i386 .so files have text relocations; exclude from final composition.
- Test 11 (24-48h soak) skipped per operator decision.

Two amendments to the spec's proposed composition required for the
refactor:
- SystemCallArchitectures=native x86 (not bare 'native') — srcds_linux
  is i386, the kernel kills every native-only call.
- PrivatePIDs=true added — ProtectProc=invisible alone cannot hide
  gunicorn from srcds because both run as uid 980; PrivatePIDs gives
  each instance its own PID namespace and closes D2.b.

Spec bugs surfaced and documented in the "Output" section: PID lookup
via pgrep (race vs. instance), Test 4/10 gdb-from-host doesn't
actually exercise the unit's SECCOMP filter, Test 8 D5 pgrep pattern
won't match. Tooling note corrected: scmp_sys_resolver is in
'seccomp' package, not 'libseccomp-dev'.

Next session: write docs/superpowers/plans/2026-MM-DD-hardening-refactor.md
against the proven composition; supersede the uid-split spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:39:50 +02:00
deploy refactor: move privileged scripts to scripts/{libexec,sbin}/; deploy/ is reference 2026-05-15 12:05:30 +02:00
docs spec(hardening): test plan executed on left4.me — results recorded 2026-05-15 13:39:50 +02:00
examples/script-overlays feat(l4d2-web): seed example script overlays from examples/script-overlays/ 2026-05-08 18:41:08 +02:00
l4d2host refactor: move privileged scripts to scripts/{libexec,sbin}/; deploy/ is reference 2026-05-15 12:05:30 +02:00
l4d2web docs: correct stale bubblewrap references in v1 spec + live docstring 2026-05-15 12:12:31 +02:00
scripts docs: correct stale bubblewrap references in v1 spec + live docstring 2026-05-15 12:12:31 +02:00
.envrc chore: add direnv .envrc for local Python 3.13 venv 2026-05-08 18:56:51 +02:00
.gitignore chore: add dev.db and opencode.json to gitignore 2026-05-13 14:29:57 +02:00
AGENTS.md Revert "AGENTS: harden the spec+plan commit rule" 2026-05-11 22:26:47 +02:00
README.md chore: add direnv .envrc for local Python 3.13 venv 2026-05-08 18:56:51 +02:00

left4me

left4me is a local L4D2 server management platform with two planned components:

  1. l4d2host + l4d2ctl (host library + CLI)
  2. l4d2-web-app (Flask web app for users, blueprints, servers, jobs, and logs)

Status

Implementation plans remain the source of truth for architecture and task sequencing:

  • docs/superpowers/plans/2026-04-22-l4d2-host-lib-v1.md
  • docs/superpowers/plans/2026-04-23-l4d2-web-app-v1.md

Locked v1 Decisions

  • Naming is strictly l4d2 (not l4d).
  • Host library and web app are separate components.
  • Host CLI write commands are fixed to:
    • install
    • initialize <name> -f <spec.yaml>
    • start <name>
    • stop <name>
    • delete <name>
  • Host CLI read commands are available for the web/host boundary:
    • status <name> --json
    • logs <name> --lines <n> --follow/--no-follow
  • The web app calls host operations through l4d2ctl, not direct l4d2host imports.
  • Deployment uses /var/lib/left4me for runtime state, /opt/left4me for repository contents and the virtualenv, /etc/left4me for environment files, and global units under /usr/local/lib/systemd/system.
  • Overlay handling is directory-based; the web app populates each overlay (workshop downloads, managed-global refresh).
  • No lock manager, no rollback, no preflight checks in host library.
  • CLI propagates subprocess failures via stderr and return code.
  • delete on missing instance is no-op success.
  • Blueprint model (web app):
    • user-private in v1
    • servers are live-linked to blueprint
    • no per-server overrides
    • delete blueprint blocked when linked servers exist
    • blueprint changes apply on next action
    • server can reassign blueprint anytime

Planned Repository Layout

  • l4d2host/
  • l4d2web/
  • deploy/
  • docs/superpowers/plans/

Deployment

See deploy/README.md for the Linux test deployment contract, including the runtime user, target filesystem layout, systemd units, privileged helpers, sudoers rules, admin bootstrap, and overlay reference rules.

Local development

This repo uses direnv to auto-activate a Python 3.13 venv on cd (matching the Debian Trixie production target). With direnv installed and hooked into your shell:

  1. direnv allow once per fresh checkout (and after any .envrc change).
  2. cd out and back in — .direnv/python-3.13/ is created and put on PATH.
  3. pip install -e ./l4d2host -e ./l4d2web to install both packages editable.
  4. pip install pytest to run the test suites (pytest tests/ inside either subproject).

Tech Stack (planned)

  • Python 3.12+
  • Typer, PyYAML, pytest
  • Flask, SQLAlchemy, Alembic
  • HTMX (vendored locally), custom CSS, SSE
  • systemd units, kernel overlayfs (mounted via the left4me-overlay privileged helper), steamcmd
  1. Implement l4d2host plan first.
  2. Implement l4d2web plan second.
  3. Keep tests green task-by-task (TDD flow from plans).
  4. Keep commits small and aligned with plan tasks.

Contributing Notes

  • Follow plan task order unless explicitly re-planned.
  • Keep contracts above unchanged unless the user asks to change them.
  • Update plan docs when scope or behavior changes.