Phase 1: Compass/NHS skeleton (Go, SQLite, session login, Docker, Caddy)
Phase 1 of AGENTS.md §11: the app runs on .13 in its own container on port 8792, behind Caddy at school.lab.audasmedia.com.au, with its own session login and GET /health. - Go service (Go 1.25, modernc SQLite, no cgo) with its own image. - SQLite schema per AGENTS.md §7: children, items, scans, notifications, session (internal/store/migrations/001_init.sql). - Separate session login (signed cookie, CSRF double-submit), not SSO. - HTMX server-rendered shell using the Family Home Lab tokens.css: canvas #f6f5f4, action blue #0075de, Inter, 8px grid, hairline borders, pill CTAs, dark mode, phone-friendly. - Fail loudly (FR-12): a missing or failed scan shows as an explicit warning or error banner, never as an empty day. - Dockerfile + docker-compose.yml (own container, own port 8792; uses network_mode bridge because .13 has no free default Docker address pool). - Caddy snippet for .35 in deploy/caddy/, deployment notes, and deploy/verify-phase1.sh. No school scan in this phase; the Compass login and fetch are Phase 2. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
93
deploy/verify-phase1.sh
Executable file
93
deploy/verify-phase1.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 1 definition of done (AUD-103).
|
||||
#
|
||||
# - the container is up and healthy
|
||||
# - GET /health returns 200 with status ok
|
||||
# - the login page renders and a session login succeeds
|
||||
# - the Caddy route on .35 serves school.lab.audasmedia.com.au
|
||||
#
|
||||
# Run on .13 from the project folder. It reads the admin password from
|
||||
# environment.d/school-service.env, never prints it, and never touches the
|
||||
# school's systems.
|
||||
set -u
|
||||
|
||||
BASE="${SCHOOL_VERIFY_BASE:-http://127.0.0.1:8792}"
|
||||
PUBLIC="${SCHOOL_VERIFY_PUBLIC:-https://school.lab.audasmedia.com.au}"
|
||||
ENV_FILE="${SCHOOL_ENV_FILE:-environment.d/school-service.env}"
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
fail=0
|
||||
pass() { printf 'PASS %s\n' "$1"; }
|
||||
bad() { printf 'FAIL %s\n' "$1"; fail=1; }
|
||||
|
||||
echo "== container =="
|
||||
timeout 60 docker compose ps || true
|
||||
|
||||
echo
|
||||
echo "== GET /health =="
|
||||
code="$(curl -sS -o "$TMP/health.json" -w '%{http_code}' "$BASE/health" || echo 000)"
|
||||
body="$(cat "$TMP/health.json" 2>/dev/null)"
|
||||
printf 'HTTP %s\n%s\n' "$code" "$body"
|
||||
if [ "$code" = "200" ] && printf '%s' "$body" | grep -q '"status":"ok"'; then
|
||||
pass "/health 200 and status ok"
|
||||
else
|
||||
bad "/health did not return 200 status ok"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== login page =="
|
||||
curl -sS -c "$TMP/cookies" -o "$TMP/login.html" -w 'HTTP %{http_code}\n' "$BASE/login"
|
||||
if grep -q 'name="csrf"' "$TMP/login.html"; then
|
||||
pass "login page renders with a csrf token"
|
||||
else
|
||||
bad "login page did not render a csrf token"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== session login =="
|
||||
# Extract the plaintext password or use the hash-only path. With a hash-only
|
||||
# env file the operator must supply SCHOOL_VERIFY_PASSWORD.
|
||||
pw="${SCHOOL_VERIFY_PASSWORD:-}"
|
||||
if [ -z "$pw" ] && [ -f "$ENV_FILE" ]; then
|
||||
pw="$(sed -n 's/^SCHOOL_ADMIN_PASSWORD=//p' "$ENV_FILE" | head -1)"
|
||||
fi
|
||||
csrf="$(grep -o 'name="csrf" value="[^"]*"' "$TMP/login.html" | head -1 | sed 's/.*value="//; s/"//')"
|
||||
if [ -z "$pw" ]; then
|
||||
echo "SKIP no SCHOOL_VERIFY_PASSWORD and no plaintext password in $ENV_FILE"
|
||||
elif [ -z "$csrf" ]; then
|
||||
bad "no csrf token to submit"
|
||||
else
|
||||
code="$(curl -sS -b "$TMP/cookies" -c "$TMP/cookies" -o /dev/null -w '%{http_code}' \
|
||||
-d "csrf=$csrf" -d "username=sam" -d "password=$pw" "$BASE/login")"
|
||||
if [ "$code" = "303" ]; then
|
||||
dash="$(curl -sS -b "$TMP/cookies" -o "$TMP/dash.html" -w '%{http_code}' "$BASE/")"
|
||||
if [ "$dash" = "200" ] && grep -q 'What is due' "$TMP/dash.html"; then
|
||||
pass "session login succeeds and the dashboard renders"
|
||||
else
|
||||
bad "dashboard did not render after login (HTTP $dash)"
|
||||
fi
|
||||
else
|
||||
bad "login POST returned $code, expected 303"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Caddy route (.35) =="
|
||||
code="$(curl -sS -o "$TMP/pub.json" -D "$TMP/pub.headers" -w '%{http_code}' --max-time 25 "$PUBLIC/health" || echo 000)"
|
||||
printf 'HTTP %s\n' "$code"
|
||||
grep -i '^server:' "$TMP/pub.headers" 2>/dev/null || true
|
||||
grep -i '^content-type:' "$TMP/pub.headers" 2>/dev/null || true
|
||||
if [ "$code" = "200" ] && grep -qi '^server: Caddy' "$TMP/pub.headers"; then
|
||||
pass "Caddy serves $PUBLIC/health"
|
||||
else
|
||||
bad "Caddy route did not answer 200 (HTTP $code)"
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "$fail" = "0" ]; then
|
||||
echo "RESULT: Phase 1 verified"
|
||||
else
|
||||
echo "RESULT: Phase 1 verification FAILED"
|
||||
fi
|
||||
exit "$fail"
|
||||
Reference in New Issue
Block a user