Skip to content

fix: make pre-migration backups schema-aware - #77

Merged
Aliferous3 merged 2 commits into
mainfrom
fix/pre-migration-backup-schema-awareness
Oct 18, 2026
Merged

Aliferous3 merged 2 commits into
mainfrom
fix/pre-migration-backup-schema-awareness

Conversation

@Aliferous3

Copy link
Copy Markdown
Owner

Summary

Fixes a production-migration sequencing hazard discovered after PR #76: db:backup requested every BACKUP_TABLES entry via pg_dump --table=, so the mandatory fresh backup required before applying 012_ownership.sql would fail on a database where 012 is committed but not yet applied.

db:backup now reads the target's schema_migrations and resolves the dump set to BACKUP_TABLES ∩ tables the applied migrations created (resolveBackupTables() in scripts/backup-scope.mjs). A target at 011 backs up the 10 pre-012 tables and simply excludes the not-yet-created ownership tables; a target at 012 backs up all 14.

The allowlist-only model is unchanged — unknown tables can never be requested, and resolution fails closed on a broken schema:

  • a table the applied migrations expect but the DB lacks → abort (no silently partial backup)
  • an allowlisted table physically present without a recorded migration → abort (bookkeeping/schema disagreement)
  • empty resolved set (unmigrated DB) → abort

Also reports schema metadata: applied count/latest, repo migration count, behind-main flag, and which allowlisted tables were excluded. No credentials or URLs printed.

Scope

Operator-safety only. No migration, schema, ingestion, API, UI, privacy-page, or permission changes. Production DB untouched.

Security / privacy impact

  • Security/privacy behavior changed and is explained below

Strengthens backup integrity: a broken or inconsistent schema now aborts rather than yielding a partial backup. Allowlist-only dump model preserved; TOC assertions in the recovery drill unchanged.

Database / deployment impact

  • No migration
  • No deployment-order concerns — this unblocks the controlled npm run db:backup + db:migrate sequence for 012.

Verification

  • npm test — 538 tests, 0 failures (new test/backup-schema.test.mjs: pre-012, post-012, broken-post-012 fail-closed, unknown-table exclusion, missing-core-table fail-closed, unrecorded-table fail-closed)
  • npm run typecheck
  • npm run build
  • npm audit --audit-level=moderate — 0 vulnerabilities
  • npm run db:drill — PASS on Postgres 17 (post-012 target still dumps all 14; TOC allowlist proof unchanged)
  • Live smoke test on docker Postgres 17: simulated pre-012 DB → 10 tables dumped, ownership excluded, unclassified table ignored; simulated broken post-012 (012 recorded, tables absent) → refused closed

Contributor agreement

Generated with Devin

The mandatory backup taken before applying a pending migration (e.g.
012_ownership.sql) previously requested every BACKUP_TABLES entry via
--table, so pg_dump would fail on tables the target schema had not yet
created. db:backup now reads the target's schema_migrations and resolves
the dump set to BACKUP_TABLES intersected with the tables the applied
migrations actually created.

Resolution fails closed on schema inconsistencies: an expected table
missing from the DB, or an allowlisted table present without a recorded
migration, aborts the backup instead of producing a silently partial
artifact. The dump remains allowlist-only — unknown tables can never be
requested, an empty resolved set is refused, and the archive TOC
assertions in the recovery drill are unchanged.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
dev-ledger Ready Ready Preview Oct 18, 2026 2:29pm UTC

Three fail-closed hardenings to schema-aware backup resolution:

- an applied migration filename unknown to this checkout now aborts the
  backup ("target database schema is ahead of this repository checkout")
  instead of being tolerated — an older tool cannot know whether its
  allowlist is still complete
- the applied ledger must be a contiguous prefix of the repo migration
  list; gaps or skipped migrations abort before any table resolution
- the live schema query restricts to BASE TABLE relations, so a view can
  never satisfy a required backup table

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@Aliferous3
Aliferous3 merged commit 78ae77e into main Oct 18, 2026
5 checks passed

This branch was successfully deployed

1 active deployment
Preview — ecfd96af Deployed Oct 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant