Skip to content

Nightly DB backup

Nightly DB backup #4

Workflow file for this run

name: Nightly DB backup
# Nightly logical backup of the mainnet and testnet Postgres databases, so a
# lost or capped managed instance has a minutes-not-days restore path. See
# docs/backup-restore.md for the restore procedure. This is the durability
# fallback noted in docs/DUAL_NETWORK.md (#165) — Wraith's data is also
# re-derivable by re-indexing from chain, so this backup exists to make that
# unnecessary, not because it's the only copy.
on:
schedule:
# Nightly at 03:00 UTC.
- cron: "0 3 * * *"
workflow_dispatch:
inputs:
network:
description: "Network to back up"
required: false
default: "both"
type: choice
options:
- both
- testnet
- mainnet
jobs:
backup-testnet:
name: pg_dump (testnet)
if: ${{ github.event.inputs.network == '' || github.event.inputs.network == 'both' || github.event.inputs.network == 'testnet' }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Check secrets are configured
id: check
env:
DATABASE_URL_TESTNET: ${{ secrets.DATABASE_URL_TESTNET }}
BACKUP_PASSPHRASE: ${{ secrets.BACKUP_PASSPHRASE }}
run: |
if [[ -z "$DATABASE_URL_TESTNET" ]]; then
echo "::warning::DATABASE_URL_TESTNET is not set — skipping testnet backup."
echo "configured=false" >> "$GITHUB_OUTPUT"
elif [[ -z "$BACKUP_PASSPHRASE" ]]; then
# Skip rather than dump: this repository is public, so an
# unencrypted artifact would be world-readable. A missing backup is
# recoverable — Wraith re-derives its data by re-indexing — whereas
# a published one is not.
echo "::warning::BACKUP_PASSPHRASE is not set — skipping testnet backup rather than writing an unencrypted dump."
echo "configured=false" >> "$GITHUB_OUTPUT"
else
echo "configured=true" >> "$GITHUB_OUTPUT"
fi
- name: Install postgresql-client
if: steps.check.outputs.configured == 'true'
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends postgresql-client
- name: Dump and compress
if: steps.check.outputs.configured == 'true'
env:
NETWORK: testnet
DATABASE_URL: ${{ secrets.DATABASE_URL_TESTNET }}
BACKUP_PASSPHRASE: ${{ secrets.BACKUP_PASSPHRASE }}
run: |
chmod +x ops/backup/dump.sh
ops/backup/dump.sh
- name: Upload backup artifact
if: steps.check.outputs.configured == 'true'
uses: actions/upload-artifact@v4
with:
name: wraith-db-backup-testnet-${{ github.run_id }}
# Encrypted files only. The glob is deliberately not `*.dump.gz*` —
# if encryption ever fails to run, this must find nothing and fail the
# job, not quietly publish the cleartext dump.
path: backups/*.dump.gz.gpg
retention-days: 14
if-no-files-found: error
backup-mainnet:
name: pg_dump (mainnet)
if: ${{ github.event.inputs.network == '' || github.event.inputs.network == 'both' || github.event.inputs.network == 'mainnet' }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Check secrets are configured
id: check
env:
DATABASE_URL_MAINNET: ${{ secrets.DATABASE_URL_MAINNET }}
BACKUP_PASSPHRASE: ${{ secrets.BACKUP_PASSPHRASE }}
run: |
if [[ -z "$DATABASE_URL_MAINNET" ]]; then
echo "::warning::DATABASE_URL_MAINNET is not set — skipping mainnet backup."
echo "configured=false" >> "$GITHUB_OUTPUT"
elif [[ -z "$BACKUP_PASSPHRASE" ]]; then
# Skip rather than dump: this repository is public, so an
# unencrypted artifact would be world-readable. A missing backup is
# recoverable — Wraith re-derives its data by re-indexing — whereas
# a published one is not.
echo "::warning::BACKUP_PASSPHRASE is not set — skipping mainnet backup rather than writing an unencrypted dump."
echo "configured=false" >> "$GITHUB_OUTPUT"
else
echo "configured=true" >> "$GITHUB_OUTPUT"
fi
- name: Install postgresql-client
if: steps.check.outputs.configured == 'true'
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends postgresql-client
- name: Dump and compress
if: steps.check.outputs.configured == 'true'
env:
NETWORK: mainnet
DATABASE_URL: ${{ secrets.DATABASE_URL_MAINNET }}
BACKUP_PASSPHRASE: ${{ secrets.BACKUP_PASSPHRASE }}
run: |
chmod +x ops/backup/dump.sh
ops/backup/dump.sh
- name: Upload backup artifact
if: steps.check.outputs.configured == 'true'
uses: actions/upload-artifact@v4
with:
name: wraith-db-backup-mainnet-${{ github.run_id }}
# Encrypted files only. The glob is deliberately not `*.dump.gz*` —
# if encryption ever fails to run, this must find nothing and fail the
# job, not quietly publish the cleartext dump.
path: backups/*.dump.gz.gpg
retention-days: 14
if-no-files-found: error