foundation/preflight/checks/tools.sh

90 lines
4.1 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# checks/tools.sh — every required host tool is present and >= its VERSIONS pin.
# Reads TOOL_<X>_MIN from foundation/VERSIONS (PLAN-002 §9.1 host validation).
# Exits non-zero if any required tool is missing or below its minimum.
# -----------------------------------------------------------------------------
set -euo pipefail
PF_DIR=$(cd "$(dirname "$0")/.." && pwd)
# shellcheck source=../lib/common.sh
. "$PF_DIR/lib/common.sh"
echo "[tools] required host tools present and >= VERSIONS pin"
# pf_get_version <tool> : echo a parseable version string for the tool, or "".
# Kept in one place so the per-tool quirks are visible and testable.
pf_get_version() {
case "$1" in
pulumi) pulumi version 2>/dev/null ;; # -> v3.243.0
bun) bun --version 2>/dev/null ;; # -> 1.3.9
node) node --version 2>/dev/null ;; # -> v24.10.0
docker) docker --version 2>/dev/null | sed 's/.*version //' ;; # Docker version 29.5.3, build ...
git) git --version 2>/dev/null ;; # git version 2.54.0
age) age --version 2>/dev/null ;; # v1.1.1 (or "1.1.1")
zstd) zstd --version 2>/dev/null | sed -n 's/.*[ vV]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/p' ;; # *** Zstandard CLI (64-bit) v1.5.7, ...
jq) jq --version 2>/dev/null ;; # jq-1.8.1
vault) vault --version 2>/dev/null ;; # Vault v1.18.0 (...)
psql) psql --version 2>/dev/null ;; # psql (PostgreSQL) 16.2
pg_dump) pg_dump --version 2>/dev/null ;; # pg_dump (PostgreSQL) 16.2
ssh) ssh -V 2>&1 ;; # OpenSSH_10.2p1, LibreSSL ...
mc) mc --version 2>/dev/null | head -1 ;; # mc version RELEASE.2025-08-13T08-35-41Z
*) printf '' ;;
esac
}
# pf_check_tool <bin> <VERSIONS_KEY> <pretty-name>
pf_check_tool() {
bin="$1"; key="$2"; pretty="$3"
min=$(pf_versions_get "$key" 2>/dev/null || true)
if [ -z "$min" ]; then
pf_fail "$pretty: no $key in VERSIONS (cannot determine minimum)"
return
fi
if ! pf_have "$bin"; then
pf_fail "$pretty ($bin): NOT INSTALLED (need >= $min)"
return
fi
raw=$(pf_get_version "$bin" || true)
# mc uses a date-stamped RELEASE.YYYY-MM-DD... tag; normalize to a dotted date.
if [ "$bin" = "mc" ]; then
norm=$(printf '%s' "$raw" | sed -n 's/.*RELEASE\.\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\).*/\1.\2.\3/p')
minn=$(printf '%s' "$min" | tr '-' '.')
if [ -z "$norm" ]; then
pf_warn "$pretty ($bin): present but version unparseable ('$raw'); assuming OK"
return
fi
if pf_ge "$norm" "$minn"; then
pf_pass "$pretty ($bin) $norm >= $min"
else
pf_fail "$pretty ($bin) $norm < required $min"
fi
return
fi
if [ -z "$raw" ]; then
pf_warn "$pretty ($bin): present but version unparseable; assuming OK"
return
fi
if pf_ge "$raw" "$min"; then
pf_pass "$pretty ($bin) $(printf '%s' "$raw" | sed -e 's/^[^0-9]*//' -e 's/[^0-9.].*$//') >= $min"
else
pf_fail "$pretty ($bin) '$raw' < required $min"
fi
}
# bin VERSIONS key pretty name
pf_check_tool pulumi TOOL_PULUMI_MIN "Pulumi"
pf_check_tool bun TOOL_BUN_MIN "Bun"
pf_check_tool node TOOL_NODE_MIN "Node.js"
pf_check_tool docker TOOL_DOCKER_MIN "Docker CLI"
pf_check_tool git TOOL_GIT_MIN "Git"
pf_check_tool age TOOL_AGE_MIN "age"
pf_check_tool zstd TOOL_ZSTD_MIN "zstd"
pf_check_tool jq TOOL_JQ_MIN "jq"
pf_check_tool vault TOOL_VAULT_MIN "Vault CLI"
pf_check_tool psql TOOL_PSQL_MIN "PostgreSQL client (psql)"
pf_check_tool pg_dump TOOL_PG_DUMP_MIN "PostgreSQL client (pg_dump)"
pf_check_tool ssh TOOL_OPENSSH_MIN "OpenSSH client"
pf_check_tool mc TOOL_MC_MIN "S3/RustFS client (mc)"
pf_summary "tools"