package store import "testing" // Part B (v0.60.0) — the escrow retention red-proof (the 2026-07-17 incident class). A new escrow blob // with a DIFFERENT sealed-passphrase sha must RETAIN the old blob (recoverable) instead of destroying // it; a same-sha re-upload is idempotent (no supersede row). Pre-fix (destructive ON CONFLICT // overwrite) the old blob is gone → the retrieval assertion FAILS. func TestSaveHostEscrow_RetainsSuperseded(t *testing.T) { st := newTestStore(t) const h = "h1" // 1st upload (P_old) — nothing to supersede. sup, err := st.SaveHostEscrow(h, []byte("blob-old"), "fp-old", "zk", "2026-07-09T00:00:00Z", "SHA_OLD") if err != nil { t.Fatal(err) } if sup { t.Fatal("first upload must not supersede") } // 2nd upload (P_new, DIFFERENT sha) — must supersede + retain the old. sup, err = st.SaveHostEscrow(h, []byte("blob-new"), "fp-new", "zk", "2026-07-16T00:00:00Z", "SHA_NEW") if err != nil { t.Fatal(err) } if !sup { t.Fatal("a different-passphrase upload must supersede (retain the old blob)") } // Current row is the NEW blob (ACK/restore-serving read this — unchanged behavior). cur, _ := st.GetHostEscrow(h) if cur == nil || string(cur.Blob) != "blob-new" || cur.ResticPwSHA256 != "SHA_NEW" { t.Fatalf("current row not the new blob: %+v", cur) } // RED-PROOF: the OLD blob is RETAINED and retrievable. old, err := st.ListSupersededEscrow(h) if err != nil { t.Fatal(err) } if len(old) != 1 || string(old[0].Blob) != "blob-old" || old[0].ResticPwSHA256 != "SHA_OLD" { t.Fatalf("old blob NOT retained after overwrite (incident): %+v", old) } if n, _ := st.CountSupersededEscrow(h); n != 1 { t.Fatalf("superseded count = %d, want 1", n) } // 3rd upload, SAME sha as current — idempotent (re-ceremony of the same password): NO supersede row. sup, err = st.SaveHostEscrow(h, []byte("blob-new-2"), "fp-new", "zk", "2026-07-16T01:00:00Z", "SHA_NEW") if err != nil { t.Fatal(err) } if sup { t.Fatal("a same-sha re-upload must NOT supersede (idempotent)") } if n, _ := st.CountSupersededEscrow(h); n != 1 { t.Fatalf("idempotent re-upload created a superseded row: count=%d", n) } }