Files
urania cad6c1f421
build-and-release / release (push) Successful in 2m32s
fix: install sh
2026-06-25 20:42:05 +02:00

113 lines
3.9 KiB
Cheetah

#!/bin/sh
set -e
# Nadir bootstrap installer.
#
# Detects the host architecture, fetches the latest release asset from the
# Gitea releases API, and installs it as a systemd service:
#
# curl -fsSL https://<existing-nadir-host>:<port>/install.sh | sudo sh
#
# The binary always comes from the Gitea release (not the source instance),
# so the installed copy is guaranteed to be the latest tagged build,
# independent of whatever version the serving host happens to be running.
#
# Everything is wrapped in do_install and invoked on the last line, the same
# pattern get.docker.com uses: when piped via `curl | sh`, sh executes while
# still receiving bytes from the network. Defining the whole body as a
# function before running anything means sh has fully parsed the script
# before do_install ever runs.
# Where to look for releases. Substituted at request time by the server
# (cmd/server/server.go) so the script knows which Gitea instance owns
# this deployment. Example: https://gitea.example.com/urania/nadir
RELEASE_REPO="__NADIR_RELEASE_REPO__"
do_install() {
if [ "$(id -u)" -ne 0 ]; then
echo "this script must be run as root (try piping through 'sudo sh')" >&2
exit 1
fi
if ! command -v curl >/dev/null 2>&1; then
echo "curl is required" >&2
exit 1
fi
case "$(uname -m)" in
x86_64|amd64) arch=amd64 ;;
aarch64|arm64) arch=arm64 ;;
*) echo "unsupported architecture: $(uname -m) (only amd64 and arm64 are built)" >&2; exit 1 ;;
esac
api="$RELEASE_REPO/releases/latest"
api="${api%/}"
# Convert https://host/owner/repo/releases/latest into Gitea API form.
# Splits the URL once on '/' between host and path, inserts /api/v1/repos.
host=$(echo "$RELEASE_REPO" | awk -F/ '{print $1"//"$3}')
path=$(echo "$RELEASE_REPO" | awk -F/ '{print $4"/"$5}')
api="$host/api/v1/repos/$path/releases/latest"
echo "querying $api ..."
asset_url=$(curl -fsSL "$api" \
| grep -o '"browser_download_url":"[^"]*linux-'"$arch"'"' \
| head -n1 \
| cut -d'"' -f4)
if [ -z "$asset_url" ]; then
echo "no linux-$arch asset found in the latest release at $api" >&2
exit 1
fi
echo "downloading $asset_url ..."
curl -f --progress-bar -L "$asset_url" -o /usr/local/bin/nadir.tmp
asset_name=$(basename "$asset_url")
# Verify SHA-256: download the checksums file published alongside the binary
# and confirm the hash matches. This catches CDN corruption and (together with
# the HTTPS transport) makes tampered binaries detectable.
sums_url="$host/api/v1/repos/$path/releases/latest"
sums_asset_url=$(curl -fsSL "$sums_url" \
| grep -o '"browser_download_url":"[^"]*sha256sums\.txt"' \
| head -n1 \
| cut -d'"' -f4)
if [ -n "$sums_asset_url" ]; then
echo "verifying checksum ..."
curl -fsSL "$sums_asset_url" -o /tmp/nadir-sha256sums.txt
# Extract the expected hash for our asset and compare.
expected=$(grep "$asset_name" /tmp/nadir-sha256sums.txt | awk '{print $1}')
actual=$(sha256sum /usr/local/bin/nadir.tmp | awk '{print $1}')
rm -f /tmp/nadir-sha256sums.txt
if [ -z "$expected" ]; then
echo "warning: sha256sums.txt does not contain a hash for $asset_name" >&2
echo "proceeding without verification" >&2
elif [ "$expected" != "$actual" ]; then
echo "SHA-256 MISMATCH: expected $expected, got $actual" >&2
echo "the downloaded binary may be corrupted or tampered with — aborting" >&2
rm -f /usr/local/bin/nadir.tmp
exit 1
else
echo "checksum OK ($actual)"
fi
else
echo "warning: no sha256sums.txt in release — skipping verification" >&2
fi
mv /usr/local/bin/nadir.tmp /usr/local/bin/nadir
chmod +x /usr/local/bin/nadir
echo "binary installed at /usr/local/bin/nadir"
echo "installing as a systemd service ..."
if [ -c /dev/tty ]; then
/usr/local/bin/nadir install < /dev/tty
else
/usr/local/bin/nadir install
fi
echo
echo "done. check status with: nadir status"
}
do_install