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