#!/usr/bin/env bash # ci-box — the forgejo-runner binary. Run BY THE MECHANISM as root, with # TENANT_USER/TENANT_HOME/TENANT_GROUP/ROLE exported. # # This lands the BINARY ONLY. Registration is deliberately not here: it needs a # short-lived token from the Forgejo instance, and a tenant install is # creds-free by contract — box auto-runs it at mint, holding nothing. The # operator registers afterwards, out loud: # # box shell ci-box # sudo rig forgejo-runner install --instance https://forgejo.example.com # # Same split as staging-box's tailnet join, for the same reason. # # Root-owned under /usr/local/bin rather than the tenant's home: unlike an # agent CLI, this binary is run by a systemd unit as the tenant user, and a # tenant-writable binary that root's unit executes is a trivial path to root # inside the box. set -euo pipefail BIN=/usr/local/bin/forgejo-runner if [ -x "$BIN" ]; then exit 0 fi case "$(uname -m)" in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; *) echo "ci-box install: unsupported arch: $(uname -m)" >&2; exit 1 ;; esac # The latest release, resolved by following the releases/latest redirect — no # API call, no token, no JSON to parse on a dependency-free guest. A pinned # version belongs to `rig forgejo-runner install --version`, which is where an # operator who needs a deterministic install already is; a pin baked into the # registry would go stale in a repo nobody watches. LATEST_URL="$(curl -fsSLI -o /dev/null -w '%{url_effective}' \ https://code.forgejo.org/forgejo/runner/releases/latest)" \ || { echo "ci-box install: could not resolve the latest forgejo-runner release" >&2; exit 1; } VERSION="${LATEST_URL##*/}" VERSION="${VERSION#v}" case "$VERSION" in ""|*[!0-9.]*) echo "ci-box install: could not parse a version from ${LATEST_URL}" >&2; exit 1 ;; esac ASSET="forgejo-runner-${VERSION}-linux-${ARCH}" URL="https://code.forgejo.org/forgejo/runner/releases/download/v${VERSION}/${ASSET}" WORKDIR="$(mktemp -d)" cleanup() { rm -rf "$WORKDIR"; } trap cleanup EXIT echo "ci-box install: downloading forgejo-runner ${VERSION} (${ARCH})" curl -fsSL "$URL" -o "$WORKDIR/forgejo-runner" \ || { echo "ci-box install: could not download ${URL}" >&2; exit 1; } # Forgejo publishes a .sha256 beside each binary. Verifying it costs one # request and makes the install auditable; this file executes as root inside # every future mint, so an unverified download is the last thing it should do. if curl -fsSL "${URL}.sha256" -o "$WORKDIR/forgejo-runner.sha256" 2>/dev/null; then WANT="$(tr -d '\r' < "$WORKDIR/forgejo-runner.sha256" | awk '{print $1}' | head -n1)" GOT="$(sha256sum "$WORKDIR/forgejo-runner" | awk '{print $1}')" if [ -z "$WANT" ]; then echo "ci-box install: the published checksum for ${ASSET} is unreadable — refusing to install an unverified binary" >&2 exit 1 fi if [ "$WANT" != "$GOT" ]; then echo "ci-box install: checksum mismatch for ${ASSET}: published ${WANT}, downloaded ${GOT} — refusing to install" >&2 exit 1 fi echo "ci-box install: checksum verified (${GOT})" else echo "ci-box install: WARNING: no published .sha256 for ${ASSET} — installing WITHOUT checksum verification" >&2 fi install -m 0755 -o root -g root "$WORKDIR/forgejo-runner" "$BIN" echo "ci-box install: installed ${BIN}"