fix(backup): ignore interrupted shard temps

This commit is contained in:
Peter Steinberger 2026-04-28 01:46:50 +01:00
parent 9d7ca4ec5f
commit 81cedf4e9e
No known key found for this signature in database
3 changed files with 44 additions and 0 deletions

View File

@ -760,3 +760,25 @@ func removeStaleShards(repo string, shards []ShardEntry) error {
}
return nil
}
func removeTempShardFiles(repo string) error {
for _, rootName := range []string{"data", "checkpoints"} {
root := filepath.Join(repo, rootName)
if _, err := os.Stat(root); os.IsNotExist(err) {
continue
}
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil || d == nil || d.IsDir() {
return err
}
name := d.Name()
if strings.HasPrefix(name, ".shard-") && strings.HasSuffix(name, ".age") {
return os.Remove(path) //nolint:gosec // repo-owned temp shard paths come from WalkDir below configured backup roots.
}
return nil
}); err != nil {
return err
}
}
return nil
}

View File

@ -141,6 +141,25 @@ func TestPushCheckpointWritesIncompleteManifestOutsideMainSnapshot(t *testing.T)
}
}
func TestCommitAndPushRemovesInterruptedShardTemps(t *testing.T) {
ctx, repo, config, _ := initTestBackup(t)
temp := filepath.Join(repo, "checkpoints", "gmail", "acct", "run-one", "messages", ".shard-interrupted.age")
if err := os.MkdirAll(filepath.Dir(temp), 0o700); err != nil {
t.Fatalf("MkdirAll: %v", err)
}
if err := os.WriteFile(temp, []byte("partial ciphertext"), 0o600); err != nil {
t.Fatalf("WriteFile: %v", err)
}
pushSingleShard(t, ctx, config, mustGmailMessageShard(t, "data/gmail/acct/messages/2026/04/part-0001.jsonl.gz.age", []map[string]string{{"id": "m1", "raw": "final"}}))
if _, err := os.Stat(temp); !os.IsNotExist(err) {
t.Fatalf("temp shard should be removed before commit: %v", err)
}
if err := git(ctx, repo, "ls-files", "--error-unmatch", "checkpoints/gmail/acct/run-one/messages/.shard-interrupted.age"); err == nil {
t.Fatal("temp shard was committed")
}
}
func TestCatAndDecryptSnapshotVerifyPlaintext(t *testing.T) {
ctx, repo, config, _ := initTestBackup(t)
shardPath := "data/gmail/acct/messages/2026/04/part-0001.jsonl.gz.age"

View File

@ -54,6 +54,9 @@ func ensureRepo(ctx context.Context, cfg Config) error {
}
func commitAndPush(ctx context.Context, cfg Config, message string, push bool) (bool, error) {
if err := removeTempShardFiles(cfg.Repo); err != nil {
return false, err
}
if err := git(ctx, cfg.Repo, "add", "."); err != nil {
return false, err
}