Merge remote-tracking branch 'origin/main' into pr140
This commit is contained in:
commit
5187b74fa0
4 changed files with 127 additions and 15 deletions
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
|
@ -26,7 +26,21 @@ jobs:
|
|||
# The file list is printed so under-coverage shows up in the log, and
|
||||
# the comm below turns under-coverage into a failure rather than a
|
||||
# thing someone has to notice: every tracked `.sh` must be in the set.
|
||||
#
|
||||
# Install shellcheck when missing (#144). rig's default Forgejo label
|
||||
# maps ubuntu-latest to catthehacker's act-22.04 (slim), which does not
|
||||
# ship shellcheck; GitHub-hosted ubuntu-latest does. The conditional
|
||||
# keeps each forge from paying for the other.
|
||||
#
|
||||
# sudo: load-bearing on GitHub (job runs as `runner` with passwordless
|
||||
# sudo) and a no-op on act-22.04 (jobs run as uid 0; the image has no
|
||||
# `runner` account). Do not delete it as "dead weight" — that breaks
|
||||
# the GitHub half the day that image stops preinstalling shellcheck.
|
||||
run: |
|
||||
if ! command -v shellcheck >/dev/null 2>&1; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y shellcheck
|
||||
fi
|
||||
shopt -s globstar dotglob
|
||||
files=(bin/* **/*.sh)
|
||||
printf 'shellcheck: %s\n' "${files[@]}"
|
||||
|
|
|
|||
8
changelog.d/144.md
Normal file
8
changelog.d/144.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
### Added
|
||||
|
||||
- Default Forgejo runner labels include opt-in `ubuntu-latest-full` for the GitHub-parity image (#144)
|
||||
|
||||
### Fixed
|
||||
|
||||
- `ci.yml` installs `shellcheck` when the runner image lacks it, so Forgejo's slim `ubuntu-latest` can run `check` (#144)
|
||||
- Plain `rig forgejo-runner install` warns when recorded labels are a retired rig default, without nagging custom `--labels` (#144)
|
||||
|
|
@ -33,7 +33,32 @@ die() { printf 'rig-forgejo-runner: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
|
|||
# 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'
|
||||
#
|
||||
# WHY act-22.04 (slim) for ubuntu-latest, not full-22.04 — measured 2026-08-01
|
||||
# against ghcr manifests (#144):
|
||||
# act-22.04: ~0.55 GB compressed / ~2.2 GB on disk — no shellcheck
|
||||
# full-22.04: ~18.67 GB compressed / ~54.5 GB on disk — has shellcheck 0.8.0
|
||||
# A normal box-class ci tenant cannot hold 54.5 GB (typical free space ~34 GB).
|
||||
# So ubuntu-latest stays slim, and workflows must not assume GitHub-image tools
|
||||
# (rig's own ci.yml installs shellcheck when missing). Operators who need the
|
||||
# full tool surface opt in with runs-on: ubuntu-latest-full — that label is
|
||||
# inert until matched, so boxes that never ask pay nothing.
|
||||
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'
|
||||
|
||||
# labels_are_a_retired_default <recorded>
|
||||
#
|
||||
# True when <recorded> is a past DEFAULT_LABELS value rig has shipped — the
|
||||
# only plain-converge case that should warn about re-registration (#144).
|
||||
# Custom operator maps (drill's Leg 3, any --labels) must return false so a
|
||||
# bare re-run stays quiet. One pattern per past default; add when the string
|
||||
# changes. Extracted and driven by test/cli.sh — a grep pin alone cannot prove
|
||||
# the match is exact.
|
||||
labels_are_a_retired_default() {
|
||||
case "${1:-}" in
|
||||
'ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04,docker:docker://node:22-bookworm') return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# fetch_and_verify_sha256 <asset-url> <file> <sumfile> <label>
|
||||
#
|
||||
|
|
@ -95,8 +120,10 @@ 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
|
||||
workflow written for GitHub runs unchanged.
|
||||
ubuntu-latest (slim act image), ubuntu-latest-full
|
||||
(opt-in parity image), and docker onto containers so
|
||||
a workflow written for GitHub runs; full tools need
|
||||
runs-on: ubuntu-latest-full or an install step.
|
||||
--user <name> unprivileged service user (default: the tenant user
|
||||
`ci` when it exists, else forgejo-runner; created if
|
||||
absent; never root)
|
||||
|
|
@ -414,14 +441,29 @@ 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
|
||||
# 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
|
||||
# registered with — NOT whatever this invocation was passed. Forgejo owns
|
||||
# labels from registration time; a re-run never rewrites them.
|
||||
#
|
||||
# Two warn paths (#144):
|
||||
# EXPLICIT --labels that differs → operator asked and it was not applied.
|
||||
# Plain converge whose recorded labels match a known *retired* default →
|
||||
# rig's default map moved (e.g. added ubuntu-latest-full). Without this
|
||||
# the operator re-runs install, sees "already registered", and believes
|
||||
# they have the new default while Forgejo still holds the old set.
|
||||
#
|
||||
# Do NOT warn on every RECORDED != current default: that fires forever for
|
||||
# any runner the operator deliberately gave custom --labels (drill's Leg 3
|
||||
# registers drill:docker://node:22-bookworm). The old LABELS_EXPLICIT-only
|
||||
# gate existed to avoid that noise; retired-default matching keeps the
|
||||
# silence for intentional maps and still catches silent drift off a past
|
||||
# rig default. Re-register only to pick up labels the old set never had —
|
||||
# nothing matching the recorded set is broken by the map change alone.
|
||||
if [ -r "$RUNNER_DIR/.rig-labels" ]; then
|
||||
RECORDED="$(cat "$RUNNER_DIR/.rig-labels")"
|
||||
if [ "$RECORDED" != "$LABELS" ]; then
|
||||
if [ "$LABELS_EXPLICIT" -eq 1 ] && [ "$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."
|
||||
elif [ "$LABELS_EXPLICIT" -eq 0 ] && labels_are_a_retired_default "$RECORDED"; then
|
||||
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."
|
||||
fi
|
||||
fi
|
||||
else
|
||||
|
|
|
|||
56
test/cli.sh
56
test/cli.sh
|
|
@ -3389,12 +3389,22 @@ check "forgejo-runner: --version refuses a path, not a release number" 2 "releas
|
|||
"$FR" --instance https://f.example.com --version ../../etc/passwd
|
||||
check "forgejo-runner: --version refuses a non-numeric pin" 2 "release number like" \
|
||||
"$FR" --instance https://f.example.com --version latest
|
||||
# Reaching the root check is the proof a good pin got THROUGH validation: this
|
||||
# runs as a normal user in CI, so "must run as root" is the next gate down.
|
||||
check "forgejo-runner: a plain release number passes validation" 1 "must run as root" \
|
||||
# Reaching a gate AFTER --version parsing is the proof a good pin got THROUGH
|
||||
# validation. Which gate depends on the uid: non-root hits "must run as root";
|
||||
# act/Forgejo jobs run as uid 0 (no `runner` account — #144), so they sail past
|
||||
# the root check and hit the unattended-token refuse instead. Both prove the
|
||||
# same thing. GitHub-hosted ubuntu-latest is non-root and takes the first arm.
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
check "forgejo-runner: a plain release number passes validation" 1 "must run as root" \
|
||||
"$FR" --instance https://f.example.com --version 12.13.2
|
||||
check "forgejo-runner: a leading v is stripped before that check" 1 "must run as root" \
|
||||
check "forgejo-runner: a leading v is stripped before that check" 1 "must run as root" \
|
||||
"$FR" --instance https://f.example.com --version v12.13.2
|
||||
else
|
||||
check "forgejo-runner: a plain release number passes validation" 1 "FORGEJO_RUNNER_TOKEN is unset" \
|
||||
env -u FORGEJO_RUNNER_TOKEN "$FR" --instance https://f.example.com --version 12.13.2
|
||||
check "forgejo-runner: a leading v is stripped before that check" 1 "FORGEJO_RUNNER_TOKEN is unset" \
|
||||
env -u FORGEJO_RUNNER_TOKEN "$FR" --instance https://f.example.com --version v12.13.2
|
||||
fi
|
||||
# A schemeless host and a repo URL are the two ways an operator mis-states the
|
||||
# instance, and only one of them would fail loudly on its own — a repo URL
|
||||
# registers somewhere subtly wrong instead. Both refuse by name.
|
||||
|
|
@ -3744,6 +3754,44 @@ check "forgejo-runner: an explicit --labels on a rerun warns it was not applied"
|
|||
grep -o -- "--labels was not applied" "$FR"
|
||||
check "forgejo-runner: that warning is gated on --labels being EXPLICIT" 0 "LABELS_EXPLICIT" \
|
||||
grep -o "LABELS_EXPLICIT" "$FR"
|
||||
# #144 option B: plain converge warns only for known *retired* defaults — not
|
||||
# for every RECORDED != current default (that would noise custom --labels
|
||||
# forever, including drill's Leg 3). Drive the recogniser against fixtures
|
||||
# (test/drill.sh extraction pattern) so a dead matcher cannot greppen green.
|
||||
check "forgejo-runner: plain converge warns on a known retired default label set" 0 "registered with an older rig default label set" \
|
||||
grep -o "registered with an older rig default label set" "$FR"
|
||||
check "forgejo-runner: that warn says re-register only if you want the new label" 0 "re-register only if you want the new label" \
|
||||
grep -o "re-register only if you want the new label" "$FR"
|
||||
PRE_144_LABELS='ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04,docker:docker://node:22-bookworm'
|
||||
CURRENT_LABELS="$(sed -n "s/^DEFAULT_LABELS='\\(.*\\)'$/\\1/p" "$FR")"
|
||||
RETIRED_FNS="$(mktemp)"
|
||||
awk '/^labels_are_a_retired_default\(\) \{/,/^\}/' "$FR" > "$RETIRED_FNS"
|
||||
check "extraction guards the awk: labels_are_a_retired_default() landed" 0 "labels_are_a_retired_default() {" \
|
||||
grep -F 'labels_are_a_retired_default() {' "$RETIRED_FNS"
|
||||
# shellcheck source=/dev/null
|
||||
. "$RETIRED_FNS"
|
||||
check "retired-default: the pre-#144 default is recognised" 0 "" \
|
||||
labels_are_a_retired_default "$PRE_144_LABELS"
|
||||
check "retired-default: the CURRENT default is not drift" 1 "" \
|
||||
labels_are_a_retired_default "$CURRENT_LABELS"
|
||||
check "retired-default: an operator's own --labels map is never drift" 1 "" \
|
||||
labels_are_a_retired_default 'drill:docker://node:22-bookworm'
|
||||
check "retired-default: a near-miss of a past default is not a match" 1 "" \
|
||||
labels_are_a_retired_default "${PRE_144_LABELS} "
|
||||
rm -f "$RETIRED_FNS"
|
||||
# Default map: slim ubuntu-latest (act), opt-in full, docker — pin the three
|
||||
# so a silent drop of the full rider or a flip back to full-as-default fails.
|
||||
check "forgejo-runner: DEFAULT_LABELS maps ubuntu-latest to act-22.04 (slim)" 0 "ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04" \
|
||||
grep -o "ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04" "$FR"
|
||||
check "forgejo-runner: DEFAULT_LABELS offers ubuntu-latest-full as opt-in" 0 "ubuntu-latest-full:docker://ghcr.io/catthehacker/ubuntu:full-22.04" \
|
||||
grep -o "ubuntu-latest-full:docker://ghcr.io/catthehacker/ubuntu:full-22.04" "$FR"
|
||||
check "forgejo-runner: DEFAULT_LABELS comment records the slim/full size measurement" 0 "54.5 GB" \
|
||||
grep -o "54.5 GB" "$FR"
|
||||
# ci.yml must install shellcheck when the image lacks it (#144 option B).
|
||||
check "ci.yml: shellcheck step installs the tool when missing" 0 "command -v shellcheck" \
|
||||
grep -o "command -v shellcheck" "$ROOT/.github/workflows/ci.yml"
|
||||
check "ci.yml: shellcheck install uses sudo (GitHub path; no-op on act as root)" 0 "sudo apt-get install -y shellcheck" \
|
||||
grep -o "sudo apt-get install -y shellcheck" "$ROOT/.github/workflows/ci.yml"
|
||||
# The GitHub sibling is the precedent this restores — pin that it still scopes
|
||||
# its own write, so the two cannot drift apart again.
|
||||
gh_labels_write_is_scoped() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue