#!/bin/bash # Verify the latest GCS backup is restorable in a throwaway local Docker setup. # Run from a workstation with gcloud + docker. Does not touch the production VM. # # Usage: ./test-restore.sh [project-id] # project-id defaults to the active gcloud project set -euo pipefail PROJECT=${1:-$(gcloud config get-value project 2>/dev/null)} if [[ -z "$PROJECT" ]]; then echo "ERROR: no project specified and no active gcloud project." >&2 exit 1 fi BUCKET="${PROJECT}-forgejo-backups" WORKDIR=$(mktemp -d -t forgejo-test-restore.XXXXXX) trap 'docker rm -f forgejo-test >/dev/null 2>&1 || true; rm -rf "$WORKDIR"' EXIT echo "Workdir: $WORKDIR" LATEST=$(gsutil ls "gs://${BUCKET}/" | grep '\.tar\.gz$' | sort | tail -1) if [[ -z "$LATEST" ]]; then echo "ERROR: no backups found in gs://${BUCKET}/" >&2 exit 1 fi echo "Latest backup: $LATEST" gsutil cp "$LATEST" "$WORKDIR/backup.tar.gz" tar xzf "$WORKDIR/backup.tar.gz" -C "$WORKDIR" if [[ ! -d "$WORKDIR/forgejo" ]]; then echo "ERROR: tarball does not contain a 'forgejo' directory" >&2 exit 1 fi if [[ ! -f "$WORKDIR/forgejo/gitea/gitea.db" ]]; then echo "ERROR: SQLite DB missing from backup" >&2 exit 1 fi # Boot Forgejo against the restored data and probe it. docker run -d --rm --name forgejo-test \ -p 13000:3000 \ -v "$WORKDIR/forgejo:/data" \ -e FORGEJO__server__DISABLE_SSH=true \ -e FORGEJO__database__DB_TYPE=sqlite3 \ codeberg.org/forgejo/forgejo:11 >/dev/null echo "Waiting for Forgejo to start..." for i in $(seq 1 30); do if curl -sf http://localhost:13000/api/v1/version >/dev/null; then echo "OK: Forgejo responded with version: $(curl -s http://localhost:13000/api/v1/version)" REPOS=$(curl -s http://localhost:13000/api/v1/repos/search?limit=1 | python3 -c 'import sys,json; d=json.load(sys.stdin); print(len(d.get("data", [])))') echo "OK: API repos endpoint returned $REPOS result(s)" echo "PASS: backup is restorable" exit 0 fi sleep 2 done echo "FAIL: Forgejo did not respond within 60s" >&2 docker logs forgejo-test >&2 || true exit 1