#!/usr/bin/env bash # # smoke-elastic-beanstalk.sh — post-deploy smoke checks for the shoc-backend # dev environment. # # Checks: # 1. swagger.json is reachable (HTTP 200) # 2. swagger advertises release-critical webhook, login, and vendor routes # 3. protected vendor routes reject unauthenticated callers rather than 404 # 4. an unauthenticated JSON POST to the webhook returns 401 or 503 (disabled), # never 404 or a server error other than the intentional 503 # # Usage: # bash scripts/smoke-elastic-beanstalk.sh [base-url] # bash scripts/smoke-elastic-beanstalk.sh https://api.dev.seahaven.com set -euo pipefail BASE_URL="${1:-https://api.dev.seahaven.com}" BASE_URL="${BASE_URL%/}" SWAGGER_URL="$BASE_URL/swagger/v1/swagger.json" WEBHOOK_URL="$BASE_URL/api/webhooks/work-orders" log() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; } ok() { printf '\033[32mPASS\033[0m %s\n' "$1"; } die() { printf '\033[31mFAIL\033[0m %s\n' "$1" >&2; exit 1; } command -v curl >/dev/null 2>&1 || die "curl is required." mkdir -p .artifacts/elastic-beanstalk log "swagger reachable: $SWAGGER_URL" swagger_http=$(curl -sS -o .artifacts/elastic-beanstalk/swagger.json \ -w '%{http_code}' --max-time 30 "$SWAGGER_URL" || true) [[ "$swagger_http" == "200" ]] \ || die "swagger.json returned HTTP $swagger_http (expected 200)." swagger_file=".artifacts/elastic-beanstalk/swagger.json" ok "swagger.json HTTP 200" log "swagger advertises release-critical routes" required_paths=( "/api/webhooks/work-orders" "/api/Authentication/login" "/api/Vendor/facets" "/api/Vendor/{id}/deactivation-impact" "/api/vendor-operations/notifications" "/api/vendor-operations/availability" "/api/vendor-operations/sites/{locationId}/preferred-vendors" "/api/vendor-operations/work-orders/{workOrderId}/assignment" "/api/vendor-operations/insights" "/api/vendor-operations/insights.csv" "/api/vendor-operations/insights.pdf" "/api/vendor-portal/dispatches/{id}/completion-documents" "/api/vendor-portal/dispatches/{id}/completion-documents/{documentId}" "/api/vendor-portal/dispatches/{id}/documents" "/api/vendor-portal/dispatches/{id}/documents/{documentId}" ) for path in "${required_paths[@]}"; do grep -Fq "\"$path\"" "$swagger_file" \ || die "swagger.json missing $path route." done ok "release-critical webhook, login, and vendor routes present" assert_protected_route() { local url="$1" local route_http route_http=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 30 "$url" || true) case "$route_http" in 401|403) ok "$url rejected an unauthenticated caller with HTTP $route_http." ;; 404) die "$url returned 404 — route not wired (deployment broken)." ;; 5*) die "$url returned HTTP $route_http — unexpected server error." ;; *) die "$url returned HTTP $route_http — expected 401 or 403." ;; esac } log "protected vendor routes are wired" assert_protected_route "$BASE_URL/api/Vendor/facets" assert_protected_route "$BASE_URL/api/vendor-operations/notifications" assert_protected_route "$BASE_URL/api/Vendor/1/deactivation-impact" log "vendor portal rejects a missing token" portal_session_http=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 30 \ "$BASE_URL/api/vendor-portal/session" || true) [[ "$portal_session_http" == "401" ]] \ || die "vendor portal session returned HTTP $portal_session_http (expected 401)." ok "vendor portal session returned 401 without a token" log "unauthenticated webhook POST: $WEBHOOK_URL" webhook_http=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 30 \ -X POST -H 'Content-Type: application/json' \ --data '{"smoke":true}' "$WEBHOOK_URL" || true) case "$webhook_http" in 401) ok "webhook returned 401 (unauthorized) as expected." ;; 503) ok "webhook returned 503 (intentionally disabled) as expected." ;; 404) die "webhook returned 404 — route not wired (deployment broken)." ;; 5*) die "webhook returned HTTP $webhook_http — unexpected server error." ;; *) die "webhook returned HTTP $webhook_http — expected 401 or 503." ;; esac log "smoke: all checks passed"