#!/usr/bin/env bash # 운영 스모크 — GET 전용, API 키 없이 호출. KIS/주문 경로 호출 없음. # - PUBLIC : 키 없이 200 + 유효 JSON 이어야 한다 (공개 시장 데이터) # - AUTH : 키 없이 401 이어야 한다 (계좌·손익·리스크 상태). 200 이면 **노출 회귀**로 FAIL, # 5xx/000 이면 기동 실패로 FAIL. (2026-10-02 H-1: journals/analysis 가 키 없이 응답하던 결함) # 사용: .claude/scripts/prod_smoke.sh (환경변수 PROD_BASE_URL 로 대상 변경 가능) set -u BASE="${PROD_BASE_URL:-https://stock.shium.net}" PUBLIC_ENDPOINTS=( "/api/v1/market/indices" ) AUTH_ENDPOINTS=( "/api/v1/journals/stats" "/api/v1/analysis/performance" "/api/v1/market-intelligence/dashboard" ) fail=0 echo "== 운영 스모크 ($BASE) $(TZ=Asia/Seoul date '+%Y-%m-%d %H:%M:%S KST') ==" probe() { # $1=kind(PUBLIC|AUTH) $2=endpoint local kind="$1" ep="$2" tmp out code secs bytes valid mark tmp="$(mktemp)" out="$(curl -s -o "$tmp" -w '%{http_code} %{time_total}' --max-time 15 "$BASE$ep" 2>/dev/null)" || out="000 0" code="${out%% *}"; secs="${out##* }" bytes="$(wc -c < "$tmp" | tr -d ' ')" valid="-" if [ "$kind" = "PUBLIC" ]; then if command -v python3 >/dev/null 2>&1 && [ "$code" = "200" ]; then python3 -c 'import json,sys; json.load(open(sys.argv[1]))' "$tmp" 2>/dev/null && valid="json-ok" || valid="json-INVALID" fi if [ "$code" = "200" ] && [ "$valid" != "json-INVALID" ]; then mark="OK "; else mark="FAIL"; fail=1; fi else if [ "$code" = "401" ]; then mark="OK "; valid="auth-enforced" elif [ "$code" = "200" ]; then mark="FAIL"; valid="LEAK(키 없이 200)"; fail=1 else mark="FAIL"; fail=1; fi fi printf '%s %-6s %s http=%s %ss %sB %s\n' "$mark" "$kind" "$ep" "$code" "$secs" "$bytes" "$valid" if [ "$mark" = "FAIL" ] && [ "$code" != "200" ]; then head -c 200 "$tmp" | sed 's/^/ /'; echo; fi rm -f "$tmp" } for ep in "${PUBLIC_ENDPOINTS[@]}"; do probe PUBLIC "$ep"; done for ep in "${AUTH_ENDPOINTS[@]}"; do probe AUTH "$ep"; done [ "$fail" = 0 ] && echo "== 스모크 통과 ==" || echo "== 스모크 실패 — Jenkins 로그/컨테이너 상태 확인 (LEAK 이면 인증 회귀) ==" exit "$fail"