Files
freno-dev/scripts/verify-deploy.sh
agent-senior-engineer 91bedd915d docs(deploy): name the retention cron the first mirror fires, and probe the root (FRE-1707)
Two findings from the FRE-1695 review (approved at df788cb6).

1. The mirrored deploy activates a destructive cron the deploy docs never
   mentioned. vercel.json carries two crons: /api/the-nook/lifecycle (13:00
   UTC), already on the tree Vercel builds, and /api/analytics-retention
   (12:00 UTC, 1d9287a / FRE-369), which exists only on Gitea master. The first
   deploy that follows the mirror starts calling it, and the next 12:00 UTC
   deletes every VisitorAnalytics row older than the window —
   ANALYTICS_RETENTION_DAYS, 365 by default — irreversibly and unstaged. The
   behaviour is intended; the silence was not, because the operator is the one
   who presses the button. docs/deploy-source.md "Failure modes" now names the
   cron, the ANALYTICS_RETENTION_SECRET ?? CRON_SECRET bearer check, the 365-day
   default, the fails-closed-without-a-secret path, and that the first run after
   enabling prunes at that default.

2. scripts/verify-deploy.sh could read green with a broken root deploy: it
   probed nook.freno.me, nessa.freno.me/terms and the two remotes, never
   freno.me itself — and FRE-1695's acceptance names the root domain. Adds a
   ROOT_HOST (default https://freno.me) status check ahead of the subdomain
   probes: expects a direct 200, no -L, so a redirect reads as a failure. It
   deliberately does not probe https://freno.me/terms — SITEMAP_ROUTES.main has
   no /terms; Terms of Use is a Nessa surface, so a root /terms 404 is the
   design. The script stays read-only and credential-free.
2026-11-10 03:02:57 +00:00

102 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# Live probe for the freno-dev deploy path (FRE-1695). Read-only; no credentials.
#
# Proves, in one run:
# 1. Gitea master and GitHub master are the same commit (the mirror converged).
# 2. The root domain answers on its own terms: https://freno.me/ returns a direct 200,
# so a broken root deploy cannot read as green while the subdomains look fine.
# 3. The live site serves copy that only exists on the reconciled line:
# NOOK-1038's scoped remote claim (GitHub-only before the merge) *and*
# FRE-997's "Supported agents" (Gitea-only before the merge). Both at once
# can only come from the merge commit.
# 4. The served tree therefore contains FRE-371 (`2fd2a4a`), which is an
# ancestor of that merge — checked locally when the commit is in the object
# store, so run this from a freno-dev checkout.
#
# Usage: scripts/verify-deploy.sh [expected-gitea-sha]
set -uo pipefail
GITEA_REMOTE="${GITEA_REMOTE:-https://git.freno.me/Mike/freno-dev.git}"
GITHUB_REMOTE="${GITHUB_REMOTE:-https://github.com/mikefreno/freno-dev.git}"
ROOT_HOST="${ROOT_HOST:-https://freno.me}"
NOOK_HOST="${NOOK_HOST:-https://nook.freno.me}"
NESSA_HOST="${NESSA_HOST:-https://nessa.freno.me}"
fail=0
ok() { printf 'ok %s\n' "$1"; }
bad() { printf 'FAIL %s\n' "$1"; fail=1; }
echo "== remotes =="
gitea_sha=$(git ls-remote "$GITEA_REMOTE" refs/heads/master | cut -f1)
github_sha=$(git ls-remote "$GITHUB_REMOTE" refs/heads/master | cut -f1)
printf 'gitea master %s\ngithub master %s\n' "${gitea_sha:-<none>}" "${github_sha:-<none>}"
[ -n "$gitea_sha" ] && ok "gitea master readable" || bad "gitea master unreadable"
if [ -n "$gitea_sha" ] && [ "$gitea_sha" = "$github_sha" ]; then
ok "github master is the same commit (mirror converged)"
else
bad "github master differs from gitea master — the mirror has not run"
fi
if [ -n "${1:-}" ]; then
if [ "$1" = "$gitea_sha" ]; then ok "gitea master is the expected commit $1"
else bad "gitea master is $gitea_sha, expected $1"; fi
fi
echo
echo "== live copy =="
# The root is every other surface's entry point and deploys from the same tree, so it is
# probed first. No -L: a redirect away from 200 is the failure we want to see, not a pass.
root_code=$(curl -sS -o /dev/null -w '%{http_code}' "$ROOT_HOST/" 2>/dev/null)
if [ "$root_code" = "200" ]; then
ok "$ROOT_HOST/ serves 200"
elif [ -z "$root_code" ] || [ "$root_code" = "000" ]; then
bad "$ROOT_HOST/ gave no response, expected 200"
else
bad "$ROOT_HOST/ returned $root_code, expected 200 (green subdomains do not cover the root)"
fi
page=$(curl -sS "$NOOK_HOST/" 2>/dev/null)
case "$page" in
*"One-click setup for Tailscale and authorized known hosts"*)
ok "nook landing carries NOOK-1038's scoped remote claim" ;;
*) bad "nook landing is missing NOOK-1038's scoped remote claim" ;;
esac
agents=$(curl -sS "$NOOK_HOST/agents" 2>/dev/null)
case "$agents" in
*"Supported agents"*) ok "nook /agents carries FRE-997's restored coverage title" ;;
*) bad "nook /agents still serves the pre-FRE-997 title" ;;
esac
terms_code=$(curl -sS -o /tmp/verify-deploy-terms.$$ -w '%{http_code}' "$NESSA_HOST/terms" 2>/dev/null)
if [ "$terms_code" = "200" ] && grep -q 'nessa-support@freno.me' /tmp/verify-deploy-terms.$$; then
ok "nessa /terms is published and names the support address (FRE-1670)"
else
bad "nessa /terms returned $terms_code without the support address (FRE-1670 undeployed)"
fi
rm -f /tmp/verify-deploy-terms.$$
echo
echo "== ancestry =="
for commit in 2fd2a4a 7fde259; do
if git cat-file -e "${commit}^{commit}" 2>/dev/null; then
if git merge-base --is-ancestor "$commit" "$gitea_sha" 2>/dev/null; then
ok "$commit is an ancestor of gitea master"
else
bad "$commit is NOT an ancestor of gitea master"
fi
else
printf 'skip %s not in this clone; run from a freno-dev checkout to check ancestry\n' "$commit"
fi
done
echo
if [ "$fail" -eq 0 ]; then
echo "PASS — the deploy follows gitea master and the served tree contains FRE-371."
else
echo "FAIL — see the lines above."
fi
exit "$fail"