From a45d84892fed03c6edf5cd9c2783a32a09b9568e Mon Sep 17 00:00:00 2001 From: cluade-reviewer-andresmgsl Date: Fri, 31 Jul 2026 16:57:42 +0000 Subject: [PATCH] fix(forgejo-runner): the cache server can start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProtectHome=read-only made the whole home read-only and only RUNNER_DIR was punched back through, so forgejo-runner could not create $HOME/.cache and disabled its cache server on every install. actions/cache was silently off on every rig-installed Forgejo runner, evidenced by one error line in the journal while `status` reported a healthy runner. Both halves are required, and the obvious one-line version is WORSE than the bug: a ReadWritePaths entry naming a path that does not exist makes systemd refuse to start the unit at all — "Failed to set up mount namespacing", three restart attempts, service down. Measured on a live runner before writing this. So the directory is created at install, owned by the runner user like RUNNER_DIR beside it, and the unit lists it. ProtectHome stays read-only: the runner supervises job containers on this box's docker socket, and the cache is not a reason to widen that. Verified live from scratch: directory removed, unit removed, converge, then zero cache-server errors and the two cache listeners bound. Closes #135 Co-Authored-By: Claude Opus 5 (1M context) --- changelog.d/135.md | 3 +++ commands/forgejo-runner-install.sh | 10 +++++++++- test/cli.sh | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 changelog.d/135.md diff --git a/changelog.d/135.md b/changelog.d/135.md new file mode 100644 index 0000000..e8f18e1 --- /dev/null +++ b/changelog.d/135.md @@ -0,0 +1,3 @@ +### Fixed + +- Forgejo runners installed by rig can start their cache server — `$HOME/.cache` is created and punched through `ProtectHome` (#135) diff --git a/commands/forgejo-runner-install.sh b/commands/forgejo-runner-install.sh index 224e406..902bff6 100755 --- a/commands/forgejo-runner-install.sh +++ b/commands/forgejo-runner-install.sh @@ -397,6 +397,14 @@ fi # holds the UUID. assert_runner_instance's contract survives either way — it # asks about the instance, which both spellings record. install -d -m 0755 -o "$RUNNER_USER" -g "$RUNNER_GROUP" "$RUNNER_DIR" +# forgejo-runner's cache server writes to $HOME/.cache, which ProtectHome makes +# read-only below. Create it HERE, before the unit can reference it: a +# ReadWritePaths entry naming a path that does not exist makes systemd refuse +# to start the unit at all ("Failed to set up mount namespacing"), which is +# worse than the disabled cache it was meant to fix. Measured on a live runner, +# 2026-07-31 (#135). Root-owned would fail the same way under User=, so it +# carries the runner's own ownership like RUNNER_DIR above. +install -d -m 0755 -o "$RUNNER_USER" -g "$RUNNER_GROUP" "$USER_HOME/.cache" if [ -e "$RUNNER_DIR/.runner" ]; then log "already registered; skipping registration" # Registration was skipped, so the labels on the instance are the ones it was @@ -461,7 +469,7 @@ NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=read-only -ReadWritePaths=${RUNNER_DIR} +ReadWritePaths=${RUNNER_DIR} ${USER_HOME}/.cache [Install] WantedBy=multi-user.target diff --git a/test/cli.sh b/test/cli.sh index 4846778..fd79ee2 100644 --- a/test/cli.sh +++ b/test/cli.sh @@ -3350,6 +3350,27 @@ check "forgejo-runner: remove warns about an orphaned unit" 0 "orphaned unit" \ check "forgejo-runner: remove never rm's an unguarded \$RUNNER_DIR path" 1 "" \ grep -qE '^rm -f "\$RUNNER_DIR' "$ROOT/commands/forgejo-runner-remove.sh" +# #135: ProtectHome=read-only made the whole home read-only and only RUNNER_DIR +# was punched back through, so forgejo-runner could not create $HOME/.cache and +# disabled its cache server on every install — actions/cache silently off, one +# error line in the journal, and `status` reporting a healthy runner. +# +# BOTH halves are asserted because the obvious one-line version is WORSE than +# the bug: listing the path in ReadWritePaths without creating it makes systemd +# refuse to start the unit at all ("Failed to set up mount namespacing"), +# measured on a live box. The directory must exist first. +FRI="$ROOT/commands/forgejo-runner-install.sh" +grep_cache_install() { + # shellcheck disable=SC2016 # $RUNNER_USER is literal text in the shipped file + grep -qE 'install -d .*-o "\$RUNNER_USER".*\.cache' "$FRI" +} +check "forgejo-runner: the cache dir is punched through ProtectHome" 0 "" \ + grep -qE 'ReadWritePaths=.*\.cache' "$FRI" +check "forgejo-runner: …and the install creates it, owned by the runner user" 0 "" \ + grep_cache_install +check "forgejo-runner: ProtectHome stays read-only (the cache is not an excuse to widen it)" 0 "" \ + grep -qF 'ProtectHome=read-only' "$FRI" + check "forgejo-runner: status --help exits 0" 0 "usage:" "$ROOT/commands/forgejo-runner-status.sh" --help check "forgejo-runner: remove --help exits 0" 0 "usage:" "$ROOT/commands/forgejo-runner-remove.sh" --help