Ctrl K
ComunidadGuías…

scripts/test-install-cli.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/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'