backup-verification-author
Author backup-verification harness - per-backup-type integrity (SHA-256 / encrypted-payload signature), restore-to-test-env spot-check cadence, partial-restore (single-table / single-object) verification, cross-region replication validation, retention-policy assertions. "An untested backup is not a backup." Use when a service's backups have never been restore-tested, when the backup tool is being swapped, or when an audit needs proof that backups are integrity-checked and restorable.
Install with skills.sh (any agent)
npx skills add testland/qa --skill backup-verification-authorbackup-verification-author
Backups silently fail in many ways - wrong encryption key, missing volume, corrupted file, expired credential. Per the Google Cloud DR planning guide (opens in new window), DR success requires "end-to-end recovery design addressing backup, restoration, and cleanup procedures." This skill authors the verification harness.
When to use
Step 1 - Catalog backup types
## Backup Catalog - `<service>`
| Type | Source | Frequency | Retention | Tool |
|---|---|---|---|---|
| Full DB dump | postgres prod | Daily 02:00 UTC | 30 days | pg_dump + S3 |
| Logical schema | postgres prod | Hourly | 24 hours | logical replication slot |
| File store | S3 prod bucket | Continuous | 90 days | S3 versioning + cross-region |
| Audit log | append-only S3 | Continuous | 7 years | S3 + Glacier |
| Secrets / KMS keys | Vault prod | Daily | 7 days | Vault snapshot + encrypted S3 |Each row needs its own verification step (Step 3).
Step 2 - Integrity checks at backup time
#!/usr/bin/env bash
set -e
BACKUP_FILE="postgres-prod-$(date +%Y%m%d).sql.gz"
BACKUP_PATH="/backups/$BACKUP_FILE"
# Take backup
pg_dump -h prod-db -U replica db_name | gzip > "$BACKUP_PATH"
# Generate SHA-256 + sign
sha256sum "$BACKUP_PATH" > "$BACKUP_PATH.sha256"
gpg --detach-sign --armor "$BACKUP_PATH"
# Upload to backup destination
aws s3 cp "$BACKUP_PATH" "s3://backup/postgres/$BACKUP_FILE"
aws s3 cp "$BACKUP_PATH.sha256" "s3://backup/postgres/$BACKUP_FILE.sha256"
aws s3 cp "$BACKUP_PATH.asc" "s3://backup/postgres/$BACKUP_FILE.asc"
# Tag with metadata
aws s3api put-object-tagging \
--bucket backup --key "postgres/$BACKUP_FILE" \
--tagging 'TagSet=[{Key=integrity_verified,Value=true},{Key=created,Value='$(date -Iseconds)'}]'Tests assert:
Step 3 - Restore-to-test-env spot check
A restore that has never been done is not a backup. Schedule:
# CI cron: weekly random sample
- cron: "0 4 * * 1" # Monday 04:00 UTC
job:
- name: Pick random backup
run: |
DAYS=(1 7 14 30)
DAYS_AGO=${DAYS[$RANDOM % ${#DAYS[@]}]}
BACKUP=$(date -d "$DAYS_AGO days ago" +%Y%m%d)
echo "BACKUP=postgres-prod-$BACKUP.sql.gz" >> $GITHUB_ENV
- name: Verify integrity
run: |
aws s3 cp s3://backup/postgres/$BACKUP.sha256 .
aws s3 cp s3://backup/postgres/$BACKUP .
sha256sum -c "$BACKUP.sha256"
- name: Restore to test DB
run: |
gunzip "$BACKUP"
psql -h test-db -U test -f "${BACKUP%.gz}" db_test
- name: Spot check
run: |
psql -h test-db -U test db_test -c "SELECT COUNT(*) FROM orders WHERE created_at > NOW() - INTERVAL '1 day'"
# Verify count > 0 (or whatever invariant fits)Step 4 - Partial-restore test
Real DR scenarios often need single-table or single-object restore (not full DB):
# Single-table extract + restore
pg_restore --table=orders --data-only \
-h test-db -U test -d db_test \
postgres-prod-backup.dumpTest: extract one table; assert rowcount + checksum match the production-time snapshot.
For S3 single-object:
aws s3 cp \
s3://backup-versioned/object-key \
--version-id "VERSION_ID_AT_DESIRED_TIME" \
./restored-objectStep 5 - Cross-region replication test
def test_backup_replicated_to_dr_region():
# Take a backup in primary region
backup_path_primary = take_backup_to(region="us-east-1")
# Wait for replication SLA
deadline = time.time() + 300 # 5 min SLA
while time.time() < deadline:
if exists_in(region="us-west-2", path=backup_path_primary):
return
time.sleep(10)
pytest.fail("Cross-region replication exceeded 5min SLA")Per the Google Cloud DR planning guide (opens in new window): "Security synchronization" also matters - DR region must have the same KMS keys / IAM / secrets, not just the data.
Step 6 - Retention-policy verification
def test_old_backups_purged_per_retention_policy():
# 30-day retention; 100-day-old backup should not exist
target = (datetime.utcnow() - timedelta(days=100)).strftime("%Y%m%d")
obj_key = f"postgres/postgres-prod-{target}.sql.gz"
response = s3.head_object(Bucket="backup", Key=obj_key)
# Should 404
pytest.fail(f"Backup {obj_key} still exists past 30-day retention")Wrap in a try/except - actual missing object = pass.
def test_recent_backups_present():
# Last 30 days should have at least one daily backup each
for d in range(30):
date = (datetime.utcnow() - timedelta(days=d)).strftime("%Y%m%d")
key = f"postgres/postgres-prod-{date}.sql.gz"
s3.head_object(Bucket="backup", Key=key) # raises if missingStep 7 - Encryption verification
For encrypted backups, verify both:
def test_backup_encrypted_with_correct_key():
obj = s3.head_object(Bucket="backup", Key=key)
assert obj["ServerSideEncryption"] == "aws:kms"
assert obj["SSEKMSKeyId"] == EXPECTED_KMS_KEY_ARNStep 8 - Customer-induced backup test (compliance)
Some regulations (HIPAA, SOC 2) require demonstrated ability to restore on demand. Author the workflow:
## Customer-Induced Backup Restore Test
1. Customer requests demo restore via support ticket.
2. SRE picks a random recent backup; restores to clean isolated env.
3. Customer verifies their data via read-only SQL or UI.
4. Cleanup: tear down env, sanitize logs.
5. Document: ticket + timestamps + verification artifacts → audit log.Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Verify backup file exists; not contents | Corrupt files pass | SHA + restore (Steps 2-3) |
| Test restore once, never again | Bit rot, key rotation, schema drift surface later | Weekly cadence (Step 3) |
| Skip partial-restore test | Real DR usually wants partial; full restore takes too long | Step 4 |
| Skip key recovery | Backup encrypted with key not in DR region; useless | Step 7 |
| Trust replication "succeeded" status | Async replication can claim success then fail | Step 5 explicit verification |
Limitations
References
Related skills
dr-drill-runner
Author and execute a single DR drill for one service: author the runbook (per-tier RTO + RPO), pre-drill checklist (data sync state, alert silencing, customer comms), drill workflow (announce, fail-over, verify, fail-back) with timestamps, standby verification, failback, and an auditor-ready post-drill report. Per Google Cloud DR planning guide; covers cold / warm / hot standby tier-specific patterns. For coordinating drills across multiple services or teams, use a multi-service drill orchestrator. Use when a scheduled or post-incident failover drill for one service is being planned, executed, or written up, or when a new tier-1 service ships without a drill defined.
error-budget-tests
Build error-budget gate tests - SLO + error-budget calculation per Google SRE workbook ("difference between target uptime and actual uptime"); burn-rate alerting; monthly-budget exhaustion test; freeze-trigger when budget consumed. Per sre.google embracing-risk reference. Use when an SLO and error budget are written down but nothing verifies that burn-rate alerts fire or that the release freeze engages when the budget runs out.
mttr-mtbf-tracker
Reference for tracking MTTR (Mean Time To Recovery) / MTBF (Mean Time Between Failures) / MTTD (Mean Time To Detection) / MTTA (Mean Time To Acknowledge) - incident-record schema, calculation formulae, dashboards-as-code, target-vs-actual alerting. Aligns with ITIL incident management + ISO 20000 + Google SRE incident response chapter. Use when incident reporting is being stood up from scratch, or when an existing MTTR / MTBF dashboard reports numbers nobody can reproduce or agree on the definition of.
restore-time-tests
Build restore-time SLA tests - per-database + per-object-store baseline measurement, RTO objective verification, parallel-restore optimization tests, point-in-time-recovery (PITR) latency. Bound `time-to-functional` (TTF) ≤ documented RTO; flag silent regressions when restore time grows over months. Use when a service documents an RTO nobody has actually timed, when the backup has grown by an order of magnitude, or right after a backup-tool change.
slo-negotiation-prep
Build-an-X workflow that produces the manager's prep pack for the QA - SRE - Product SLO conversation - current error-budget consumption + MTTR/MTBF trend + a single framed decision question + an explicit 3-5 option matrix with reversibility / stakeholder cost / impact scoring + recommended posture with cited alternatives. Consumes existing SLI / SLO / error-budget math and per-incident MTTR / MTBF metrics rather than computing them. Use when budget is burning or a proposed change will stress the SLO - the output is the evidence pack the manager carries into the meeting, not a recommendation about which option to pick.