From 0d12e045440ce84560be7e46712201d66803ec7e Mon Sep 17 00:00:00 2001 From: MP2EZ <182439403+MP2EZ@users.noreply.github.com> Date: Mon, 25 May 2026 17:49:01 -0700 Subject: [PATCH] chore(ci): post-deploy smoke + prod env build + extended route coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes three deployment-confidence gaps that the recent prod cutover (PR #37) made visible. # 1. Build with NEXT_PUBLIC_SHOW_FULL_SITE='true' in wrangler-smoke CI previously built without the env var, so the / → /home redirect codepath (production behavior) was never exercised in CI. Now matches the deploy.yml build mode. Readiness probe switched from / (now 307) to /home (always 200) so wrangler-dev startup detection still works. # 2. Extend wrangler-smoke route coverage Old coverage: POST /api/waitlist + GET /crisis (2 routes). New coverage adds 4 routes: - GET / → 307 with location: /home - GET /home → 200 + 'Mindfulness with meaning' body marker - GET /download → 200 + 'Coming soon' marker, NOT 'graphic needed' (catches if the page regresses to the pre-#36 placeholder badges) - GET /privacy/multi-state → 200 + 'Multi-State' body marker Each follows the existing /crisis assertion pattern. # 3. Post-deploy smoke against live URL (deploy.yml) Catches the failure mode CI cannot reach: DNS misconfig, custom-domain unbound, SSL broken, deploy succeeded-but-routed-wrong. After the wrangler-action deploy command succeeds: - Branch-aware URL (main → being.fyi, preview → workers.dev) - 15s sleep for Cloudflare edge propagation - Cache-busted curl on /home (200), /download (Coming soon marker), /privacy (Strict-Transport-Security header) - FAIL exits the workflow loudly so an alert fires Note on the 'Coming soon' assertion: temporary marker tied to pre-launch state. When the app launches and /download swaps to real app-store badges, update this assertion or replace with a durable marker like the H1 text. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 64 +++++++++++++++++++++++++++++++++++- .github/workflows/deploy.yml | 27 +++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 914fbae..cf7f630 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,6 +92,10 @@ jobs: run: npm ci - name: Build worker with OpenNext + env: + # Match the production build mode so the / → /home redirect path + # and the rest of the (main) layout behavior is what gets smoked. + NEXT_PUBLIC_SHOW_FULL_SITE: 'true' run: npx opennextjs-cloudflare build - name: Start wrangler dev in background @@ -101,8 +105,9 @@ jobs: - name: Wait for worker readiness run: | + # Probe /home (always 200) instead of / (now 307 under SHOW_FULL_SITE=true). for i in {1..30}; do - if curl -sf -o /dev/null http://localhost:8787/; then + if curl -sf -o /dev/null http://localhost:8787/home; then echo "Worker ready after ${i} attempt(s)" exit 0 fi @@ -158,6 +163,63 @@ jobs: fi echo "GET /crisis smoke + headers smoke passed." + - name: GET / redirects to /home (production codepath) + run: | + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8787/) + if [ "$HTTP_CODE" != "307" ] && [ "$HTTP_CODE" != "308" ]; then + echo "Expected 307/308 redirect from /, got $HTTP_CODE" + exit 1 + fi + LOCATION=$(curl -sI http://localhost:8787/ | grep -i '^location:' | tr -d '\r' | awk '{print $2}') + if [ "$LOCATION" != "/home" ]; then + echo "Expected location: /home, got '$LOCATION'" + exit 1 + fi + echo "GET / redirect smoke passed." + + - name: GET /home renders + run: | + curl -s -i -o /tmp/home.txt http://localhost:8787/home + if ! head -1 /tmp/home.txt | grep -q " 200 "; then + echo "Expected HTTP 200 on /home" + exit 1 + fi + if ! grep -qi "Mindfulness with meaning" /tmp/home.txt; then + echo "Expected 'Mindfulness with meaning' in /home body" + exit 1 + fi + echo "GET /home smoke passed." + + - name: GET /download renders pre-launch waitlist + run: | + curl -s -i -o /tmp/download.txt http://localhost:8787/download + if ! head -1 /tmp/download.txt | grep -q " 200 "; then + echo "Expected HTTP 200 on /download" + exit 1 + fi + if ! grep -qi "Coming soon" /tmp/download.txt; then + echo "Expected 'Coming soon' in /download body (pre-launch waitlist marker)" + exit 1 + fi + if grep -qi "graphic needed" /tmp/download.txt; then + echo "Found 'graphic needed' placeholder text — /download regressed to old badges" + exit 1 + fi + echo "GET /download smoke passed." + + - name: GET /privacy/multi-state renders + run: | + curl -s -i -o /tmp/multistate.txt http://localhost:8787/privacy/multi-state + if ! head -1 /tmp/multistate.txt | grep -q " 200 "; then + echo "Expected HTTP 200 on /privacy/multi-state" + exit 1 + fi + if ! grep -qi "Multi-State" /tmp/multistate.txt; then + echo "Expected 'Multi-State' in /privacy/multi-state body" + exit 1 + fi + echo "GET /privacy/multi-state smoke passed." + - name: Stop wrangler dev if: always() run: | diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9f32aa1..2540605 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -61,3 +61,30 @@ jobs: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} command: deploy ${{ github.ref_name == 'preview' && '--env preview' || '' }} + + - name: Post-deploy smoke against live URL + run: | + URL="${{ github.ref_name == 'main' && 'https://being.fyi' || 'https://being-website-preview.palouselabs.workers.dev' }}" + echo "Smoke testing $URL ..." + # Brief wait for Cloudflare edge propagation after deploy + sleep 15 + # Cache-bust query param to avoid stale edge responses + CB="?cb=$(date +%s)" + # /home must return 200 + HOME_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL/home$CB") + if [ "$HOME_CODE" != "200" ]; then + echo "FAIL: $URL/home returned $HOME_CODE (expected 200)" + exit 1 + fi + # /download must contain pre-launch marker (update at app launch) + if ! curl -sf "$URL/download$CB" | grep -q "Coming soon"; then + echo "FAIL: $URL/download body missing 'Coming soon' marker" + exit 1 + fi + # /privacy must serve security headers (HSTS proves the security + # headers pipeline is intact end-to-end through Cloudflare) + if ! curl -sI "$URL/privacy" | grep -qi "strict-transport-security"; then + echo "FAIL: $URL/privacy missing Strict-Transport-Security header" + exit 1 + fi + echo "Post-deploy smoke passed for $URL"