# shellcheck shell=bash # Shared helpers for Castopod ops on koopa — fail fast, never hang forever. set -euo pipefail # --- defaults (override via env) --- : "${CP_BASEURL:=https://castopod.hacktivism.ch}" : "${CP_COMPOSE_DIR:=/home/hernani/koopa-castopod}" : "${CP_CONNECT_TIMEOUT:=10}" # seconds — TCP connect : "${CP_MAX_TIME:=120}" # seconds — whole HTTP transfer : "${CP_PULL_TIMEOUT:=600}" # seconds — image pull : "${CP_HEALTH_TRIES:=30}" # health poll attempts : "${CP_HEALTH_SLEEP:=5}" # seconds between polls # curl that cannot hang forever cp_curl() { curl -sS \ --connect-timeout "${CP_CONNECT_TIMEOUT}" \ --max-time "${CP_MAX_TIME}" \ --retry 2 \ --retry-delay 2 \ --retry-connrefused \ "$@" } # HTTP status only (no hang) cp_http_code() { local url=$1 cp_curl -o /dev/null -w '%{http_code}' "$url" || echo "000" } # Run command with hard wall-clock limit (GNU coreutils timeout) cp_timeout() { local secs=$1 shift if command -v timeout >/dev/null 2>&1; then timeout --signal=TERM --kill-after=15s "${secs}" "$@" else # fallback: no timeout binary — still run, but warn echo "WARN: timeout(1) missing; running without wall limit: $*" >&2 "$@" fi } # Non-interactive answer stream for spark / CLI that prompts [y,n] or passwords. # Usage: cp_yes | podman exec -i … php spark … # Prefer SQL for activate when possible (spark prompts hang without TTY). cp_yes() { # enough y's for a few prompts; never block waiting for input yes y 2>/dev/null | head -n 20 } # Poll until URL returns expected code or give up cp_wait_http() { local url=$1 local want=${2:-200} local i code for ((i = 1; i <= CP_HEALTH_TRIES; i++)); do code=$(cp_http_code "$url") echo "health try $i/${CP_HEALTH_TRIES}: $url → $code" if [[ "$code" == "$want" || "$code" =~ ^[23] ]]; then return 0 fi sleep "${CP_HEALTH_SLEEP}" done echo "ERROR: $url still not healthy after ${CP_HEALTH_TRIES} tries (last=$code)" >&2 return 1 } # MariaDB password from compose .env (no hang if missing) cp_mysql_password() { local envf="${CP_COMPOSE_DIR}/.env" [[ -f "$envf" ]] || { echo "ERROR: missing $envf" >&2; return 1; } # shellcheck disable=SC1090 grep -E '^MYSQL_PASSWORD=' "$envf" | head -1 | cut -d= -f2- } cp_mysql() { local pw pw=$(cp_mysql_password) podman exec koopa-castopod-mariadb \ mariadb -ucastopod -p"$pw" castopod "$@" } # Activate shield users without spark interactive prompt cp_activate_users() { cp_mysql -e "UPDATE cp_users SET active=1 WHERE username IN ('admin','ngi');" } # Session login for admin UI automation (uses users.env) cp_admin_login() { local cookie=${1:-/tmp/cp-cj} local envf="${CP_COMPOSE_DIR}/users.env" [[ -f "$envf" ]] || { echo "ERROR: missing $envf" >&2; return 1; } # shellcheck disable=SC1090 source "$envf" [[ -n "${ADMIN_PW:-}" ]] || { echo "ERROR: ADMIN_PW empty" >&2; return 1; } rm -f "$cookie" cp_curl -c "$cookie" -b "$cookie" "${CP_BASEURL}/cp-auth/login" -o /tmp/cp-login.html local csrf csrf=$(sed -n 's/.*name="csrf_test_name" value="\([^"]*\)".*/\1/p' /tmp/cp-login.html | head -1) [[ -n "$csrf" ]] || { echo "ERROR: no CSRF on login page" >&2; return 1; } local code code=$(cp_curl -c "$cookie" -b "$cookie" -o /dev/null -w '%{http_code}' \ -X POST "${CP_BASEURL}/cp-auth/login" \ --data-urlencode "csrf_test_name=${csrf}" \ --data-urlencode "email=admin@castopod.hacktivism.ch" \ --data-urlencode "password=${ADMIN_PW}") # 303 see other is success if [[ "$code" != "303" && "$code" != "302" && "$code" != "200" ]]; then echo "ERROR: login HTTP $code" >&2 return 1 fi }