Files
glchat/deploy/smoke.sh
T

203 lines
7.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# glchat: smoke-тест после установки (AGENT.md 10.9).
# Фаза 0 проверяет фундамент: HTTPS-заглушка, meta, healthy, порты, fail2ban.
set -uo pipefail
GLCHAT_ETC_DIR="${GLCHAT_ETC_DIR:-/opt/glchat}"
ENV_FILE="${GLCHAT_ETC_DIR}/.env"
PASSED=0
FAILED=0
SKIPPED=0
pass() {
printf ' \033[32m✓\033[0m %s\n' "$*"
PASSED=$((PASSED + 1))
}
fail() {
printf ' \033[31m✗\033[0m %s\n' "$*"
FAILED=$((FAILED + 1))
}
skip() {
printf ' \033[33m–\033[0m %s\n' "$*"
SKIPPED=$((SKIPPED + 1))
}
if [ -f "$ENV_FILE" ]; then
# shellcheck disable=SC1090
set -a && . "$ENV_FILE" && set +a
fi
DOMAIN="${DOMAIN:-}"
APP_PORT="${APP_PORT:-8080}"
PROXY_MODE="${PROXY_MODE:-embedded}"
LIVEKIT_TCP_PORT="${LIVEKIT_TCP_PORT:-7881}"
LIVEKIT_UDP_PORT="${LIVEKIT_UDP_PORT:-7882}"
TURN_ENABLED="${TURN_ENABLED:-true}"
TURN_UDP_PORT="${TURN_UDP_PORT:-3478}"
TURN_TLS_PORT="${TURN_TLS_PORT:-5349}"
SKIP_TLS="${SKIP_TLS:-0}"
LIVEKIT_PUBLISH="${LIVEKIT_PUBLISH:-true}"
ENABLE_FAIL2BAN="${FAIL2BAN_ENABLED:-true}"
printf '\n=== glchat smoke-тест ===\n'
printf '\n[1] Приложение\n'
if curl -fsS "http://127.0.0.1:${APP_PORT}/healthz" >/dev/null; then
pass "/healthz отвечает 200"
else
fail "/healthz недоступен на 127.0.0.1:${APP_PORT}"
fi
ready="$(curl -fsS "http://127.0.0.1:${APP_PORT}/readyz" 2>/dev/null || true)"
if printf '%s' "$ready" | grep -q '"status":"ready"'; then
pass "/readyz: база данных готова"
else
fail "/readyz: ${ready:-нет ответа}"
fi
meta="$(curl -fsS "http://127.0.0.1:${APP_PORT}/api/v1/meta" 2>/dev/null || true)"
if printf '%s' "$meta" | grep -q '"api_version":"v1"'; then
version="$(printf '%s' "$meta" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')"
pass "/api/v1/meta отвечает, версия ${version}"
else
fail "/api/v1/meta недоступен"
fi
printf '\n[2] Веб-клиент\n'
index="$(curl -fsS "http://127.0.0.1:${APP_PORT}/" 2>/dev/null || true)"
if printf '%s' "$index" | grep -qi '<div id="root"'; then
pass "заглушка клиента отдаётся с /"
elif printf '%s' "$index" | grep -qi 'web client bundle is not present'; then
fail "в образе нет собранного веб-клиента"
else
fail "некорректный ответ на /"
fi
printf '\n[3] Публичный доступ\n'
if [ "$SKIP_TLS" = "1" ]; then
skip "TLS отключён (--skip-tls): публичная проверка пропущена"
elif [ "$PROXY_MODE" = "external" ]; then
if curl -fsS --max-time 10 "https://${DOMAIN}/api/v1/meta" >/dev/null 2>&1; then
pass "https://${DOMAIN}/api/v1/meta отвечает через внешний прокси"
else
fail "https://${DOMAIN} недоступен: добавьте блок из ${GLCHAT_ETC_DIR}/external-proxy.conf во внешний прокси"
fi
else
if curl -fsS --max-time 15 "https://${DOMAIN}/api/v1/meta" >/dev/null 2>&1; then
pass "https://${DOMAIN}/api/v1/meta отвечает (сертификат валиден)"
else
fail "https://${DOMAIN} недоступен (проверьте DNS и логи Caddy)"
fi
fi
printf '\n[4] Внутренние порты закрыты снаружи\n'
public_ip="$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null || true)"
if [ -z "$public_ip" ]; then
skip "внешний IP не определён: пропускаем проверку публикации портов"
else
for port in "$APP_PORT" 7880; do
if timeout 4 bash -c "</dev/tcp/${public_ip}/${port}" 2>/dev/null; then
fail "порт ${port} доступен снаружи (${public_ip})"
else
pass "порт ${port} недоступен снаружи"
fi
done
fi
printf '\n[5] Открытые медиапорты\n'
if [ "$LIVEKIT_PUBLISH" = "false" ] || [ "${SKIP_TLS}" = "1" ]; then
skip "порты LiveKit не публиковались в этом режиме"
else
for spec in "${LIVEKIT_TCP_PORT}/tcp" "${LIVEKIT_UDP_PORT}/udp"; do
port="${spec%%/*}"
if ss -tulnH 2>/dev/null | grep -q ":${port} "; then
pass "слушает ${spec}"
else
fail "не слушает ${spec}"
fi
done
if [ "$TURN_ENABLED" = "true" ]; then
for spec in "${TURN_UDP_PORT}/udp" "${TURN_TLS_PORT}/tcp"; do
port="${spec%%/*}"
if ss -tulnH 2>/dev/null | grep -q ":${port} "; then
pass "слушает ${spec}"
else
skip "не слушает ${spec} (проверьте конфиг LiveKit/TURN)"
fi
done
fi
fi
printf '\n[6] UFW и DOCKER-USER\n'
if command -v ufw >/dev/null 2>&1; then
if ufw status 2>/dev/null | grep -q 'Status: active'; then
pass "UFW активен"
if [ "$PROXY_MODE" = "external" ]; then
ufw status | grep -q "${LIVEKIT_TCP_PORT}/tcp" && pass "UFW: ${LIVEKIT_TCP_PORT}/tcp разрешён" || fail "UFW: нет правила для ${LIVEKIT_TCP_PORT}/tcp"
ufw status | grep -q "${LIVEKIT_UDP_PORT}/udp" && pass "UFW: ${LIVEKIT_UDP_PORT}/udp разрешён" || fail "UFW: нет правила для ${LIVEKIT_UDP_PORT}/udp"
fi
else
fail "UFW не активен"
fi
else
skip "ufw не установлен"
fi
if command -v iptables >/dev/null 2>&1 && iptables -nL DOCKER-USER >/dev/null 2>&1; then
if iptables -nL DOCKER-USER 2>/dev/null | grep -q 'glchat-block-internal'; then
pass "DOCKER-USER: внутренние порты заблокированы"
else
fail "DOCKER-USER: нет правил glchat"
fi
else
skip "цепочка DOCKER-USER недоступна"
fi
printf '\n[7] fail2ban\n'
if [ "$ENABLE_FAIL2BAN" = "true" ] && command -v fail2ban-client >/dev/null 2>&1; then
jails="$(fail2ban-client status 2>/dev/null | sed -n 's/.*Jail list:\s*//p')"
for jail in sshd glchat-auth recidive; do
if printf '%s' "$jails" | grep -q "$jail"; then
pass "jail ${jail} активен"
else
fail "jail ${jail} не активен"
fi
done
else
skip "fail2ban не включён"
fi
printf '\n[8] Автозапуск\n'
if systemctl is-enabled glchat.service >/dev/null 2>&1; then
pass "glchat.service включён"
else
fail "glchat.service не включён в автозапуск"
fi
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^glchat-app$'; then
restart_policy="$(docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' glchat-app 2>/dev/null)"
if [ "$restart_policy" = "unless-stopped" ]; then
pass "политика перезапуска контейнера: unless-stopped"
else
fail "политика перезапуска: ${restart_policy:-unknown}"
fi
else
fail "контейнер glchat-app не запущен"
fi
printf '\n[9] Бэкап\n'
if GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/backup.sh" >/tmp/glchat-smoke-backup.log 2>&1; then
last_backup="$(ls -1t "${GLCHAT_ETC_DIR}/data/backups"/glchat-*.tar.gz* 2>/dev/null | head -1)"
pass "бэкап создан: $(basename "${last_backup:-unknown}")"
if [ "${last_backup}" = *.age ]; then
pass "бэкап зашифрован age"
else
skip "бэкап создан без шифрования: задайте AGE_RECIPIENT (install.sh генерирует его автоматически)"
fi
else
fail "бэкап не создан (см. /tmp/glchat-smoke-backup.log)"
fi
printf '\n=== Итог: %d ok, %d ошибок, %d пропущено ===\n\n' "$PASSED" "$FAILED" "$SKIPPED"
if [ "$FAILED" -gt 0 ]; then
exit 1
fi
exit 0