Files
Wanjohi d8e5c19181 release(nesdoctor): point the installers at v0.3.0
Flipped after publishing, so there was never a window where the live installer
named a tag that did not exist.

Verified before committing: all five assets under the new tag return 200, and
the installer was run end to end — it fetched the published binary, checked it
against SHA256SUMS, and the thing it ran reported 0.3.0.
2026-09-03 22:40:26 +03:00

130 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env sh
# nesdoctor installer — https://doctor.nestri.io/install.sh
#
# This file is the source of what that URL serves. It lives in the public
# repository so that anyone about to pipe it into a shell can read it first:
#
# https://github.com/nestrilabs/nestri/blob/dev/apps/nesdoctor/install/install.sh
#
# What it does, in order: work out your platform, download the matching
# nesdoctor binary from GitHub Releases, verify it against the published
# SHA256SUMS, run it, and delete it. It installs nothing permanently, touches
# no system directory, and never asks for sudo.
#
# What nesdoctor itself does is printed when it starts.
set -eu
REPO="nestrilabs/nestri"
# Pinned, and NOT `releases/latest`. This repository ships product releases as
# well as this tool, so `latest` is whatever went out most recently -- it
# resolved to a 2024 release while this was being written, and the day a
# product release goes out it would move again and every install here would
# 404. Bump this line when cutting a nesdoctor release; `NESDOCTOR_TAG`
# overrides it for testing.
DEFAULT_TAG="nesdoctor-v0.3.0"
TAG="${NESDOCTOR_TAG:-$DEFAULT_TAG}"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT INT TERM
say() { printf '%s\n' "$*" >&2; }
die() { printf 'error: %s\n' "$*" >&2; exit 1; }
# --- platform ---------------------------------------------------------------
case "$(uname -s)" in
Linux) os=linux ;;
Darwin) os=macos ;;
*) die "unsupported OS: $(uname -s). nesdoctor runs on Linux, macOS and Windows." ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch=x86_64 ;;
arm64|aarch64) arch=aarch64 ;;
*) die "unsupported architecture: $(uname -m)" ;;
esac
case "$os/$arch" in
linux/x86_64) target=x86_64-unknown-linux-musl ;;
macos/aarch64) target=aarch64-apple-darwin ;;
macos/x86_64) target=x86_64-apple-darwin ;;
linux/aarch64)
die "no aarch64 Linux build yet. Building from source takes a minute:
git clone --depth 1 https://github.com/$REPO && cd nestri
cargo run --release -p nesdoctor" ;;
*) die "no build for $os/$arch" ;;
esac
ASSET="nesdoctor-$target"
# --- fetch ------------------------------------------------------------------
# curl or wget, whichever is present. -f so an HTML error page is never
# mistaken for a binary.
if command -v curl >/dev/null 2>&1; then
get() { curl -fsSL "$1" -o "$2"; }
elif command -v wget >/dev/null 2>&1; then
get() { wget -qO "$2" "$1"; }
else
die "need curl or wget"
fi
BASE="https://github.com/$REPO/releases/download/$TAG"
say "Downloading nesdoctor ($target)…"
get "$BASE/$ASSET" "$TMP/$ASSET" || die "download failed: $BASE/$ASSET\n If $TAG is not published yet, that is why."
# --- verify -----------------------------------------------------------------
# A checksum we fetch from the same place as the binary is not a security
# boundary, and pretending otherwise would be worse than saying so: it catches
# a truncated or corrupted download, which is the failure that actually
# happens. The signed-release version of this is a later job.
if get "$BASE/SHA256SUMS" "$TMP/SHA256SUMS" 2>/dev/null; then
if command -v sha256sum >/dev/null 2>&1; then
have="$(sha256sum "$TMP/$ASSET" | cut -d' ' -f1)"
elif command -v shasum >/dev/null 2>&1; then
have="$(shasum -a 256 "$TMP/$ASSET" | cut -d' ' -f1)"
else
have=""
fi
if [ -n "$have" ]; then
want="$(grep -F "$ASSET" "$TMP/SHA256SUMS" | cut -d' ' -f1 | head -n1)"
[ -n "$want" ] || die "no checksum for $ASSET in SHA256SUMS"
[ "$have" = "$want" ] || die "checksum mismatch — do not run this file
expected $want
got $have"
say "Checksum OK."
else
say "No sha256 tool found; skipping verification."
fi
else
say "No SHA256SUMS published; skipping verification."
fi
# --- run --------------------------------------------------------------------
chmod +x "$TMP/$ASSET"
say ""
# Reopen stdin on the terminal before handing over.
#
# This matters more than it looks. When this script is run the documented way
# -- `curl -fsSL url | sh` -- the shell's stdin *is* the pipe, and the pipe is
# at end-of-file by the time we get here. nesdoctor inherits that, sees a
# non-terminal stdin, and correctly skips every question. The result is a run
# that completes, looks fine, and answers nothing: the exact failure the whole
# install path exists to avoid, and it would have been invisible in testing
# because running the script from a file works perfectly.
#
# /dev/tty is the controlling terminal regardless of what stdin was piped to.
# Where there is no terminal at all -- CI, a cron job -- the redirect fails and
# we run without it, which is the right behaviour rather than a fallback.
# The probe runs in a subshell on purpose. A failing redirection on `exec` is
# *fatal* to a non-interactive shell rather than merely non-zero, so testing it
# inline killed this script outright on any machine without a controlling
# terminal -- measured, not theorised. The parentheses contain that.
if [ -e /dev/tty ] && (exec 3</dev/tty) 2>/dev/null; then
exec "$TMP/$ASSET" "$@" < /dev/tty
else
say "(no terminal available, so the questions will be skipped)"
exec "$TMP/$ASSET" "$@"
fi