#!/usr/bin/env bash # PhysioSuite, step 0: get the installer of one release, checked, before anything runs (decision 45). # Served at https://get.astrealab.ai/physiosuite/install.sh, beside the product's page at /physiosuite/; the release # job fills in the three @…@ values below. # # curl -fsSL https://get.astrealab.ai/physiosuite/install.sh -o install.sh # sudo bash install.sh on the application server: the setup page starts # sudo bash install.sh nas on a data server, over SSH (the setup page's step 4 gives the command) # sudo bash install.sh --version v0.1.0 … another release than the one this script came with # bash install.sh --download-only download and check only, then say where the folder is # # The release's deploy folder comes as one archive, with a list of checksums (SHA256SUMS) and Astrea's signature # of that list (SHA256SUMS.gpg), as Ubuntu publishes its own downloads. The signature is checked against Astrea's # public key, written into this script, and the archive against the list; only then is it unpacked, into # ./physiosuite- beside this script, and its installer run. A download that fails either check is # deleted and nothing runs. set -euo pipefail RELEASE="v0.1.0" # the release this script was published with: the default FINGERPRINT="22380CCB56872AD05807ABC01ADAC65F0D4F070B" # Astrea's release signing key KEYRING="mDMEavW9qxYJKwYBBAHaRw8BAQdAsntWTMy5B+TuEA0VHAfdO7/bZDkYmC9cVO21uuulcC20M0FzdHJlYSBQaHlzaW9TdWl0ZSByZWxlYXNlcyA8cmVsZWFzZXNAYXN0cmVhbGFiLmFpPoiQBBMWCgA4FiEEIjgMy1aHKtBYB6vAGtrGXw1PBwsFAmr1vasCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQGtrGXw1PBwsuDQEAxNz2szCuinWiIST7HCIaJknInpQgERkgGOEOkCsk7OkBALX94uuvlPVuH+jrlNRu8bFObD9XX+EWPP0lZ/zG6NUA" # that key: a binary OpenPGP keyring, in base64 GET_URL="${PHYSIOSUITE_GET_URL:-https://get.astrealab.ai/physiosuite}" # test benches only # Where nothing the person can do will help, the same last line as the installer's (physiosuite.sh, SUPPORT). SUPPORT="If it fails the same way again, send the lines above to support@astrealab.ai." R=$'\e[31m'; G=$'\e[32m'; D=$'\e[2m'; N=$'\e[0m' ok() { echo " ${G}✔${N} $*"; } note() { echo " ${D}$*${N}"; } fail() { echo " ${R}✖${N} $*" >&2; exit 1; } version=$RELEASE only="" args=() while [ $# -gt 0 ]; do case $1 in --version) [ $# -ge 2 ] || fail "--version needs a release, such as $RELEASE."; version=$2; shift 2 ;; --version=*) version=${1#--version=}; shift ;; --download-only) only=yes; shift ;; -h|--help) sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) args+=("$1"); shift ;; esac done [ ${#args[@]} -gt 0 ] || args=(setup) # A release name is exactly vMAJOR.MINOR.PATCH: it becomes part of an address and of a folder name. [[ $version =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "\"$version\" is not a release name, such as $RELEASE." [ -n "$only" ] || [ "$(id -u)" = 0 ] || fail "Run it with sudo: the installer sets up Docker containers and root-only files." for tool in curl tar gzip sha256sum base64; do pkg=$tool; case $tool in sha256sum|base64) pkg=coreutils ;; esac command -v "$tool" >/dev/null 2>&1 \ || fail "$tool is needed and is not on this server. Install it (sudo apt install $pkg), then run this again." done # The signature checker: gpgv on Ubuntu (apt depends on it), sqv on Debian 13 (apt's own checker there). if command -v gpgv >/dev/null 2>&1; then checker=gpgv elif command -v sqv >/dev/null 2>&1; then checker=sqv else fail "No signature checker here: install gpgv (sudo apt install gpgv), then run this again." fi dest="$PWD/physiosuite-$version" work=$(mktemp -d "$PWD/.physiosuite-download.XXXXXX") trap 'rm -rf "$work"' EXIT echo "PhysioSuite $version" # Downloads: HTTPS only (the bench's own address aside), failing on any error answer. A failure is told by curl's exit # code: 22 is an error answer from the site (its HTTP code says which), any other is the site not reached. proto=(--proto '=https' --tlsv1.2); [ -z "${PHYSIOSUITE_GET_URL:-}" ] || proto=() site=${GET_URL#*://}; site=${site%%/*} for f in SHA256SUMS SHA256SUMS.gpg "physiosuite-$version.tar.gz"; do rc=0 code=$(curl -fsSL "${proto[@]}" --retry 3 -w '%{http_code}' -o "$work/$f" "$GET_URL/$version/$f" 2>"$work/curl.log") || rc=$? [ "$rc" = 0 ] && continue if [ "$rc" = 22 ] && [ "$code" = 404 ] && [ "$f" = SHA256SUMS ]; then fail "PhysioSuite $version is not a published release. Check the release name at $GET_URL/, then run this again." elif [ "$rc" = 22 ] && [ "$code" = 404 ]; then fail "PhysioSuite $version has no $f at $GET_URL/$version/: the release is incomplete, and nothing was installed. $SUPPORT" elif [ "$rc" = 22 ]; then fail "$site answered HTTP $code for $f, and nothing was installed. Run this again in a few minutes. $SUPPORT" fi fail "Could not reach $site: $(tail -n 1 "$work/curl.log" | sed 's/^curl: ([0-9]*) //'). Check that this server can reach the internet on port 443, then run this again." done ok "Downloaded physiosuite-$version.tar.gz ($(( $(wc -c < "$work/physiosuite-$version.tar.gz") / 1024 )) KB)" # 1. The list of checksums is Astrea's: its signature, against the one key written into this script. base64 -d > "$work/astrea-release.gpg" <<<"$KEYRING" mkdir -m 700 "$work/gnupg" not_signed="The signature does not match Astrea's key: nothing was installed. The download may have been changed on the way: do not use it. Download install.sh again from $GET_URL/ and run it once more. $SUPPORT" if [ "$checker" = gpgv ]; then gpgv --homedir "$work/gnupg" --keyring "$work/astrea-release.gpg" "$work/SHA256SUMS.gpg" "$work/SHA256SUMS" \ >"$work/check.log" 2>&1 || { sed 's/^/ /' "$work/check.log" >&2; fail "$not_signed"; } else sqv --keyring "$work/astrea-release.gpg" --signature-file "$work/SHA256SUMS.gpg" "$work/SHA256SUMS" \ >"$work/check.log" 2>&1 || { sed 's/^/ /' "$work/check.log" >&2; fail "$not_signed"; } fi ok "Signed by Astrea's release key ${FINGERPRINT: -16} (checked with $checker)" # 2. The archive is the one in that list. line=$(grep -E "^[0-9a-f]{64} physiosuite-$version\.tar\.gz$" "$work/SHA256SUMS" || true) [ -n "$line" ] || fail "The signed list does not name physiosuite-$version.tar.gz: nothing was installed. Download install.sh again from $GET_URL/ and run it once more. $SUPPORT" (cd "$work" && sha256sum --check --strict --quiet <<<"$line") \ || fail "physiosuite-$version.tar.gz is not the file Astrea signed: nothing was installed. It was damaged or changed on the way: run this again for a fresh download. $SUPPORT" ok "The archive matches the signed checksum" # 3. Unpacked beside this script, replacing only a folder this script unpacked before. mkdir "$work/unpacked" tar -xzf "$work/physiosuite-$version.tar.gz" -C "$work/unpacked" --no-same-owner 2>"$work/tar.log" \ || fail "The archive could not be unpacked: $(grep -m 1 . "$work/tar.log"). Nothing was installed. Check the free disk here (df -h .), then run this again." [ -f "$work/unpacked/deploy/install/physiosuite.sh" ] \ || fail "The archive holds no installer: nothing was installed. The release is incomplete. $SUPPORT" printf '%s\n' "$version" "${line%% *}" > "$work/unpacked/.physiosuite-release" if [ -e "$dest" ]; then [ -f "$dest/.physiosuite-release" ] || fail "$dest exists and was not unpacked by this script; move it away first." rm -rf "$dest" fi mv "$work/unpacked" "$dest" ok "Unpacked: $dest" if [ -n "$only" ]; then note "Next, as root: bash $dest/deploy/install/physiosuite.sh setup (or nas, on a data server)" exit 0 fi rm -rf "$work"; trap - EXIT # exec below leaves this script for good, so the download folder goes first echo exec bash "$dest/deploy/install/physiosuite.sh" "${args[@]}"