fix: ci check installs shellcheck where the image lacks it; default runner labels gain ubuntu-latest-full (#144)

This commit is contained in:
kimi-reviewer-andresmgsl 2026-08-01 21:24:51 +00:00
parent 9cb81c9f6b
commit ba3097491a
4 changed files with 80 additions and 7 deletions

View file

@ -15,6 +15,16 @@ jobs:
# a skip (a guard that can quietly stop guarding is the failure
# shape these checks exist to refuse).
fetch-depth: 0
- name: install shellcheck where the image lacks it
# GitHub's ubuntu-latest preinstalls shellcheck; the slim act image
# rig's Forgejo runners map `ubuntu-latest` to does not (#144), and
# the full image (54.5 GB on disk) is not a price every ci-box can
# pay. The `command -v` short-circuit means GitHub pays nothing; on
# the act image the job runs as uid 0 and sudo is a no-op — it is
# load-bearing only on GitHub, where the job runs as `runner` with
# passwordless sudo. Both forges get jammy's 0.8.0, the same version
# the full image ships, so no lint result differs between them.
run: command -v shellcheck >/dev/null || { sudo apt-get update && sudo apt-get install -y shellcheck; }
- name: shellcheck
# -x follows the `source=SCRIPTDIR/...` directives into commands/lib/.
# globstar so a script in a new subdirectory is linted without anyone

8
changelog.d/144.md Normal file
View file

@ -0,0 +1,8 @@
### Added
- `ubuntu-latest-full` runner label — opt-in GitHub-parity image, pulls nothing until a job matches it (#144)
### Fixed
- CI's `check` job installs shellcheck where the runner image lacks it — rig's own CI passes on rig-installed Forgejo runners (#144)
- `forgejo-runner install` warns on a plain converge when a runner was registered with a retired default label set (#144)

View file

@ -27,11 +27,22 @@ die() { printf 'rig-forgejo-runner: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
# editing to migrate; catthehacker's image is the act/Forgejo ecosystem's
# stand-in for GitHub's runner image. `docker` is the lean second option.
#
# `ubuntu-latest` maps to the SLIM act image, not the full one — measured
# 2026-08-01 (ghcr manifests, amd64): act-22.04 is 0.55 GB on the wire and
# ~2 GB on disk; full-22.04 is 18.67 GB on the wire and 54.52 GB on disk,
# which does not fit a box-class ci-box at all. The slim image carries no
# copy of shellcheck (streamed every layer: zero entries), so a workflow must
# assume GitHub's tool surface — it installs what it uses, as rig's own
# ci.yml does for shellcheck (#144). `ubuntu-latest-full` is the opt-in
# parity label: inert until a job matches it, so it costs nothing to boxes
# that never ask, and an operator who needs GitHub's full tool surface
# writes `runs-on: ubuntu-latest-full` and pays the 54.5 GB deliberately.
#
# Both are `docker://` — jobs run in CONTAINERS on the box's own dockerd, not
# on the box itself. No docker-in-docker: the guide this came from stacks a
# privileged dind sidecar with a plaintext tcp://…:2375 daemon to isolate jobs
# from a shared CI server, and inside a box that boundary is already paid for.
DEFAULT_LABELS='ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04,docker:docker://node:22-bookworm'
DEFAULT_LABELS='ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04,ubuntu-latest-full:docker://ghcr.io/catthehacker/ubuntu:full-22.04,docker:docker://node:22-bookworm'
# fetch_and_verify_sha256 <asset-url> <file> <sumfile> <label>
#
@ -93,7 +104,8 @@ usage: rig forgejo-runner install --instance <url> [options]
time). Pin it for a deterministic, auditable install.
--name <name> runner name (default: this host's hostname)
--labels <csv> runner labels; replaces the default. The default maps
ubuntu-latest and docker onto container images, so a
ubuntu-latest (slim), ubuntu-latest-full (GitHub
parity, opt-in) and docker onto container images, so a
workflow written for GitHub runs unchanged.
--user <name> unprivileged service user (default: the tenant user
`ci` when it exists, else forgejo-runner; created if
@ -410,13 +422,26 @@ if [ -e "$RUNNER_DIR/.runner" ]; then
# Registration was skipped, so the labels on the instance are the ones it was
# registered with — NOT whatever this invocation was passed. Say so when the
# operator explicitly asked for different ones, rather than letting the
# request evaporate. Only when EXPLICIT: comparing the default against a
# runner registered with custom labels would warn on every plain converge.
if [ "$LABELS_EXPLICIT" -eq 1 ] && [ -r "$RUNNER_DIR/.rig-labels" ]; then
# request evaporate. When nothing was asked for, warn only when the recorded
# labels are a KNOWN retired rig default — comparing a plain converge against
# the current default would warn on every run for runners registered with
# custom --labels, which is noise (the LABELS_EXPLICIT comment below).
if [ -r "$RUNNER_DIR/.rig-labels" ]; then
RECORDED="$(cat "$RUNNER_DIR/.rig-labels")"
if [ "$LABELS_EXPLICIT" -eq 1 ]; then
if [ "$RECORDED" != "$LABELS" ]; then
warn "--labels was not applied: this runner is already registered, and Forgejo owns its labels from registration time. It still has: ${RECORDED}. Labels are what 'runs-on' matches, so changing them means re-registering: 'rig forgejo-runner remove' then install again with the labels you want."
fi
else
# Retired defaults, one pattern per past DEFAULT_LABELS value. The
# message must not imply anything is broken: a retired default still
# runs everything it ran before (#144's fix lands in ci.yml, not here);
# re-registering only picks up labels the old set never had.
case "$RECORDED" in
'ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04,docker:docker://node:22-bookworm')
warn "this runner was registered with an older rig default label set. The current default adds ubuntu-latest-full (the GitHub-parity image). Labels are fixed at registration, so picking it up means re-registering: 'rig forgejo-runner remove' then install again. Nothing you run today is affected — re-register only if you want the new label." ;;
esac
fi
fi
else
log "registering runner ${RUNNER_NAME} against ${INSTANCE}"

View file

@ -3413,6 +3413,36 @@ check "forgejo-runner: …and the install creates it, owned by the runner user"
check "forgejo-runner: ProtectHome stays read-only (the cache is not an excuse to widen it)" 0 "" \
grep -qF 'ProtectHome=read-only' "$FRI"
# #144: the default label map, pinned WITH its reason. ubuntu-latest maps to
# the SLIM act image — the full one is 18.67 GB on the wire / 54.52 GB on
# disk and does not fit a box-class ci-box, so workflows install the tools
# they use (ci.yml's shellcheck step, pinned below) and the parity image is
# an opt-in label that pulls nothing until a job matches it.
check "forgejo-runner: the default map keeps ubuntu-latest on the slim act image" 0 "" \
grep -qF "DEFAULT_LABELS='ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04," "$FRI"
check "forgejo-runner: …and adds ubuntu-latest-full as the opt-in parity label" 0 "" \
grep -qF 'ubuntu-latest-full:docker://ghcr.io/catthehacker/ubuntu:full-22.04' "$FRI"
check "forgejo-runner: the default map still carries the lean docker label" 0 "" \
grep -qF "docker:docker://node:22-bookworm'" "$FRI"
# The retired-default warn: fires on a plain converge ONLY for a recorded
# label set that matches a known retired default — never for custom --labels,
# and never claiming anything is broken (the fix lives in ci.yml, so the old
# set still runs everything it ran before).
check "forgejo-runner: a plain converge names the retired default label set" 0 "" \
grep -qF "registered with an older rig default label set" "$FRI"
check "forgejo-runner: …matching the exact retired default, not any differing labels" 0 "" \
grep -qF "'ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04,docker:docker://node:22-bookworm')" "$FRI"
check "forgejo-runner: …and says re-registering is only for the new label" 0 "" \
grep -qF "re-register only if you want the new label" "$FRI"
# The other half of #144: ci.yml's check job installs shellcheck only when
# the image lacks it — the conditional is the pin, so a rewrite that makes
# GitHub pay for apt on every run fails here.
check "ci.yml: check installs shellcheck only where the image lacks it" 0 "" \
grep -qF 'command -v shellcheck >/dev/null ||' "$ROOT/.github/workflows/ci.yml"
# shellcheck disable=SC2016 # $1 is the bash -c positional, intentionally single-quoted
check "ci.yml: …and the install step runs before the shellcheck step" 0 "" \
bash -c 'grep -n "name: install shellcheck\|name: shellcheck$" "$1" | head -2 | tail -1 | grep -q "name: shellcheck"' _ "$ROOT/.github/workflows/ci.yml"
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