feat: daily encrypted DB backup and production health alerting - #110
Merged
Conversation
Closes the zero-backup posture from openadapt-cloud AUDIT.md finding (b) (pitr_enabled=false, zero provider physical backups as of 2026-07-25) with a $0 recovery point: - .github/workflows/db-backup.yml: daily supabase db dump of the runbook triple (roles/schema/data), fail-closed on missing config or a schema-only dump, encrypted with age to a public key committed in-repo, uploaded as a workflow artifact with 90-day retention. The repo is public, so artifacts are world-downloadable ciphertext; the private key stays offline with the founder. - ops/backup/age-recipients.txt: recipient file (comments only until the founder commits the real public key; the workflow fails until then). - ops/backup/RESTORE_DRILL.md: keypair generation, scratch-restore drill matching the cloud data-safety runbook, RPO/cost tradeoff table, and key-rotation/compromise procedure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
$0 pager: probes https://app.openadapt.ai/api/health/ready (the genuine dependency probe from openadapt-cloud src/lib/readiness.ts), retries 3 times over ~2 minutes to absorb transient blips, prints per-component not-ready detail, and fails the run loudly so GitHub emails on scheduled failure. Optionally pages via Telegram when the crier bot secrets (TELEGRAM_BOT_TOKEN/TELEGRAM_OWNER_ID) are configured as repo secrets. Documents the 60-day scheduled-workflow auto-disable caveat (daily docs sync currently provides keepalive activity). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the two operational blockers for the hosted path: production DB has no backups (openadapt-cloud
AUDIT.mdfinding (b):pitr_enabled=false, zero provider physical backups as of 2026-07-25), and there is no automated alerting.Part A — daily encrypted logical backup (
db-backup.yml)supabase db dumpof the exact triple the cloud data-safety runbook prescribes:roles.sql(--role-only),schema.sql,data.sql(--use-copy --data-only, excluding the storage vector tables). A single unflagged dump is schema-only and is not a backup.SUPABASE_DB_URLor the age recipient is missing, and refuses to upload an empty/schema-only dump. A red daily run is the reminder that prod still has no recovery point.ageto a public key committed in-repo (ops/backup/age-recipients.txt, currently comments-only — founder commits the real key). Private key is generated by the founder and stays offline/vault; nothing secret was generated in this PR. This repo is public, so artifacts are downloadable by any logged-in GitHub user — the encryption is load-bearing.psql --single-transactionorder as the cloud runbook):ops/backup/RESTORE_DRILL.md.Founder actions required (backup is dark until done)
$0 vs paid — honest tradeoff (Supabase public pricing, checked 2026-08-02)
pg_dump, encrypted artifact, 90d retentionAnswer: yes, we reach a recovery point for $0 (once the founder does the 3 steps above). Recommendation: buy Supabase Pro ($25/mo) now — cheapest change that makes
provider-status --require-recoverypass and gives provider-side physical restore; defer the PITR add-on (~$110-140/mo all-in) until at least one paying pilot (at N=0, 24h RPO with a drilled restore is defensible). Storage buckets are covered by neither option; bucket export stays with the cloudretentiondrill tooling.Part B — health alerting (
prod-health-alert.yml)https://app.openadapt.ai/api/health/ready— verified live today (200,"ready":true); this is the genuine dependency probe (src/lib/readiness.ts), not a static page.NOT READYdetail, then fails the run loudly — GitHub emails on scheduled-workflow failure: the $0 pager.TELEGRAM_BOT_TOKEN,TELEGRAM_OWNER_ID); neither exists in this repo today, so the step self-skips. To enable:gh secret set TELEGRAM_BOT_TOKEN --repo OpenAdaptAI/openadapt-opsandgh secret set TELEGRAM_OWNER_ID --repo OpenAdaptAI/openadapt-ops.RESTORE_DRILL.md§6: GitHub auto-disables schedules after 60 days without repo activity (the daily docssync.ymlcommit currently provides keepalive; if it stops, schedules die silently), and failure emails go to the last committer of the workflow file.Cost discipline
openadapt-opsis public → Actions minutes and artifact storage are free. Backup: 1 run/day. Health: 48 runs/day × <1 min ≈ trivial even if metered. Both workflows pin actions by SHA and follow the repo's existing conventions (least-privilegepermissions, concurrency groups, graceful degradation for optional secrets).Validated with
actionlint(pass); probe script smoke-tested against the live endpoint (healthy and failure branches).🤖 Generated with Claude Code