Restore accepts an archive from a newer Postulo and leaves the database on a schema the code does not know #479
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#479
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, reading howrestorechecks an archive's manifest.Checked again on 2026-10-01 against
mainat0a5cad587: still present.read_manifestgates only onbackup_formatand never reads the Postulo version the manifest records. Restoring an archive written by a newer Postulo onto an older one replaces the database with one carrying migrations this code does not have;migratecannot go backwards and ignores applied migrations it does not know, so the restore reports success and the application then runs against tables and columns it does not expect.core/backup.py:405read_manifest(), whose only version check is1 <= fmt <= BACKUP_FORMAT;core/backup.py:349writes"version": __version__into the manifest and nothing reads it back;core/backup.py:565runsmigrateafter loading.NOT NULLwithout a database default makes every insert on that table fail; a column it renamed or removed makes reads fail. The restore itself said nothing.restore_backup, compare the manifest'spostulo.versionwith__version__and refuse a newer archive with a message that names the version to install; after loading, also refuse (and say so) whendjango_migrationsnames migrations absent from the code, which covers development builds with the same version string. Allow it only with an explicit flag, separate from--force, which already means "replace a non-empty instance".Related to #32 (closed), which promised that
restore"checks the manifest against the installed version".Done when
tests/test_backup.py: an archive whose manifest names a version newer than__version__is refused before the database is touched, and the message names that version.