From ae443299c8364a0dcfd23b03acd9736e4016955c Mon Sep 17 00:00:00 2001 From: mwiegand Date: Fri, 8 May 2026 16:48:26 +0200 Subject: [PATCH] chore(deploy): drop bubblewrap apt dep + tighten left4me.db mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bubblewrap is no longer used now that left4me-script-sandbox runs as a systemd service unit. Remove it from the apt-get and dnf install lines. Also tighten the application database file mode after the alembic upgrade step: chown root:left4me, chmod 0640. The DB had been created at default 0644 by SQLite's open() call inside the web service, which made it world-readable on the host — i.e. readable by any uid that can traverse /var/lib/left4me, including the sandbox's l4d2-sandbox uid. Smoke-testing the v2 sandbox prototype on ckn@10.0.4.128 surfaced this: the sandbox could read "SQLite format 3" from the DB until the parent dir was masked with TemporaryFileSystem=. Tightening the file mode is the host-level fix; the sandbox-level mask is defense in depth. Co-Authored-By: Claude Opus 4.7 (1M context) --- deploy/deploy-test-server.sh | 14 ++++++++++++-- deploy/tests/test_deploy_artifacts.py | 11 +++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/deploy/deploy-test-server.sh b/deploy/deploy-test-server.sh index ae47451..cc7c785 100755 --- a/deploy/deploy-test-server.sh +++ b/deploy/deploy-test-server.sh @@ -85,9 +85,9 @@ fi if command -v apt-get >/dev/null 2>&1; then $sudo_cmd apt-get update - $sudo_cmd apt-get install -y python3 python3-venv python3-pip curl ca-certificates tar gzip util-linux sudo bubblewrap + $sudo_cmd apt-get install -y python3 python3-venv python3-pip curl ca-certificates tar gzip util-linux sudo elif command -v dnf >/dev/null 2>&1; then - $sudo_cmd dnf install -y python3 python3-pip curl ca-certificates tar gzip util-linux sudo bubblewrap + $sudo_cmd dnf install -y python3 python3-pip curl ca-certificates tar gzip util-linux sudo else printf 'Unsupported package manager: expected apt-get or dnf\n' >&2 exit 1 @@ -171,6 +171,16 @@ run_as_left4me sh -c "cd /opt/left4me/l4d2web && set -a; . /etc/left4me/host.env PYTHONPATH=/opt/left4me \ /opt/left4me/.venv/bin/alembic -c /opt/left4me/l4d2web/alembic.ini upgrade head" +# Tighten the application database to root:left4me 0640. The DB is created +# by the web app at first start with the default 0644 umask, which makes it +# world-readable on the host. The script-overlay sandbox runs as a separate +# system uid (l4d2-sandbox) — without this clamp, a sandboxed script could +# read the entire app DB. Idempotent on rerun. +if [ -f /var/lib/left4me/left4me.db ]; then + $sudo_cmd chown root:left4me /var/lib/left4me/left4me.db + $sudo_cmd chmod 0640 /var/lib/left4me/left4me.db +fi + if [ -f "$remote_tmp/admin_username" ] && [ -f "$remote_tmp/admin_password" ]; then LEFT4ME_ADMIN_USERNAME=$(cat "$remote_tmp/admin_username") LEFT4ME_ADMIN_PASSWORD=$(cat "$remote_tmp/admin_password") diff --git a/deploy/tests/test_deploy_artifacts.py b/deploy/tests/test_deploy_artifacts.py index 53aeb27..7415b77 100644 --- a/deploy/tests/test_deploy_artifacts.py +++ b/deploy/tests/test_deploy_artifacts.py @@ -294,14 +294,21 @@ def test_deploy_script_provisions_sandbox_user(): assert "useradd --system --no-create-home --shell /usr/sbin/nologin l4d2-sandbox" in script -def test_deploy_script_installs_bubblewrap(): +def test_deploy_script_does_not_install_bubblewrap(): install_lines = [ line for line in DEPLOY_SCRIPT.read_text().splitlines() if ("apt-get install" in line or "dnf install" in line) ] assert install_lines, "expected at least one apt/dnf install line" for line in install_lines: - assert "bubblewrap" in line, f"missing bubblewrap in install line: {line}" + assert "bubblewrap" not in line, line + assert "bwrap" not in line, line + + +def test_deploy_script_tightens_left4me_db_permissions(): + script = DEPLOY_SCRIPT.read_text() + assert "chown root:left4me /var/lib/left4me/left4me.db" in script + assert "chmod 0640 /var/lib/left4me/left4me.db" in script def test_deploy_script_installs_script_sandbox_helper():