Uptime Monitor #162
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)" |