scripts/test-install-cli.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# CLI contract for the binary installer. No root, no host changes.
set -euo pipefail
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
cd "$ROOT"
failed=0
pass() { printf 'ok %s\n' "$*"; }
fail() { printf 'not ok %s\n' "$*" >&2; failed=1; }
cli_home=$(mktemp -d)
mkdir -p "$cli_home/bin" "$cli_home/.firecrab"
printf 'binary\n' >"$cli_home/bin/firecrab"
printf 'helper\n' >"$cli_home/bin/firecrab-micromanager-macos"
printf 'current_host = "lab"\n' >"$cli_home/.firecrab/config.toml"
HOME="$cli_home" sh ./install-cli.sh --install-dir "$cli_home/bin" --uninstall >/dev/null
if [ ! -e "$cli_home/bin/firecrab" ] \
&& [ ! -e "$cli_home/bin/firecrab-micromanager-macos" ] \
&& [ -e "$cli_home/.firecrab/config.toml" ]; then
pass "install-cli.sh --uninstall removes binaries and keeps config"
else
fail "install-cli.sh --uninstall removes binaries and keeps config"
fi
printf 'binary\n' >"$cli_home/bin/firecrab"
printf 'helper\n' >"$cli_home/bin/firecrab-micromanager-macos"
HOME="$cli_home" sh ./install-cli.sh --install-dir "$cli_home/bin" --uninstall --purge >/dev/null
if [ ! -e "$cli_home/bin/firecrab" ] \
&& [ ! -e "$cli_home/bin/firecrab-micromanager-macos" ] \
&& [ ! -e "$cli_home/.firecrab/config.toml" ]; then
pass "install-cli.sh --uninstall --purge removes binaries and config"
else
fail "install-cli.sh --uninstall --purge removes binaries and config"
fi
rm -rf "$cli_home"
help=$("./install.sh" --help)
if printf '%s\n' "$help" | grep -q -- '--with-pipe'; then
pass "--help documents optional pipe engines"
else
fail "--help documents optional pipe engines"
fi
if ./install.sh --deps-only --with-pipe >"$cli_home-pipe-error" 2>&1; then
fail "--with-pipe rejects dependency-only mode"
elif grep -q -- '--with-pipe is supported with installation or --check' "$cli_home-pipe-error"; then
pass "--with-pipe rejects dependency-only mode before host changes"
else
fail "--with-pipe mode rejection has no clear error"
fi
rm -f "$cli_home-pipe-error"
cli_help=$(sh ./install-cli.sh --help)
if printf '%s\n' "$cli_help" | grep -q -- '--uninstall' \
&& printf '%s\n' "$cli_help" | grep -q -- '--purge'; then
pass "CLI installer help documents uninstall and purge"
else
fail "CLI installer help documents uninstall and purge"
fi
if sh ./install-cli.sh --purge >/dev/null 2>&1; then
fail "install-cli.sh rejects --purge without --uninstall"
else
pass "install-cli.sh rejects --purge without --uninstall"
fi
if printf '%s\n' "$help" | grep -q -- '--bin-dir'; then
pass "--help mentions --bin-dir"
else
fail "--help mentions --bin-dir"
fi
if printf '%s\n' "$help" | grep -q -- '--libc'; then
pass "--help mentions --libc"
else
fail "--help mentions --libc"
fi
if printf '%s\n' "$help" | grep -q 'firecrab-host-x86_64-gnu.tar.gz' \
&& printf '%s\n' "$help" | grep -q 'firecrab-host-aarch64-musl.tar.gz'; then
pass "--help lists gnu and musl host bundles"
else
fail "--help lists gnu and musl host bundles"
fi
if printf '%s\n' "$help" | grep -q -- '--version'; then
pass "--help mentions --version"
else
fail "--help mentions --version"
fi
if printf '%s\n' "$help" | grep -q 'releases/latest/download/install.sh'; then
pass "--help shows the release install URL"
else
fail "--help shows the release install URL"
fi
if printf '%s\n' "$help" | grep -qi 'cargo build'; then
fail "--help must not tell operators to cargo build as the default"
else
pass "--help does not default to cargo build"
fi
got=$("./install.sh" --print-install-url)
want='curl -fsSL https://github.com/SteelCrab/firecrab/releases/latest/download/install.sh | bash'
if [ "$got" = "$want" ]; then
pass "--print-install-url (latest)"
else
fail "--print-install-url (got '$got')"
fi
got=$("./install.sh" --version v0.1.0 --print-install-url)
want='curl -fsSL https://github.com/SteelCrab/firecrab/releases/download/v0.1.0/install.sh | bash'
if [ "$got" = "$want" ]; then
pass "--print-install-url (v0.1.0)"
else
fail "--print-install-url v0.1.0 (got '$got')"
fi
got=$("./install.sh" --version v0.1.0 --libc gnu --print-release-url)
# shellcheck source=firecrab-release.sh
. "$ROOT/scripts/firecrab-release.sh"
want=$(firecrab_release_asset_url v0.1.0 "$(firecrab_host_tarball "" gnu)")
if [ "$got" = "$want" ]; then
pass "--print-release-url matches helper"
else
fail "--print-release-url (got '$got', want '$want')"
fi
check=$("./install.sh" --check 2>&1 || true)
if printf '%s\n' "$check" | grep -q 'would download'; then
pass "--check talks about downloading a release"
else
fail "--check talks about downloading a release"
fi
if printf '%s\n' "$check" | grep -q 'would install via rustup'; then
fail "--check must not offer rustup"
else
pass "--check does not offer rustup"
fi
bindir=$(mktemp -d)
check_dir=$("./install.sh" --bin-dir "$bindir" --check 2>&1 || true)
rmdir "$bindir"
if printf '%s\n' "$check_dir" | grep -q -- "$bindir"; then
pass "--check --bin-dir mentions the directory"
else
fail "--check --bin-dir mentions the directory"
fi
# --- published install.sh (helpers inlined, tag baked) ----------------------
pub=$(mktemp -d)
"$ROOT/scripts/bake-install-sh.sh" v0.1.0 "$pub/install.sh"
got=$("$pub/install.sh" --print-install-url)
want='curl -fsSL https://github.com/SteelCrab/firecrab/releases/download/v0.1.0/install.sh | bash'
if [ "$got" = "$want" ]; then
pass "baked install.sh pins the tag in the curl URL"
else
fail "baked install.sh pins the tag (got '$got')"
fi
# Host install prepares the host only; guest images come from OCI import.
piped_check=$(cd /tmp && bash -s -- --check --no-deps <"$pub/install.sh" 2>&1 || true)
if printf '%s\n' "$piped_check" | grep -q 'BASH_SOURCE'; then
fail "baked --check via stdin must not crash on BASH_SOURCE"
else
pass "baked --check via stdin does not crash on BASH_SOURCE"
fi
# The advertised one-liner is `curl … | bash`. That leaves BASH_SOURCE unset.
# A production change that re-reads ${BASH_SOURCE[0]} under `set -u` must fail.
piped_out=$(mktemp)
piped_err=$(mktemp)
if (cd /tmp && bash -s -- --print-install-url <"$pub/install.sh" >"$piped_out" 2>"$piped_err"); then
got=$(cat "$piped_out")
if [ "$got" = "$want" ]; then
pass "baked install.sh works when piped to bash (curl | bash)"
else
fail "baked install.sh piped (got '$got')"
fi
else
fail "baked install.sh piped (exit $?, stderr: $(tr '\n' ' ' <"$piped_err"))"
fi
# `bash <(curl …)` sets BASH_SOURCE to /dev/fd/N — not a checkout.
if got=$(cd /tmp && bash <(cat "$pub/install.sh") --print-install-url); then
if [ "$got" = "$want" ]; then
pass "baked install.sh works under process substitution"
else
fail "baked install.sh process substitution (got '$got')"
fi
else
fail "baked install.sh process substitution (exit $?)"
fi
# The unbaked repo copy still needs scripts/ next to it. The failure must
# be that message, not an unbound BASH_SOURCE crash.
if (cd /tmp && bash -s -- --print-install-url <"$ROOT/install.sh" >"$piped_out" 2>"$piped_err"); then
fail "repo install.sh piped from /tmp should not succeed"
elif grep -q 'BASH_SOURCE' "$piped_err"; then
fail "repo install.sh piped from /tmp still crashes on BASH_SOURCE"
elif grep -q 'release helpers missing' "$piped_err"; then
pass "repo install.sh piped outside a checkout explains missing helpers"
else
fail "repo install.sh piped from /tmp (stderr: $(tr '\n' ' ' <"$piped_err"))"
fi
# curl | bash has no stdin tty. The installer must prompt on /dev/tty,
# not tell the operator to run `sudo -v` themselves.
if [ "$(uname -s)" = Linux ] && [ "$(id -u)" -ne 0 ] && command -v script >/dev/null 2>&1; then
fake=$(mktemp -d)
cat >"$fake/sudo" <<'EOF'
#!/bin/bash
printf '%s\n' "$*" >>"${SUDO_LOG:?}"
if [ "$1" = "-n" ]; then
exit 1
fi
if [ "$1" = "-v" ]; then
if [ -t 0 ]; then
printf 'tty\n' >>"$SUDO_LOG"
exit 0
fi
printf 'notty\n' >>"$SUDO_LOG"
exit 1
fi
exit 0
EOF
chmod +x "$fake/sudo"
: >"$fake/log"
if SUDO_LOG="$fake/log" PATH="$fake:$PATH" \
script -q -e -c "bash -s -- --uninstall <'$pub/install.sh'" /dev/null \
>"$piped_out" 2>"$piped_err"; then
if grep -q 'Run: sudo -v' "$piped_out" "$piped_err"; then
fail "piped install.sh must not tell the operator to run sudo -v"
elif grep -qx tty "$fake/log"; then
pass "piped install.sh asks sudo on /dev/tty"
else
fail "piped install.sh did not prompt sudo on a tty (log: $(tr '\n' ' ' <"$fake/log"))"
fi
else
fail "piped --uninstall via /dev/tty (out: $(tr '\n' ' ' <"$piped_out") err: $(tr '\n' ' ' <"$piped_err"))"
fi
rm -rf "$fake"
else
pass "piped sudo tty prompt skipped (root or no script(1))"
fi
rm -f "$piped_out" "$piped_err"
# FireCrab installs the upstream Firecracker binary from its official release
# archive. That installer must preserve the exact LICENSE/NOTICE/THIRD-PARTY
# files shipped beside the binary and reject an incomplete release archive.
if bash "$ROOT/scripts/test-install-firecracker.sh"; then
pass "Firecracker release notices are preserved"
else
fail "Firecracker release notices are preserved"
fi
# --- host tarball layout ----------------------------------------------------
write_elf64() {
local dest=$1 machine=$2
python3 - "$dest" "$machine" <<'PY'
import sys
path, machine = sys.argv[1], int(sys.argv[2])
header = bytearray(64)
header[0:4] = b"\x7fELF"
header[4] = 2
header[5] = 1
header[6] = 1
header[18:20] = machine.to_bytes(2, "little")
open(path, "wb").write(header)
PY
chmod +x "$dest"
}
fake=$(mktemp -d)
write_elf64 "$fake/firecrab-api" 62
write_elf64 "$fake/firecrab-helper" 62
write_elf64 "$fake/firecrab" 62
write_elf64 "$fake/firecrab-ingress" 62
mkdir -p "$fake/ingress"
for name in LICENSE.nginx LICENSE.pcre2 LICENSE.musl sources.json; do
printf 'fixture\n' >"$fake/ingress/$name"
done
mkdir -p "$fake/dist"
printf '<html></html>\n' >"$fake/dist/index.html"
"$ROOT/scripts/package-host-release.sh" x86_64 "$fake" "$fake/dist" "$fake/firecrab-host-x86_64.tar.gz" >/dev/null
members=$(tar -tzf "$fake/firecrab-host-x86_64.tar.gz")
for need in firecrab-api firecrab-helper extract-vmlinux extract-arm64-image \
firecrab firecrab-ingress ingress/LICENSE.nginx dashboard/index.html systemd/firecrab-api.service \
systemd/firecrab-helper.service; do
if printf '%s\n' "$members" | grep -qx -- "$need"; then
pass "host tarball contains $need"
else
fail "host tarball contains $need"
fi
done
wrong=$(mktemp -d)
write_elf64 "$wrong/firecrab-api" 183
write_elf64 "$wrong/firecrab-helper" 183
write_elf64 "$wrong/firecrab" 183
mkdir -p "$wrong/dist"
printf '<html></html>\n' >"$wrong/dist/index.html"
if "$ROOT/scripts/package-host-release.sh" x86_64 "$wrong" "$wrong/dist" "$wrong/out.tar.gz" >/dev/null 2>&1; then
fail "host tarball rejects aarch64 bins packed as x86_64"
else
pass "host tarball rejects aarch64 bins packed as x86_64"
fi
rm -rf "$pub" "$fake" "$wrong"
if [ "$failed" -ne 0 ]; then
printf 'FAILED\n' >&2
exit 1
fi
printf 'all tests passed\n'