From f6ca85fc6f59625623772817b0c133d0c1a0b6e9 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Fri, 8 May 2026 17:09:47 +0200 Subject: [PATCH] fix(deploy): chown left4me.db to left4me:left4me, not root:left4me MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v2 hardening tightened the DB to mode 0640 owned by root:left4me, intending to block reads from the sandbox uid (l4d2-sandbox, not in the left4me group). It did — but it also took away write access from the web service itself, which runs as user left4me. With root owning the file, left4me only had group-read; INSERTs into the jobs table failed with "attempt to write a readonly database" and surfaced as a 500 on POST /overlays/{id}/script. Owner left4me + group left4me + mode 0640 keeps the same external posture (l4d2-sandbox gets nothing via "other") while restoring the web service's read+write access via "owner". Co-Authored-By: Claude Opus 4.7 (1M context) --- deploy/deploy-test-server.sh | 13 +++++++------ deploy/tests/test_deploy_artifacts.py | 4 +++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/deploy/deploy-test-server.sh b/deploy/deploy-test-server.sh index d51b749..f905aa9 100755 --- a/deploy/deploy-test-server.sh +++ b/deploy/deploy-test-server.sh @@ -177,13 +177,14 @@ 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. +# Tighten the application database to left4me: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) which is NOT in the left4me group — +# 0640 blocks it via "other". The owner (left4me) keeps read+write so the +# web service can update the DB. Idempotent on rerun. if [ -f /var/lib/left4me/left4me.db ]; then - $sudo_cmd chown root:left4me /var/lib/left4me/left4me.db + $sudo_cmd chown left4me:left4me /var/lib/left4me/left4me.db $sudo_cmd chmod 0640 /var/lib/left4me/left4me.db fi diff --git a/deploy/tests/test_deploy_artifacts.py b/deploy/tests/test_deploy_artifacts.py index 502fa98..dbcacf9 100644 --- a/deploy/tests/test_deploy_artifacts.py +++ b/deploy/tests/test_deploy_artifacts.py @@ -308,7 +308,9 @@ def test_deploy_script_does_not_install_bubblewrap(): def test_deploy_script_tightens_left4me_db_permissions(): script = DEPLOY_SCRIPT.read_text() - assert "chown root:left4me /var/lib/left4me/left4me.db" in script + # Owner left4me (the web service runs as this user and writes the DB); + # group left4me; mode 0640 — `other` (incl. l4d2-sandbox) gets nothing. + assert "chown left4me:left4me /var/lib/left4me/left4me.db" in script assert "chmod 0640 /var/lib/left4me/left4me.db" in script