Bash · 3160 bytes Raw Blame History
1 #!/usr/bin/env bash
2 # SPDX-License-Identifier: AGPL-3.0-or-later
3 #
4 # S40 cutover smoke test. Exercises the public-facing routes that
5 # matter at launch: landing page, signup/login forms render with
6 # a fresh CSRF token, health endpoints respond, the docs subdomain
7 # is reachable, the API authenticates a known PAT.
8 #
9 # Usage:
10 # deploy/cutover/smoke.sh https://shithub.sh
11 #
12 # Optional env (when set, the script also exercises the API):
13 # SHITHUB_SMOKE_PAT — a valid shp_ token for `user:read`
14 # SHITHUB_SMOKE_DOCS — docs subdomain URL (default: docs.<base>)
15 #
16 # Exit status:
17 # 0 — all green
18 # 1 — at least one check failed
19 # 2 — usage error
20
21 set -euo pipefail
22
23 if [[ $# -lt 1 ]]; then
24 echo "usage: $0 <base-url>" >&2
25 exit 2
26 fi
27
28 BASE="$1"
29 DOCS="${SHITHUB_SMOKE_DOCS:-${BASE/shithub./docs.shithub.}}"
30 fail=0
31
32 say() { printf '\n=== %s ===\n' "$*"; }
33 ok() { printf ' PASS: %s\n' "$*"; }
34 bad() { printf ' FAIL: %s\n' "$*"; fail=$((fail + 1)); }
35
36 # 1. Landing.
37 say "GET $BASE/"
38 body=$(curl -fsS -o - -w "\n%{http_code}\n" "$BASE/" 2>&1) || { bad "landing fetch"; body=""; }
39 if [[ "$body" == *"shithub"* ]]; then ok "body contains shithub"; else bad "body missing shithub"; fi
40
41 # 2. Health endpoints. /readyz proves DB + storage are reachable.
42 say "GET $BASE/-/health"
43 curl -fsS "$BASE/-/health" >/dev/null && ok "/-/health 200" || bad "/-/health"
44 say "GET $BASE/healthz"
45 curl -fsS "$BASE/healthz" >/dev/null && ok "/healthz 200" || bad "/healthz"
46 say "GET $BASE/readyz"
47 curl -fsS "$BASE/readyz" >/dev/null && ok "/readyz 200" || bad "/readyz"
48
49 # 3. Signup form renders.
50 say "GET $BASE/signup"
51 body=$(curl -fsS "$BASE/signup") || { bad "signup fetch"; body=""; }
52 if [[ "$body" == *"csrf_token"* ]]; then ok "CSRF token present"; else bad "no csrf_token in signup form"; fi
53
54 # 4. Login form renders.
55 say "GET $BASE/login"
56 body=$(curl -fsS "$BASE/login") || { bad "login fetch"; body=""; }
57 if [[ "$body" == *"username"* ]] && [[ "$body" == *"password"* ]]; then
58 ok "login form fields present"
59 else
60 bad "login form missing username/password"
61 fi
62
63 # 5. TLS posture. Strict-Transport-Security must be set.
64 say "TLS / HSTS"
65 hdrs=$(curl -fsS -I "$BASE/" 2>&1) || { bad "headers fetch"; hdrs=""; }
66 if grep -qi "strict-transport-security" <<<"$hdrs"; then
67 ok "HSTS header set"
68 else
69 bad "HSTS header missing"
70 fi
71 if grep -qi "x-content-type-options" <<<"$hdrs"; then
72 ok "X-Content-Type-Options set"
73 else
74 bad "X-Content-Type-Options missing"
75 fi
76
77 # 6. Docs subdomain.
78 say "GET $DOCS/"
79 curl -fsS -o /dev/null "$DOCS/" && ok "docs site 200" || bad "docs site"
80
81 # 7. API (only if a PAT is provided).
82 if [[ -n "${SHITHUB_SMOKE_PAT:-}" ]]; then
83 say "GET $BASE/api/v1/user (with PAT)"
84 body=$(curl -fsS -H "Authorization: Bearer $SHITHUB_SMOKE_PAT" "$BASE/api/v1/user") || { bad "api fetch"; body=""; }
85 if [[ "$body" == *'"username"'* ]]; then
86 ok "API returned a user object"
87 else
88 bad "API response unexpected: $body"
89 fi
90 else
91 printf ' SKIP: API check (set SHITHUB_SMOKE_PAT to run)\n'
92 fi
93
94 printf '\n'
95 if [[ "$fail" -eq 0 ]]; then
96 echo "smoke: all checks passed"
97 exit 0
98 fi
99 echo "smoke: $fail check(s) FAILED"
100 exit 1