1 Commits
Author SHA1 Message Date
sneak 523629f1a8 Keep the local index when remote nuke cannot list or find the destination (closes #292)
check / check (push) Waiting to run
`remote nuke` took a destination store it could not list, or one
without `vaultik-destination.txt` while the local index held
snapshots, as a warning: it then cleared the local snapshot records,
and for an unplugged volume's empty mount point reported the store
empty and exited zero. Nuke now fails on either before it removes
anything, without its advice to run it again, which would fail the
same way. The bulk remove it runs fails on either too; only a
local-only remove still goes on with a warning. Nuke also deletes each
snapshot's remote metadata before its local record, so a failed delete
keeps the snapshot in the local index rather than leaving it on the
store as a remote-only snapshot.

Model: opus-5-5
2026-10-14 04:25:50 +00:00
3 changed files with 15 additions and 4 deletions
+4 -2
View File
@@ -153,8 +153,9 @@ func TestPurgeRefusesDestinationWithoutMarker(t *testing.T) {
}
// TestNukeRemoteRefusesDestinationWithoutMarker checks that remote nuke
// fails, deletes no local snapshot record and does not report the
// destination empty when the destination has no marker.
// fails, deletes no local snapshot record, and neither reports the
// destination empty nor advises running nuke again when the destination
// has no marker.
func TestNukeRemoteRefusesDestinationWithoutMarker(t *testing.T) {
log.Initialize(log.Config{})
t.Parallel()
@@ -165,6 +166,7 @@ func TestNukeRemoteRefusesDestinationWithoutMarker(t *testing.T) {
err := v.NukeRemote(true)
require.ErrorContains(t, err, markerFile)
assert.NotContains(t, out.String(), "now empty")
assert.NotContains(t, out.String(), "vaultik remote nuke --force")
assertUntouched(ctx, t, repos, storeDir)
}
+3 -1
View File
@@ -191,7 +191,8 @@ func TestPurgeSaysListingFailedOnceWhenDestinationMissing(t *testing.T) {
// TestNukeRemoteKeepsLocalIndexWhenDestinationMissing checks that remote
// nuke fails on a destination it cannot list, leaves the local index
// unchanged, and does not report the destination empty.
// unchanged, and neither reports the destination empty nor advises
// running nuke again.
func TestNukeRemoteKeepsLocalIndexWhenDestinationMissing(t *testing.T) {
log.Initialize(log.Config{})
t.Parallel()
@@ -211,6 +212,7 @@ func TestNukeRemoteKeepsLocalIndexWhenDestinationMissing(t *testing.T) {
require.ErrorIs(t, err, fs.ErrNotExist)
require.ErrorContains(t, err, "listing remote snapshots")
assert.NotContains(t, out.String(), "now empty")
assert.NotContains(t, out.String(), "vaultik remote nuke --force")
snapshots, err := repos.Snapshots.ListRecent(ctx, listRecentTestLimit)
require.NoError(t, err)
+8 -1
View File
@@ -55,12 +55,19 @@ func (v *Vaultik) NukeRemote(force bool) error {
}
// Checked before anything is deleted: running nuke again would fail
// the same way, so the advice below must not follow this error.
// the same way, so the advice below must not follow these errors.
// The listing also fails on a destination without the marker while
// the local index holds snapshots.
err := v.EnsureStorageBinding()
if err != nil {
return err
}
_, err = v.listAllRemoteSnapshotKeys()
if err != nil {
return err
}
err = v.emptyDestinationStore()
if err != nil {
v.UI.Warningf("Run '%s' again to delete what is left on the "+