diff --git a/.gitea/workflows/browser-e2e.yml b/.gitea/workflows/browser-e2e.yml index d250d7c..2d1f46d 100644 --- a/.gitea/workflows/browser-e2e.yml +++ b/.gitea/workflows/browser-e2e.yml @@ -52,6 +52,13 @@ jobs: LOGIN_STATUS="$(curl -s -o /dev/null -w '%{http_code}' "http://${DEPLOY_HOST}/taxbaik/admin/login" || true)" if echo "$VERSION_BODY" | grep -q "\"version\": \"${SHORT_VERSION}\"" && [ "$BLOG_STATUS" = "200" ] && [ "$LOGIN_STATUS" = "200" ]; then echo "✓ Deployment ready for ${SHORT_VERSION} (attempt $i/20)" + ROOT_URL="http://${DEPLOY_HOST}/" \ + ADMIN_URL="http://${DEPLOY_HOST}/taxbaik/admin/login" \ + PUBLIC_MARKER="백원숙 세무회계" \ + PUBLIC_FORBIDDEN="관리자" \ + ADMIN_MARKER="TaxBaik Admin" \ + MAX_RETRIES=1 \ + bash ./scripts/taxbaik-smoke.sh exit 0 fi if [ $i -lt 20 ]; then diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index c829767..d8465c8 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -364,57 +364,15 @@ jobs: echo "✓ 배포 완료: taxbaik_${TIMESTAMP} @ $DEPLOY_HOST" - # 내부 127.0.0.1:5001 헬스 체크는 Nginx/Cloudflare를 거치지 않으므로 - # Nginx 설정 오류(잘못된 파일 수정, 죽은 포트 하드코딩 등)를 잡지 못한다. - # 실제 사용자가 접속하는 경로 그대로 외부에서 검증해야 이런 장애를 CI가 스스로 잡는다. - check_public() { - local url="$1" - local allow_redirect="${2:-0}" - local must_contain="${3:-}" - local must_not_contain="${4:-}" - local status - local body - body=$(curl -fsSL --max-time 15 "$url" 2>/dev/null || true) - status=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$url" || echo "000") - if [ "$allow_redirect" = "1" ]; then - if ! printf '%s' "$status" | grep -Eq '^(200|301|302|303|307|308)$'; then - echo " ✗ $url → HTTP $status" >&2 - return 1 - fi - elif [ "$status" != "200" ]; then - echo " ✗ $url → HTTP $status" >&2 - return 1 - fi - if [ -n "$must_contain" ] && ! printf '%s' "$body" | grep -q "$must_contain"; then - echo " ✗ $url → body missing required marker: $must_contain" >&2 - return 1 - fi - if [ -n "$must_not_contain" ] && printf '%s' "$body" | grep -q "$must_not_contain"; then - echo " ✗ $url → body contains forbidden marker: $must_not_contain" >&2 - return 1 - fi - echo " ✓ $url → HTTP $status" - return 0 - } - echo "--- 실제 공개 도메인 종단 간 검증 (Nginx/Cloudflare 경유, 최대 3회 재시도) ---" - PUBLIC_OK=false - for i in 1 2 3; do - if check_public "https://www.taxbaik.com/" 1 "백원숙 세무회계" "관리자" \ - && check_public "https://www.taxbaik.com/taxbaik/" 1 "백원숙 세무회계" "관리자" \ - && check_public "https://www.taxbaik.com/taxbaik/admin/login" 0 "TaxBaik Admin" ""; then - PUBLIC_OK=true - break - fi - echo " 재시도 대기 중... ($i/3)" - sleep 5 - done - - if [ "$PUBLIC_OK" != "true" ]; then - echo "❌ FATAL: 실제 공개 도메인 검증 실패. Nginx가 죽은 포트를 가리키거나 잘못된 파일을 수정했을 가능성이 높다." >&2 - echo " 확인: sites-enabled/의 실제 파일에서 location / 은 public 홈을, /taxbaik/admin 은 관리자 앱을 가리키는지 점검" >&2 - exit 1 - fi + ROOT_URL="https://www.taxbaik.com/" \ + ADMIN_URL="https://www.taxbaik.com/taxbaik/admin/login" \ + PUBLIC_MARKER="백원숙 세무회계" \ + PUBLIC_FORBIDDEN="관리자" \ + ADMIN_MARKER="TaxBaik Admin" \ + MAX_RETRIES=3 \ + RETRY_SLEEP_SECONDS=5 \ + bash ./scripts/taxbaik-smoke.sh echo "✓ 실제 공개 도메인 전체 정상" send_telegram "✅ TaxBaik 배포 완료 diff --git a/scripts/taxbaik-smoke.sh b/scripts/taxbaik-smoke.sh new file mode 100644 index 0000000..3cd4fab --- /dev/null +++ b/scripts/taxbaik-smoke.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_URL="${ROOT_URL:-https://www.taxbaik.com/}" +ADMIN_URL="${ADMIN_URL:-https://www.taxbaik.com/taxbaik/admin/login}" +PUBLIC_MARKER="${PUBLIC_MARKER:-백원숙 세무회계}" +PUBLIC_FORBIDDEN="${PUBLIC_FORBIDDEN:-관리자}" +ADMIN_MARKER="${ADMIN_MARKER:-TaxBaik Admin}" +MAX_RETRIES="${MAX_RETRIES:-3}" +RETRY_SLEEP_SECONDS="${RETRY_SLEEP_SECONDS:-5}" + +check_page() { + local url="$1" + local allow_redirect="${2:-0}" + local must_contain="${3:-}" + local must_not_contain="${4:-}" + local status + local body + + body=$(curl -fsSL --max-time 15 "$url" 2>/dev/null || true) + status=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$url" || echo "000") + + if [ "$allow_redirect" = "1" ]; then + if ! printf '%s' "$status" | grep -Eq '^(200|301|302|303|307|308)$'; then + echo " ✗ $url -> HTTP $status" >&2 + return 1 + fi + elif [ "$status" != "200" ]; then + echo " ✗ $url -> HTTP $status" >&2 + return 1 + fi + + if [ -n "$must_contain" ] && ! printf '%s' "$body" | grep -q "$must_contain"; then + echo " ✗ $url -> body missing required marker: $must_contain" >&2 + return 1 + fi + + if [ -n "$must_not_contain" ] && printf '%s' "$body" | grep -q "$must_not_contain"; then + echo " ✗ $url -> body contains forbidden marker: $must_not_contain" >&2 + return 1 + fi + + echo " ✓ $url -> HTTP $status" +} + +for i in $(seq 1 "$MAX_RETRIES"); do + if check_page "$ROOT_URL" 1 "$PUBLIC_MARKER" "$PUBLIC_FORBIDDEN" \ + && check_page "${ROOT_URL%/}/taxbaik/" 1 "$PUBLIC_MARKER" "$PUBLIC_FORBIDDEN" \ + && check_page "$ADMIN_URL" 0 "$ADMIN_MARKER" ""; then + echo "✓ public/admin smoke passed" + exit 0 + fi + + if [ "$i" -lt "$MAX_RETRIES" ]; then + echo " retrying... ($i/$MAX_RETRIES)" + sleep "$RETRY_SLEEP_SECONDS" + fi +done + +echo "✗ smoke verification failed" >&2 +exit 1