fix(forgejo-runner): the cache server can start
Some checks failed
ci / check (pull_request) Failing after 7s
ci / install (pull_request) Successful in 4s
ci / db-integration (pull_request) Successful in 4s
labels / labels (pull_request) Failing after 7s

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) <noreply@anthropic.com>
This commit is contained in:
cluade-reviewer-andresmgsl 2026-07-31 16:57:42 +00:00
parent 4a6e9761e5
commit a45d84892f
3 changed files with 33 additions and 1 deletions

3
changelog.d/135.md Normal file
View file

@ -0,0 +1,3 @@
### Fixed
- Forgejo runners installed by rig can start their cache server — `$HOME/.cache` is created and punched through `ProtectHome` (#135)

View file

@ -397,6 +397,14 @@ fi
# holds the UUID. assert_runner_instance's contract survives either way — it # holds the UUID. assert_runner_instance's contract survives either way — it
# asks about the instance, which both spellings record. # asks about the instance, which both spellings record.
install -d -m 0755 -o "$RUNNER_USER" -g "$RUNNER_GROUP" "$RUNNER_DIR" 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 if [ -e "$RUNNER_DIR/.runner" ]; then
log "already registered; skipping registration" log "already registered; skipping registration"
# Registration was skipped, so the labels on the instance are the ones it was # Registration was skipped, so the labels on the instance are the ones it was
@ -461,7 +469,7 @@ NoNewPrivileges=true
PrivateTmp=true PrivateTmp=true
ProtectSystem=full ProtectSystem=full
ProtectHome=read-only ProtectHome=read-only
ReadWritePaths=${RUNNER_DIR} ReadWritePaths=${RUNNER_DIR} ${USER_HOME}/.cache
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View file

@ -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 "" \ 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" 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: 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 check "forgejo-runner: remove --help exits 0" 0 "usage:" "$ROOT/commands/forgejo-runner-remove.sh" --help