Author SHA1 Message Date
clawbot 192ceac73e Do not prune when a backup misses an earlier mount point (closes #395)
check / check (push) Canceled after 0s
snapshot create --prune purged the older snapshots holding a volume's
files when the volume, mounted below a configured path, was not
mounted: its empty mount point read as deleted files.

The scan now records in the local index each directory at or below a
configured path that the walk found an entry in and that, once listed,
is on a different device from its parent; listing mounts an
automounted volume. Under --prune, when an earlier snapshot of that
name recorded such a directory and this run does not, the run skips
the prune, keeps every older snapshot and exits non-zero, naming the
directory. For a volume retired on purpose, snapshot purge removes the
older snapshots.

Model: opus-5-5
2026-10-15 06:03:29 +00:00
3 changed files with 8 additions and 26 deletions

No files matched your search

+5 -1
View File
@@ -30,7 +30,11 @@ var (
errFilesFailedRestore = errors.New("file(s) failed to restore")
errPathsNotInSnapshot = errors.New("requested path(s) not in the snapshot")
errFilesFailedVerify = errors.New("files failed verification")
errDecryptionKeyRequired = errors.New(ageSecretKeyMissingMessage)
errDecryptionKeyRequired = errors.New(
"decryption key required for restore\n\n" +
"Set the VAULTIK_AGE_SECRET_KEY environment variable to your " +
"age private key file:\n" +
" export VAULTIK_AGE_SECRET_KEY=\"$(cat vaultik_backup_private_key.txt)\"")
// errInvalidAgeSecretKey is returned when the configured key does not
// parse as any age identity. It names the source but never the value,
// which is secret, so the message is safe to print and log.
-15
View File
@@ -106,18 +106,3 @@ func TestRestoreIdentitiesMissingKey(t *testing.T) {
_, err := v.restoreIdentities()
require.ErrorIs(t, err, errDecryptionKeyRequired)
}
// TestMissingKeyErrorsNameBothSources asserts the missing-key errors for
// restore and deep verify say the key is missing and name both places it
// can be set, the environment variable first since it is preferred, with
// the same wording in both.
func TestMissingKeyErrorsNameBothSources(t *testing.T) {
t.Parallel()
const want = "age secret key is missing; set it in " +
"the VAULTIK_AGE_SECRET_KEY environment variable or the " +
"age_secret_key config file field"
require.Equal(t, want, errSecretKeyRequired.Error())
require.Equal(t, want, errDecryptionKeyRequired.Error())
}
+3 -10
View File
@@ -20,18 +20,11 @@ import (
"sneak.berlin/go/vaultik/internal/storage"
)
// ageSecretKeyMissingMessage is the shared text of the missing-key errors
// for restore and deep verify. It says the key is missing and names both
// places it can come from, the environment variable first since it is
// preferred.
const ageSecretKeyMissingMessage = "age secret key is missing; set it in " +
"the VAULTIK_AGE_SECRET_KEY environment variable or the " +
"age_secret_key config file field"
// Sentinel errors for snapshot verification failures.
var (
errVerificationFailed = errors.New("verification failed")
errSecretKeyRequired = errors.New(ageSecretKeyMissingMessage)
errVerificationFailed = errors.New("verification failed")
errSecretKeyRequired = errors.New(
"VAULTIK_AGE_SECRET_KEY not set; required for deep verification")
errChunksOutOfOrder = errors.New("chunks out of order")
errChunkHashMismatch = errors.New("chunk hash mismatch")
errNegativeChunkLength = errors.New("chunk length is negative")