monitoring: taler-monitoring www/inside/sanity/server/e2e scaffold
This commit is contained in:
parent
fed083d0d5
commit
95499a7f59
11 changed files with 2828 additions and 0 deletions
255
scripts/taler-monitoring/check_urls.sh
Executable file
255
scripts/taler-monitoring/check_urls.sh
Executable file
|
|
@ -0,0 +1,255 @@
|
|||
#!/usr/bin/env bash
|
||||
# Outside-in public HTTPS checks (no SSH).
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
|
||||
# Area www-### — public HTTPS (outside-in)
|
||||
set_area www
|
||||
section "www · public URLs · ${TALER_DOMAIN:-?} (outside-in, no SSH)"
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
check_url() {
|
||||
local label="$1" expect="$2" url="$3"
|
||||
local code
|
||||
code=$(http_code "$url")
|
||||
case ",$expect," in
|
||||
*",$code,"*) ok "$label $url" ;;
|
||||
*) fail "$label $url" "got $code want $expect" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Soft check: OK on expect, WARN on foreign stack if down, ERROR on local stack
|
||||
check_url_soft() {
|
||||
local label="$1" expect="$2" url="$3"
|
||||
local code
|
||||
code=$(http_code "$url")
|
||||
case ",$expect," in
|
||||
*",$code,"*) ok "$label $url" ;;
|
||||
*)
|
||||
if [ "${LOCAL_STACK:-1}" = "0" ]; then
|
||||
warn "$label $url" "got $code (optional on remote domain)"
|
||||
else
|
||||
fail "$label $url" "got $code want $expect"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
expect_currency() {
|
||||
local label="$1" file="$2" want="${EXPECT_CURRENCY:-}"
|
||||
local cur
|
||||
cur=$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("currency",""))' "$file" 2>/dev/null || true)
|
||||
if [ -z "$want" ]; then
|
||||
info "$label currency" "${cur:-?}"
|
||||
return
|
||||
fi
|
||||
if [ "$cur" = "$want" ]; then
|
||||
ok "$label currency=$want"
|
||||
else
|
||||
fail "$label currency" "got ${cur:-?} want $want"
|
||||
fi
|
||||
}
|
||||
|
||||
# Legal docs: /terms and /privacy must be HTTP 200 with a real document body
|
||||
# (not empty, not "not configured", not JSON API error).
|
||||
# $1=label $2=url $3=optional needle regex (case-insensitive) for local stack
|
||||
check_legal_doc() {
|
||||
local label="$1" url="$2" needle="${3:-}"
|
||||
local f code soft
|
||||
soft=0
|
||||
[ "${LOCAL_STACK:-1}" = "0" ] && soft=1
|
||||
f=$(mktemp)
|
||||
code=$(curl -skS --max-redirs 5 -L -m "${TIMEOUT}" \
|
||||
-H "Accept: text/html,text/markdown,text/plain,*/*" \
|
||||
-o "$f" -w '%{http_code}' "$url" 2>/dev/null || echo 000)
|
||||
if [ "$code" != "200" ]; then
|
||||
rm -f "$f"
|
||||
if [ "$soft" = "1" ]; then
|
||||
warn "$label" "HTTP $code — $url"
|
||||
else
|
||||
fail "$label" "HTTP $code — $url"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
if [ ! -s "$f" ]; then
|
||||
rm -f "$f"
|
||||
fail "$label" "empty body — $url"
|
||||
return
|
||||
fi
|
||||
# merchant returns plain "not configured" when PRIVACY_ETAG missing
|
||||
if grep -qiE '^(not configured)\s*$' "$f" 2>/dev/null \
|
||||
|| grep -qiE '"code"\s*:\s*21' "$f" 2>/dev/null; then
|
||||
rm -f "$f"
|
||||
fail "$label" "not configured / API error — $url"
|
||||
return
|
||||
fi
|
||||
if [ -n "$needle" ] && [ "${LOCAL_STACK:-1}" = "1" ]; then
|
||||
if ! grep -qiE "$needle" "$f" 2>/dev/null; then
|
||||
warn "$label content" "missing /$needle/ — $url"
|
||||
rm -f "$f"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
ok "$label" "HTTP 200 · $(wc -c <"$f" | tr -d ' ') bytes"
|
||||
rm -f "$f"
|
||||
}
|
||||
|
||||
# --- exchange (core; always required) --- www-001 …
|
||||
check_url "exchange /config" 200 "$EXCHANGE_PUBLIC/config"
|
||||
code=$(http_body "$EXCHANGE_PUBLIC/config" "$tmp/ec.json")
|
||||
if [ "$code" = "200" ]; then
|
||||
expect_currency "exchange" "$tmp/ec.json"
|
||||
# currency_specification.alt_unit_names (wallet codec)
|
||||
if json_has_alt_unit_names "$tmp/ec.json" "${EXPECT_CURRENCY:-}" >/tmp/alt-ex.$$ 2>&1; then
|
||||
ok "exchange /config alt_unit_names" "$(tr '\n' '; ' </tmp/alt-ex.$$ | sed 's/; $//')"
|
||||
else
|
||||
fail "exchange /config alt_unit_names" "$(tr '\n' '; ' </tmp/alt-ex.$$ | sed 's/; $//')"
|
||||
fi
|
||||
rm -f /tmp/alt-ex.$$
|
||||
fi
|
||||
check_url "exchange /keys" 200 "$EXCHANGE_PUBLIC/keys"
|
||||
# /keys should also expose currency_specification.alt_unit_names when present
|
||||
code=$(http_body "$EXCHANGE_PUBLIC/keys" "$tmp/ek.json")
|
||||
if [ "$code" = "200" ]; then
|
||||
if python3 - "$tmp/ek.json" <<'PY'
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1]))
|
||||
cs=d.get("currency_specification") or {}
|
||||
au=cs.get("alt_unit_names") if isinstance(cs,dict) else None
|
||||
if not isinstance(au, dict) or "0" not in au:
|
||||
# older keys without embedded spec: not a hard fail if /config is good
|
||||
sys.exit(2)
|
||||
sys.exit(0)
|
||||
PY
|
||||
then
|
||||
ok "exchange /keys alt_unit_names"
|
||||
else
|
||||
ec=$?
|
||||
if [ "$ec" = "2" ]; then
|
||||
warn "exchange /keys alt_unit_names" "no currency_specification in /keys (ok if /config has it)"
|
||||
else
|
||||
fail "exchange /keys alt_unit_names"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
check_url_soft "exchange /intro/" 200 "$EXCHANGE_PUBLIC/intro/"
|
||||
# Root should land on intro (302/301 then 200 on follow is checked separately)
|
||||
check_url_soft "exchange /" 302,301,200 "$EXCHANGE_PUBLIC/"
|
||||
|
||||
# Terms + privacy (legal docs)
|
||||
check_legal_doc "exchange /terms" "$EXCHANGE_PUBLIC/terms" "terms|GOA|exploration|FADP|revDSG|privacy"
|
||||
check_legal_doc "exchange /privacy" "$EXCHANGE_PUBLIC/privacy" "privacy|FADP|revDSG|data|GOA|exploration"
|
||||
# trailing slash: 200 or redirect to bare path
|
||||
code=$(http_code "$EXCHANGE_PUBLIC/terms/")
|
||||
case "$code" in
|
||||
200|301|302) ok "exchange /terms/" "HTTP $code" ;;
|
||||
*)
|
||||
if [ "${LOCAL_STACK:-1}" = "1" ]; then warn "exchange /terms/" "HTTP $code"
|
||||
else warn "exchange /terms/" "HTTP $code"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- bank ---
|
||||
if [ "${LOCAL_STACK:-1}" = "0" ]; then
|
||||
check_url_soft "bank /config" 200 "$BANK_PUBLIC/config"
|
||||
else
|
||||
check_url "bank /config" 200 "$BANK_PUBLIC/config"
|
||||
fi
|
||||
code=$(http_body "$BANK_PUBLIC/config" "$tmp/bc.json")
|
||||
if [ "$code" = "200" ]; then
|
||||
expect_currency "bank" "$tmp/bc.json"
|
||||
if json_has_alt_unit_names "$tmp/bc.json" >/tmp/alt-bank.$$ 2>&1; then
|
||||
ok "bank /config alt_unit_names" "$(tr '\n' '; ' </tmp/alt-bank.$$ | sed 's/; $//')"
|
||||
else
|
||||
fail "bank /config alt_unit_names" "$(tr '\n' '; ' </tmp/alt-bank.$$ | sed 's/; $//')"
|
||||
fi
|
||||
rm -f /tmp/alt-bank.$$
|
||||
check_url_soft "bank /taler-integration/config" 200 "$BANK_PUBLIC/taler-integration/config"
|
||||
check_url_soft "bank /webui/" 200 "$BANK_PUBLIC/webui/"
|
||||
check_url_soft "bank /intro/" 200 "$BANK_PUBLIC/intro/"
|
||||
check_url_soft "bank /" 302,301,200 "$BANK_PUBLIC/"
|
||||
fi
|
||||
|
||||
# Bank legal docs (landing nginx via Caddy /terms* /privacy* or /intro/*)
|
||||
check_legal_doc "bank /terms" "$BANK_PUBLIC/terms" "terms|GOA|exploration|bank|FADP|revDSG"
|
||||
# Prefer /privacy; fall back to /intro/privacy.html for older deploys
|
||||
code=$(http_code "$BANK_PUBLIC/privacy")
|
||||
if [ "$code" = "200" ]; then
|
||||
check_legal_doc "bank /privacy" "$BANK_PUBLIC/privacy" "privacy|FADP|revDSG|data|GOA|bank"
|
||||
else
|
||||
if [ "${LOCAL_STACK:-1}" = "1" ]; then
|
||||
check_legal_doc "bank /privacy (or /intro/privacy.html)" \
|
||||
"$BANK_PUBLIC/intro/privacy.html" "privacy|FADP|revDSG|data|GOA|bank"
|
||||
# still report bare /privacy failure for local
|
||||
warn "bank /privacy" "HTTP $code — prefer Caddy handle /privacy* → landing"
|
||||
else
|
||||
check_url_soft "bank /privacy" 200 "$BANK_PUBLIC/privacy"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- merchant ---
|
||||
if [ "${LOCAL_STACK:-1}" = "0" ]; then
|
||||
check_url_soft "merchant /config" 200 "$MERCHANT_PUBLIC/config"
|
||||
else
|
||||
check_url "merchant /config" 200 "$MERCHANT_PUBLIC/config"
|
||||
fi
|
||||
code=$(http_body "$MERCHANT_PUBLIC/config" "$tmp/mc.json")
|
||||
if [ "$code" = "200" ]; then
|
||||
want="${EXPECT_CURRENCY:-}"
|
||||
if python3 - "$tmp/mc.json" "$want" <<'PY'
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1]))
|
||||
except Exception:
|
||||
sys.exit(2)
|
||||
want=sys.argv[2]
|
||||
if not want:
|
||||
sys.exit(0)
|
||||
curs=list((d.get("currencies") or {}).keys())
|
||||
ex=d.get("exchanges") or []
|
||||
ok = want in curs or any((e.get("currency") if isinstance(e,dict) else None)==want for e in ex)
|
||||
if not ok and isinstance(d.get("currency"), str):
|
||||
ok = d["currency"]==want
|
||||
sys.exit(0 if ok else 1)
|
||||
PY
|
||||
then
|
||||
ok "merchant /config (${want:-currency} ok)"
|
||||
else
|
||||
ec=$?
|
||||
if [ "$ec" = "2" ]; then
|
||||
warn "merchant /config" "non-JSON body"
|
||||
elif [ -n "$want" ]; then
|
||||
fail "merchant /config currency" "want $want"
|
||||
else
|
||||
info "merchant /config" "ok"
|
||||
fi
|
||||
fi
|
||||
# merchant-local currency maps (GOA + CHF, …)
|
||||
if json_has_alt_unit_names "$tmp/mc.json" >/tmp/alt-mer.$$ 2>&1; then
|
||||
ok "merchant /config currencies alt_unit_names" "$(tr '\n' '; ' </tmp/alt-mer.$$ | sed 's/; $//')"
|
||||
else
|
||||
fail "merchant /config currencies alt_unit_names" "$(tr '\n' '; ' </tmp/alt-mer.$$ | sed 's/; $//')"
|
||||
fi
|
||||
rm -f /tmp/alt-mer.$$
|
||||
# Follow each exchange listed in merchant /config and require its /config alt_unit_names
|
||||
check_merchant_listed_exchanges_alt_units "$tmp/mc.json"
|
||||
check_url_soft "merchant /intro/" 200 "$MERCHANT_PUBLIC/intro/"
|
||||
check_url_soft "merchant /webui/" 200 "$MERCHANT_PUBLIC/webui/"
|
||||
check_url_soft "merchant /" 302,301,200 "$MERCHANT_PUBLIC/"
|
||||
fi
|
||||
|
||||
# Merchant legal docs
|
||||
check_legal_doc "merchant /terms" "$MERCHANT_PUBLIC/terms" "terms|dual|GOA|CHF|explorational|merchant"
|
||||
check_legal_doc "merchant /privacy" "$MERCHANT_PUBLIC/privacy" "privacy|FADP|revDSG|data|GOA|CHF|merchant"
|
||||
code=$(http_code "$MERCHANT_PUBLIC/terms/")
|
||||
case "$code" in
|
||||
200|301|302) ok "merchant /terms/" "HTTP $code" ;;
|
||||
*) warn "merchant /terms/" "HTTP $code (expect 302 → /terms)" ;;
|
||||
esac
|
||||
|
||||
summary
|
||||
Loading…
Add table
Add a link
Reference in a new issue