release 1.17.0: mattermost mobile server min (Android/iOS store)

This commit is contained in:
Hernâni Marques 2026-07-19 06:04:57 +02:00
parent 2d7af7a960
commit d1de912b91
No known key found for this signature in database
GPG key ID: CB5738652768F7E9
4 changed files with 114 additions and 18 deletions

View file

@ -1 +1 @@
1.16.0
1.17.0

View file

@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre
| Tag | Date (UTC) | Notes |
|-----|------------|--------|
| **v1.17.0** | 2026-07-19 | **Feature:** mattermost phase — check **server version** (`X-Version-Id`) against **mobile store min** (default **≥10.11.0**); ERROR when too old (newest Android/iOS apps break); env `MATTERMOST_MOBILE_MIN_SERVER` / `MATTERMOST_MOBILE_CHECK=0`. |
| **v1.16.0** | 2026-07-19 | **Feature:** mon sticky — blue **info** + green **ok** filter badges; suite **version tag under status pill** (not blue badge); filters `#filter-info` / `#filter-ok`. |
| **v1.15.8** | 2026-07-19 | **Bugfix:** mon HTML filter JS — drop literal box-drawing / `\-` regex that caused Python SyntaxWarning (and weird glyphs in suite logs); use Unicode code-point loop instead. |
| **v1.15.7** | 2026-07-19 | **Bugfix:** mon HTML — do not paint «perf/ladder summary» as SUMMARY header (restore 2 INFO lines); drop converter SyntaxWarning/noise from public log; «wrote» on stderr; host-agent PYTHONWARNINGS for convert. |

View file

