feat: runner install resolves the latest release when --version is omitted
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e395d6754a
commit
63b2effe03
4 changed files with 42 additions and 11 deletions
20
README.md
20
README.md
|
|
@ -61,14 +61,14 @@ Control-plane box only. Installs Coolify at exactly the pinned version with
|
|||
the platform must never move underneath it on its own. Upgrading is an
|
||||
explicit re-run with a new pin. The pin is required; there is no default.
|
||||
|
||||
### `rig runner install --repo <owner/repo> --version <pin>`
|
||||
### `rig runner install --repo <owner/repo>`
|
||||
|
||||
Runner box only, run after `rig bootstrap runner` (the same two-step rhythm
|
||||
as `bootstrap control-plane` → `coolify install`):
|
||||
|
||||
```sh
|
||||
rig bootstrap runner --hostname my-ci-box
|
||||
rig runner install --repo acme/widgets --version 2.335.1
|
||||
rig runner install --repo acme/widgets
|
||||
```
|
||||
|
||||
Installs GitHub's official `actions/runner` as a systemd service under an
|
||||
|
|
@ -84,6 +84,10 @@ membership is root-equivalent, which is a gratuitous path to root on a box
|
|||
whose whole point is a narrow blast radius. Add Docker only once a job
|
||||
genuinely needs it, and rethink the isolation model then.
|
||||
|
||||
- `--version <pin>` — actions/runner release to install (default: the
|
||||
latest release, resolved at install time; e.g. `--version 2.335.1` —
|
||||
the latest as of this writing). Pin it when you need a deterministic,
|
||||
auditable install.
|
||||
- `--name <name>` — runner name (default: this host's hostname)
|
||||
- `--labels <csv>` — runner labels, replacing the `ci-runner` default — keep
|
||||
any label your workflows' `runs-on` needs (GitHub adds `self-hosted` itself)
|
||||
|
|
@ -93,11 +97,13 @@ genuinely needs it, and rethink the isolation model then.
|
|||
it at the interactive prompt. It's short-lived, consumed at registration, and
|
||||
never written to disk by rig.
|
||||
|
||||
The version pin is required, same as `coolify install` — but unlike Coolify,
|
||||
the installed runner **self-updates**: GitHub refuses jobs from stale
|
||||
runners, so freezing the version would just make it silently stop taking
|
||||
work. The pin states what you install today; GitHub owns the treadmill after
|
||||
that.
|
||||
Why latest-by-default here when `coolify install` demands a pin: the two
|
||||
tools age differently. Coolify never self-updates (`AUTOUPDATE=false`), so
|
||||
its version is a contract your deploy tooling is verified against — stating
|
||||
it is the point. The runner **self-updates regardless**: GitHub refuses jobs
|
||||
from stale runners, so freezing it would just make it silently stop taking
|
||||
work. The install-time version is a starting point either way; `--version`
|
||||
exists for when you want that starting point deterministic and auditable.
|
||||
|
||||
Convergent — safe to re-run; an already-registered runner is left alone.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,14 @@ die() { printf 'rig-runner: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
|
|||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
usage: rig runner install --repo <owner/repo> --version <pin> [options]
|
||||
usage: rig runner install --repo <owner/repo> [options]
|
||||
|
||||
--repo <owner/repo> GitHub repository the runner registers to (required)
|
||||
--version <pin> actions/runner release to install, e.g. 2.335.1
|
||||
(required; no default — you state what you install)
|
||||
(default: the latest release, resolved at install
|
||||
time — safe here because the runner self-updates
|
||||
regardless; pin it when you need a deterministic,
|
||||
auditable install)
|
||||
--name <name> runner name (default: this host's hostname)
|
||||
--labels <csv> runner labels; replaces the default (default: ci-runner)
|
||||
--user <name> unprivileged service user (default: github-runner;
|
||||
|
|
@ -66,7 +69,6 @@ done
|
|||
if ! printf '%s' "$REPO" | grep -qE '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$'; then
|
||||
die "--repo must be owner/repo" 2
|
||||
fi
|
||||
[ -n "$VERSION" ] || die "--version <pin> is required" 2
|
||||
VERSION="${VERSION#v}"
|
||||
[ "$RUNNER_USER" != "root" ] || die "runner user must not be root" 2
|
||||
|
||||
|
|
@ -123,6 +125,20 @@ else
|
|||
aarch64) ARCH="arm64" ;;
|
||||
*) die "unsupported arch: $(uname -m)" ;;
|
||||
esac
|
||||
if [ -z "$VERSION" ]; then
|
||||
# No pin given: resolve the latest release by following the redirect on
|
||||
# the /releases/latest page — no API call, no rate limit, no JSON to
|
||||
# parse on a dependency-free box.
|
||||
LATEST_URL="$(curl -fsSLI -o /dev/null -w '%{url_effective}' \
|
||||
https://github.com/actions/runner/releases/latest)" \
|
||||
|| die "could not resolve the latest actions/runner release"
|
||||
VERSION="${LATEST_URL##*/}"
|
||||
VERSION="${VERSION#v}"
|
||||
case "$VERSION" in
|
||||
""|*[!0-9.]*) die "could not parse a version from ${LATEST_URL}" ;;
|
||||
esac
|
||||
log "resolved latest actions/runner: ${VERSION}"
|
||||
fi
|
||||
URL="https://github.com/actions/runner/releases/download/v${VERSION}/actions-runner-linux-${ARCH}-${VERSION}.tar.gz"
|
||||
WORKDIR="$(mktemp -d)"
|
||||
cleanup() { rm -rf "$WORKDIR"; }
|
||||
|
|
|
|||
|
|
@ -286,6 +286,15 @@ Everything else about bootstrap is unchanged; `runner install`'s contract is
|
|||
untouched. Tests: +2 (`runner refuses tag:server`, `runner role parses /
|
||||
refuses non-root`) → 27 non-root.
|
||||
|
||||
Second amendment (same day): `runner install --version` becomes **optional**
|
||||
— omitted, rig resolves the latest release at install time by following the
|
||||
`releases/latest` redirect (no API, no rate limit, no JSON parsing; validated
|
||||
against a digits-and-dots pattern before use). Safe here, and only here,
|
||||
because the runner self-updates regardless of what you install; `coolify
|
||||
install` keeps its mandatory pin — Coolify never self-updates, so its version
|
||||
is a verified contract, not a starting point. The `version required` test is
|
||||
replaced by a `--version needs a value` test → still 27 non-root.
|
||||
|
||||
## Integration (orchestrator, after final review — not an SDD task)
|
||||
|
||||
1. Push the branch to the fork and open the PR **against upstream**:
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fi
|
|||
check "bare runner shows usage, exit 2" 2 "usage:" "$ROOT/bin/rig" runner
|
||||
check "runner: --help exits 0" 0 "usage:" "$ROOT/commands/runner-install.sh" --help
|
||||
check "runner: repo required, exit 2" 2 "--repo" "$ROOT/commands/runner-install.sh" --version 2.335.1
|
||||
check "runner: version required, exit 2" 2 "--version" "$ROOT/commands/runner-install.sh" --repo acme/widgets
|
||||
check "runner: version needs value" 2 "needs a value" "$ROOT/commands/runner-install.sh" --repo acme/widgets --version
|
||||
check "runner: repo needs value" 2 "needs a value" "$ROOT/commands/runner-install.sh" --repo
|
||||
check "runner: rejects bad repo slug" 2 "owner/repo" "$ROOT/commands/runner-install.sh" --repo not-a-slug --version 2.335.1
|
||||
check "runner: refuses --user root" 2 "must not be root" "$ROOT/commands/runner-install.sh" --repo acme/widgets --version 2.335.1 --user root
|
||||
|
|
|
|||
Loading…
Reference in a new issue