forked from heavy-duty/rig
79 lines
3.3 KiB
Bash
79 lines
3.3 KiB
Bash
|
|
#!/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}"
|