From c2cf5ba1c5cb821a773425d33431fbff8d794075 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 24 Feb 2026 20:08:08 +0100 Subject: [PATCH] fix(restore): validate migration data before wiping database Move archive validation (migration file existence and slice bounds check) before the database wipe. Previously a malformed archive would first destroy the database and then panic, leaving the instance in an irrecoverable state with total data loss. Now the migration data is fully parsed and validated before any destructive operations occur. --- pkg/modules/dump/restore.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/pkg/modules/dump/restore.go b/pkg/modules/dump/restore.go index 67e57c9a9..2dc8e2cb6 100644 --- a/pkg/modules/dump/restore.go +++ b/pkg/modules/dump/restore.go @@ -131,15 +131,14 @@ func Restore(filename string, overrideConfig bool) error { /////// // Restore the db - // Start by wiping everything - if err := db.WipeEverything(); err != nil { - return fmt.Errorf("could not wipe database: %w", err) - } - log.Info("Wiped database.") - // Because we don't explicitly saved the table definitions, we take the last ran db migration from the dump - // and execute everything until that point. + // Validate archive contents before wiping to avoid leaving the database + // in a destroyed state when the archive is malformed. migrations := dbfiles["migration"] + if migrations == nil { + return fmt.Errorf("dump does not contain database migration information") + } + rc, err := migrations.Open() if err != nil { return fmt.Errorf("could not open migrations: %w", err) @@ -159,7 +158,17 @@ func Restore(filename string, overrideConfig bool) error { return ms[i].ID < ms[j].ID }) + if len(ms) < 2 { + return fmt.Errorf("dump does not contain enough migration information") + } + lastMigration := ms[len(ms)-2] + + // Start by wiping everything - only after we've validated the archive + if err := db.WipeEverything(); err != nil { + return fmt.Errorf("could not wipe database: %w", err) + } + log.Info("Wiped database.") log.Debugf("Last migration: %s", lastMigration.ID) if err := migration.MigrateTo(lastMigration.ID, nil); err != nil { return fmt.Errorf("could not create db structure: %w", err)