@ -5,6 +5,13 @@
# Override: MATTERMOST_PUBLIC=https://mattermost.example.org
# MATTERMOST_HOST=mattermost.example.org
#
# Mobile compatibility (feature):
# Current Mattermost Android/iOS store apps require a minimum *server* version
# (default MATTERMOST_MOBILE_MIN_SERVER=10.11.0 — Play Store / mobile docs 2026).
# Server older than that → ERROR (users on newest app cannot rely on the server).
# Override: MATTERMOST_MOBILE_MIN_SERVER=x.y.z
# MATTERMOST_MOBILE_CHECK=0 to skip
#
# Outside-only (no SSH). Phase name: mattermost
#
set -euo pipefail
@ -15,6 +22,10 @@ source "$ROOT/lib.sh"
set_area mattermost
section "mattermost · public chat (outside-in)"
# Minimum server version for current mobile apps (Mattermost docs / Play Store).
: "${MATTERMOST_MOBILE_MIN_SERVER:=10.11.0}"
: "${MATTERMOST_MOBILE_CHECK:=1}"
if [ -n "${MATTERMOST_PUBLIC:-}" ]; then
BASE="${MATTERMOST_PUBLIC%/}"
elif [ -n "${MATTERMOST_HOST:-}" ]; then
@ -27,6 +38,7 @@ HOST=${HOST#http://}
HOST=${HOST%%/*}
info "target" "$BASE"
info "mobile policy" "newest store apps require server ≥ ${MATTERMOST_MOBILE_MIN_SERVER} (MATTERMOST_MOBILE_CHECK=${MATTERMOST_MOBILE_CHECK})"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
@ -46,30 +58,106 @@ else
fail "landing" "$BASE/ → HTTP $code (want 200 HTML Mattermost SPA)"
fi
# --- Official Mattermost health API ---
# --- Official Mattermost health API + server version (X-Version-Id) ---
set_group api
code=$(mm_get "$BASE/api/v4/system/ping" "$tmp/ping.json")
# Capture body + headers (version is in X-Version-Id, not always in JSON)
hdr_file="$tmp/ping.hdr"
code=$(curl -skS -L --max-redirs 5 -m "${TIMEOUT:-12}" \
-D "$hdr_file" -o "$tmp/ping.json" -w '%{http_code}' \
"$BASE/api/v4/system/ping" 2>/dev/null || echo 000)
MM_SERVER_VER=""
if [ -f "$hdr_file" ]; then
# X-Version-Id: 9.5.3.8427860509.c8cabb… or 10.11.0.…
MM_SERVER_VER=$(grep -i '^x-version-id:' "$hdr_file" | head -1 \
| sed 's/^[Xx]-[Vv]ersion-[Ii]d:[[:space:]]*//' | tr -d '\r' \
| sed 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/')
fi
if [ "$code" != "200" ]; then
fail "system/ping" "$BASE/api/v4/system/ping → HTTP $code (want 200 JSON)"
else
# Ping returns JSON object (fields vary by MM version)
if python3 - "$tmp/ping.json" <<'PY' 2>/dev/null
import json, sys
p = sys.argv[1]
with open(p) as f:
with open(sys.argv[1]) as f:
d = json.load(f)
if not isinstance(d, dict):
sys.exit(2)
# older builds may include status; newer still return object with backends
sys.exit(0)
sys.exit(0 if isinstance(d, dict) else 2)
PY
then
ok "system/ping" "$BASE/api/v4/system/ping → HTTP 200 JSON"
ok "system/ping" "$BASE/api/v4/system/ping → HTTP 200 JSON${MM_SERVER_VER:+ · server ${MM_SERVER_VER}}"
else
fail "system/ping" "$BASE/api/v4/system/ping → HTTP 200 but not valid JSON object"
fi
fi
# --- Server version vs current mobile app requirement ---
set_group version
if [ "${MATTERMOST_MOBILE_CHECK}" = "0" ]; then
info "mobile compat" "skipped (MATTERMOST_MOBILE_CHECK=0)"
elif [ -z "$MM_SERVER_VER" ]; then
warn "server version" "could not parse X-Version-Id from /api/v4/system/ping (mobile min=${MATTERMOST_MOBILE_MIN_SERVER})"
else
info "server version" "X-Version-Id → ${MM_SERVER_VER} (mobile apps require ≥ ${MATTERMOST_MOBILE_MIN_SERVER})"
# Compare MAJOR.MINOR.PATCH (semver-ish); returns 0 if server >= min
if python3 - "$MM_SERVER_VER" "$MATTERMOST_MOBILE_MIN_SERVER" <<'PY'
import sys
def parse(v: str):
parts = []
for p in v.strip().split(".")[:3]:
try:
parts.append(int(p))
except ValueError:
parts.append(0)
while len(parts) < 3:
parts.append(0)
return tuple(parts)
server, need = parse(sys.argv[1]), parse(sys.argv[2])
sys.exit(0 if server >= need else 1)
PY
then
ok "mobile compat" \
"server ${MM_SERVER_VER}${MATTERMOST_MOBILE_MIN_SERVER} · current Android/iOS store apps OK"
else
# Hard ERROR: newest Play Store app refuses / breaks on unsupported servers
fail "mobile compat" \
"server ${MM_SERVER_VER} < ${MATTERMOST_MOBILE_MIN_SERVER} (required by current Mattermost Android/iOS store apps)" \
"users on latest mobile app get connect failures/crashes · upgrade Mattermost server · override MATTERMOST_MOBILE_MIN_SERVER= or MATTERMOST_MOBILE_CHECK=0"
fi
fi
# Client config (optional): BuildDate / advertised Android min if server sets it
set_group client-config
code=$(mm_get "$BASE/api/v4/config/client?format=old" "$tmp/client.json")
if [ "$code" = "200" ] && [ -s "$tmp/client.json" ]; then
build=$(python3 - "$tmp/client.json" <<'PY' 2>/dev/null
import json, sys
with open(sys.argv[1]) as f:
d = json.load(f)
print(d.get("BuildDate") or d.get("Version") or "")
PY
)
and_min=$(python3 - "$tmp/client.json" <<'PY' 2>/dev/null
import json, sys
with open(sys.argv[1]) as f:
d = json.load(f)
# empty strings are common on older servers
print((d.get("AndroidMinVersion") or "").strip())
PY
)
if [ -n "$build" ]; then
info "client config" "BuildDate/Version=${build}${and_min:+ · AndroidMinVersion=${and_min}}"
else
info "client config" "HTTP 200 (no BuildDate field)"
fi
if [ -n "$and_min" ] && [ "$and_min" != "0.0.0" ]; then
info "android min (server)" "server advertises AndroidMinVersion=${and_min}"
fi
else
info "client config" "HTTP ${code:-?} — optional"
fi
# --- Login SPA (must be served for users) ---
set_group login
code=$(mm_get "$BASE/login" "$tmp/login.html")
@ -109,5 +197,9 @@ else
info "tls cert" "openssl not available — skip expiry check"
fi
info "hint" "surface catalog also lists $HOST; this phase is Mattermost-specific (SPA + /api/v4/system/ping)"
info "hint" "surface catalog also lists $HOST; this phase checks SPA + /api/v4/system/ping + mobile server min (${MATTERMOST_MOBILE_MIN_SERVER})"
# Non-zero when any fail/err so parent phase + mon pages mark ERROR
if [ "${FAIL_N:-0}" -gt 0 ]; then
exit 1
fi
exit 0

View file

@ -148,10 +148,11 @@ def ui(lang: str, key: str, **kwargs) -> str:
"stage_i6": "devtesting: fake-franken CHF via rusty.taler-ops.ch (geniban + fake-incoming)",
"pages_section_lead": "Monitoring pages themselves (suite):",
"mm_title": "Mattermost chat health",
"mm_summary": "mattermost.taler.net · SPA + /api/v4/system/ping · TLS",
"mm_summary": "mattermost.taler.net · SPA + ping · mobile server min · TLS",
"mm_i1": "Outside-in phase mattermost (default https://mattermost.taler.net)",
"mm_i2": "Landing SPA, /api/v4/system/ping JSON, /login, TLS certificate expiry",
"mm_i3": "Reported on taler-monitoring-surface HTML (no separate /taler-monitoring-mattermost* page)",
"mm_i2": "Landing SPA, /api/v4/system/ping, X-Version-Id vs mobile min (default ≥10.11.0), /login, TLS",
"mm_i3": "Newest Android/iOS store apps require server ≥ MATTERMOST_MOBILE_MIN_SERVER — ERROR if older",
"mm_i4": "Reported on taler-monitoring-surface HTML (no separate /taler-monitoring-mattermost* page)",
"mail_title": "Mail (MX / SMTP / IMAP)",
"mail_summary": "firefly.gnunet.org + anastasis.taler-systems.com · mail-catalog.conf",
"mail_i1": "Outside-in phase mail: MX, SMTP/IMAP ports and handshakes, SPF/DMARC",
@ -256,10 +257,11 @@ def ui(lang: str, key: str, **kwargs) -> str:
"pages_i6": "Hôte de cette page : {host} · libellé : {label}",
"pages_section_lead": "Les pages de monitoring elles-mêmes (suite) :",
"mm_title": "Santé du chat Mattermost",
"mm_summary": "mattermost.taler.net · SPA + /api/v4/system/ping · TLS",
"mm_summary": "mattermost.taler.net · SPA + ping · min serveur mobile · TLS",
"mm_i1": "Phase outside-in mattermost (défaut https://mattermost.taler.net)",
"mm_i2": "SPA d'accueil, /api/v4/system/ping JSON, /login, expiration du certificat TLS",
"mm_i3": "Rapporté dans le HTML taler-monitoring-surface (pas de page /taler-monitoring-mattermost*)",
"mm_i2": "SPA, /api/v4/system/ping, X-Version-Id vs min mobile (≥10.11.0), /login, TLS",
"mm_i3": "Apps store Android/iOS récentes exigent serveur ≥ MATTERMOST_MOBILE_MIN_SERVER — ERROR si plus vieux",
"mm_i4": "Rapporté sur la page surface HTML",
"mail_title": "Mail (MX / SMTP / IMAP)",
"mail_summary": "firefly.gnunet.org + anastasis.taler-systems.com · mail-catalog.conf",
"mail_i1": "Phase outside-in mail : MX, ports SMTP/IMAP et handshakes, SPF/DMARC",
@ -734,6 +736,7 @@ def monitoring_scope(
ui(lang, "mm_i1"),
ui(lang, "mm_i2"),
ui(lang, "mm_i3"),
ui(lang, "mm_i4"),
] + _pages_items(lang, host, label)
return {
"kind": "mattermost",