#!/usr/bin/env bash # ----------------------------------------------------------------------------- # checks/tools.sh — every required host tool is present and >= its VERSIONS pin. # Reads TOOL__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 : 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 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"