feat(ops): duman testi, yedekleme ve geri yükleme betikleri

- smoke-test.sh: sağlık, replica set, güvenlik başlıkları, HTTPS, oturumsuz erişim, giriş
- butcem-backup.sh: mongodump + uploads arşivi, SHA-256, 7 gün saklama
- butcem-restore.sh: bütünlük kontrolü ve onayla geri yükleme

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-07 02:13:10 +03:00
parent 7d7dd61c60
commit 1bdcedefdc
4 changed files with 203 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# BÜTÇEM duman testi (smoke test) — canlıya alma sonrası, yalnızca OKUMA yapar; veri değiştirmez.
#
# Kullanım:
# scripts/smoke-test.sh https://butcem.ta1sph.website [beklenen-sürüm]
# SMOKE_USER=admin SMOKE_PASSWORD='…' scripts/smoke-test.sh https://butcem.ta1sph.website 1.0.0
#
# Gerekenler: bash, curl. Çıkış kodu: 0 = hepsi geçti, 1 = en az bir kontrol başarısız.
set -uo pipefail
BASE="${1:?Kullanım: scripts/smoke-test.sh <adres> [beklenen-sürüm]}"
BASE="${BASE%/}"
EXPECT_VERSION="${2:-}"
FAIL=0
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
bad() { printf ' \033[31m✗\033[0m %s\n' "$1"; FAIL=1; }
check() { if eval "$2"; then ok "$1"; else bad "$1"; fi; }
echo "BÜTÇEM duman testi: $BASE"
echo "1) Sağlık kontrolü"
HEALTH_CODE=$(curl -s -o "$TMP/health" -w '%{http_code}' "$BASE/api/health")
HEALTH=$(cat "$TMP/health")
echo " $HEALTH"
check "GET /api/health 200" '[ "$HEALTH_CODE" = 200 ]'
check "veritabanı erişilebilir" 'grep -q "\"db\":\"ok\"" <<<"$HEALTH"'
check "MongoDB replica set (transaction için)" '! grep -q "\"replicaSet\":null" <<<"$HEALTH" && grep -q "\"replicaSet\":\"" <<<"$HEALTH"'
if [ -n "$EXPECT_VERSION" ]; then
check "sürüm $EXPECT_VERSION" 'grep -q "\"version\":\"$EXPECT_VERSION\"" <<<"$HEALTH"'
fi
echo "2) Sayfalar ve güvenlik başlıkları"
LOGIN_CODE=$(curl -s -D "$TMP/login-headers" -o /dev/null -w '%{http_code}' "$BASE/login")
H=$(tr -d '\r' <"$TMP/login-headers" | tr 'A-Z' 'a-z')
check "GET /login 200" '[ "$LOGIN_CODE" = 200 ]'
check "Content-Security-Policy var" 'grep -q "^content-security-policy:" <<<"$H"'
check "X-Frame-Options: DENY" 'grep -q "^x-frame-options: deny" <<<"$H"'
check "X-Content-Type-Options: nosniff" 'grep -q "^x-content-type-options: nosniff" <<<"$H"'
if [[ "$BASE" == https://* ]]; then
check "Strict-Transport-Security var" 'grep -q "^strict-transport-security:" <<<"$H"'
HTTP_URL="http://${BASE#https://}/login"
HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' "$HTTP_URL")
check "HTTP → HTTPS yönlendirmesi ($HTTP_CODE)" '[[ "$HTTP_CODE" =~ ^30[1278]$ ]]'
fi
echo "3) Oturumsuz erişim engelleniyor"
DASH=$(curl -s -o /dev/null -w '%{http_code} %{redirect_url}' "$BASE/dashboard")
check "/dashboard → giriş sayfasına yönlendirme ($DASH)" '[[ "$DASH" =~ ^30[27]\ .*/login ]]'
FILE_CODE=$(curl -s -o /dev/null -w '%{http_code}' "$BASE/api/files/000000000000000000000000")
check "/api/files oturumsuz 401 ($FILE_CODE)" '[ "$FILE_CODE" = 401 ]'
CSV=$(curl -s -o "$TMP/csv" -w '%{http_code}' "$BASE/raporlar/kategoriler/csv")
check "rapor CSV'si oturumsuz veri vermiyor ($CSV)" '! grep -q "Toplam gidere oran" "$TMP/csv"'
if [ -n "${SMOKE_USER:-}" ] && [ -n "${SMOKE_PASSWORD:-}" ]; then
echo "4) Giriş ($SMOKE_USER)"
SIGN=$(curl -s -c "$TMP/jar" -o "$TMP/signin" -w '%{http_code}' -X POST "$BASE/api/auth/sign-in/username" \
-H 'Content-Type: application/json' -H "Origin: $BASE" \
--data "$(printf '{"username":"%s","password":"%s"}' "$SMOKE_USER" "$SMOKE_PASSWORD")")
check "giriş 200 ($SIGN)" '[ "$SIGN" = 200 ]'
PAGE=$(curl -s -b "$TMP/jar" -L -o /dev/null -w '%{http_code} %{url_effective}' "$BASE/dashboard")
check "oturumla ana sayfa açılıyor ($PAGE)" '[[ "$PAGE" =~ ^200\ ]] && [[ ! "$PAGE" =~ /login ]]'
curl -s -b "$TMP/jar" -X POST "$BASE/api/auth/sign-out" -H "Origin: $BASE" -o /dev/null
else
echo "4) Giriş testi atlandı (SMOKE_USER ve SMOKE_PASSWORD tanımlı değil)"
fi
echo
if [ "$FAIL" = 0 ]; then echo "Sonuç: tüm kontroller geçti."; else echo "Sonuç: başarısız kontrol var."; fi
exit "$FAIL"