Skip to content

Uptime Monitor

Uptime Monitor #162

Workflow file for this run

name: Uptime Monitor
# Deploy-independent liveness: the backend fail-closes on a bad egress-firewall load,
# and a load can fail on a reboot/OOM/kernel update WITHOUT a deploy (which re-runs the
# entrypoint). This cron curls the PUBLIC endpoint so such an outage is caught within
# minutes instead of by a user. Zero-infra fallback; GitHub may delay scheduled runs and
# disables schedules after 60 days of repo inactivity.
on:
schedule:
- cron: "*/10 * * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
probe:
runs-on: ubuntu-latest
steps:
- name: Curl public health endpoint
run: |
set -euo pipefail
# ~180s budget: comfortably past the documented ~130s deploy cold start (the
# entrypoint builds the XBRL store before gunicorn listens, behind a --replace
# swap), so a tick landing in a deploy window catches recovery instead of crying
# wolf. A genuinely dead endpoint (>180s) still alerts.
for i in $(seq 1 9); do
if curl -fsS -m 10 https://agenticfinsearch.org/health/ >/dev/null; then
echo "healthy (attempt $i)"
exit 0
fi
echo "attempt $i/9 failed; retrying in 20s..."
sleep 20
done
echo "::error::agenticfinsearch.org/health/ is DOWN after 9 attempts (~180s)"
exit 1
- name: Verify edge security headers
# Converts the edge headers from CONFIGURED to POSITIVELY-VERIFIED: a
# non-deferred Caddy `header` block validates fine yet ships duplicate
# HSTS lines and a silently-losing Referrer-Policy (the silent-no-op
# lesson behind the deferred block in Deploy/podman/Caddyfile.example),
# so only probing the live response proves delivery. Runs only after
# the health probe above passed, so a failure here is a HEADER
# regression, not an outage. No `-f` on curl: an HTTP error status
# still carries the deferred edge headers we assert on.
# NOTE: red until the deferred header block ships on the live edge
# Caddyfile (a separate, post-review op).
run: |
set -euo pipefail
for i in 1 2 3; do
if hdrs=$(curl -sSI -m 10 https://agenticfinsearch.org/health/); then
break
fi
if [ "$i" = 3 ]; then
echo "::error::could not fetch response headers after 3 attempts"
exit 1
fi
sleep 10
done
printf '%s\n' "$hdrs"
csp=$(printf '%s\n' "$hdrs" | grep -ic '^content-security-policy:' || true)
hsts=$(printf '%s\n' "$hdrs" | grep -ic '^strict-transport-security:' || true)
if [ "$csp" -lt 1 ]; then
echo "::error::edge response lacks Content-Security-Policy (deferred header block missing at the proxy)"
exit 1
fi
if [ "$hsts" -gt 1 ]; then
echo "::error::$hsts Strict-Transport-Security lines in one response (defer lost: Caddy + Django copies both shipped)"
exit 1
fi
echo "edge headers verified (CSP present, single HSTS)"