e1b8269be0
gates / gates (push) Successful in 16s
Red-proof RP39. Released as v0.138.0 by release-agent.sh. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
75 lines
3.8 KiB
Go
75 lines
3.8 KiB
Go
package backup
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-agent/internal/proxmox"
|
|
)
|
|
|
|
const (
|
|
thisBoxKey = "de:51:7a:18:cb:39:22:30:2c:84:f5:8b:d1:91:4b:7e:81:bb:69:b8:89:0f:57:ac:d3:59:e1:1a:62:25:11:2c"
|
|
earlierBox1 = "6b:ca:5f:3f:ca:0f:e2:3f:fb:24:62:89:bf:e7:64:59:9a:41:c5:e6:e3:9f:3f:5f:e1:71:7b:a1:9d:24:67:82"
|
|
earlierBox2 = "fe:3d:db:95:d4:df:ab:e1:7d:4a:89:fa:2b:07:53:6a:e4:d2:85:95:d1:90:27:4b:d9:c6:92:20:95:04:e5:d4"
|
|
)
|
|
|
|
// R-727 (v0.138.0) — the 2026-09-30 shape, measured on a fresh box for a returning customer: the PBS
|
|
// namespace held two archives of earlier boxes (same guest 9201, same token) and this box's own, which was not
|
|
// settled yet. The old picker chose the earlier box's newest settled archive and failed `wrong key`.
|
|
// The CONSEQUENCE asserted: no archive of another box is ever picked; with this box's archive settled it is picked.
|
|
// COMPANION RED-PROOF: remove the `ownKey != "" && !EqualFold(...)` skip → the first case picks 2026-09-16T21:59:54Z.
|
|
func TestR727_TheRestoreTestTakesOnlyThisBoxsArchives(t *testing.T) {
|
|
day := int64(86400)
|
|
now := int64(1790740000) // 2026-09-30 ~04:00Z
|
|
own := proxmox.StorageContent{VolID: "felhom-pbs:backup/ct/9201/2026-09-29T19:37:07Z", Content: "backup", VMID: 9201, Size: 3490689830, CTime: 1790710627, Encrypted: thisBoxKey}
|
|
api := &fakeBackupAPI{
|
|
storages: []proxmox.Storage{{Storage: "felhom-pbs", Type: "pbs", EncryptionKey: thisBoxKey}},
|
|
content: []proxmox.StorageContent{
|
|
{VolID: "felhom-pbs:backup/ct/9201/2026-09-16T17:27:32Z", Content: "backup", VMID: 9201, Size: 4774114206, CTime: 1789579652, Encrypted: earlierBox2},
|
|
{VolID: "felhom-pbs:backup/ct/9201/2026-09-16T21:59:54Z", Content: "backup", VMID: 9201, Size: 20811501236, CTime: 1789595994, Encrypted: earlierBox1},
|
|
own,
|
|
},
|
|
}
|
|
r := NewBackupRunner(api, "local", proxmox.ModeSnapshot, "", "keep-last=1", quiet())
|
|
|
|
// 1. The night of 2026-09-30: this box's own archive is ~6 h old, not settled (cutoff 24 h) — nothing to prove.
|
|
got, _, err := r.PickSettledRestoreCandidateOn(context.Background(), "felhom-pbs", time.Unix(now-day, 0).UTC())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "" {
|
|
t.Fatalf("picked %q — an archive of ANOTHER box is never this box's proof (R-727)", got)
|
|
}
|
|
// 2. A day later this box's own archive is settled — it is the one picked.
|
|
got, _, err = r.PickSettledRestoreCandidateOn(context.Background(), "felhom-pbs", time.Unix(now+day, 0).UTC())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != own.VolID {
|
|
t.Fatalf("picked %q, want this box's own %q", got, own.VolID)
|
|
}
|
|
}
|
|
|
|
// An unencrypted storage (a local dir) holds only this box's vzdumps — no key filter applies.
|
|
func TestR727_UnencryptedStorageIsNotFiltered(t *testing.T) {
|
|
api := &fakeBackupAPI{
|
|
storages: []proxmox.Storage{{Storage: "local", Type: "dir"}},
|
|
content: []proxmox.StorageContent{{VolID: "local:backup/vzdump-lxc-9201-2026_09_29-21_27_05.tar.zst", Content: "backup", VMID: 9201, Size: 955425507, CTime: 1790710025}},
|
|
}
|
|
r := NewBackupRunner(api, "local", proxmox.ModeSnapshot, "", "keep-last=1", quiet())
|
|
if got, _, err := r.PickSettledRestoreCandidateOn(context.Background(), "local", time.Time{}); err != nil || got == "" {
|
|
t.Fatalf("got %q err %v", got, err)
|
|
}
|
|
}
|
|
|
|
// A storage-list failure makes the tier UNKNOWN (an error), never "nothing to prove".
|
|
func TestR727_KeyLookupFailureIsUnknown(t *testing.T) {
|
|
api := &fakeBackupAPI{storageErr: errors.New("proxmox: GET /storage -> HTTP 500"), content: []proxmox.StorageContent{{VolID: "felhom-pbs:backup/ct/9201/x", Content: "backup", VMID: 9201}}}
|
|
r := NewBackupRunner(api, "local", proxmox.ModeSnapshot, "", "keep-last=1", quiet())
|
|
if _, _, err := r.PickSettledRestoreCandidateOn(context.Background(), "felhom-pbs", time.Time{}); err == nil {
|
|
t.Fatal("a failed key lookup must surface as an error (tier UNKNOWN)")
|
|
}
|
|
}
|