test(api): pin restore's owner gate against a superseded former owner

handleRestoreBackup's owner-or-admin gate was not pinned by any test: the former-owner gate backstopped every non-owner case the suite exercised, so a broken owner gate would not redden. Add the mirror of the former-owner test — a released former owner (still the backup's former_owner, no longer the current owner) must get 403 — the sole subtest that fails when the owner gate is disabled. Found by the round-2 backup/restore mutation audit; production code unchanged.
This commit is contained in:
flyemoji committed 2026-07-08 05:58:00 +09:00
1 parent c67a4d3f35
commit 85b8a92a0e
1 file changed
+20
+20
View File
@@ -190,6 +190,26 @@ func TestRestoreBackup(t *testing.T) {
}
})
t.Run("former owner after release -> 403, no restore", func(t *testing.T) {
// Mirror of the guard above, pinning the owner gate rather than the former-owner
// gate (handler comment: "must re-claim first"). owner1 took this backup, then
// released survival to "newowner". owner1 is still the backup's former_owner — so
// the former-owner gate would wave them through — but is no longer the current
// owner. Only the owner gate stops them; without it a superseded owner could roll
// a live server back onto their old world. (Disable that gate and this is the one
// subtest that reddens — the former-owner gate does not backstop this case.)
api, repo, _, restorer := mk()
repo.byName["survival"].OwnerID = "newowner"
api.External = staticExternal{p: owner} // owner1: former_owner, not current owner
w := do(api.ExternalHandler(), "POST", path, "", nil)
if w.Code != http.StatusForbidden {
t.Fatalf("code = %d, want 403 (owner gate: former owner is no longer the current owner)", w.Code)
}
if restorer.calls != 0 {
t.Fatal("a released former owner must not restore onto the current owner's server")
}
})
t.Run("unknown server -> 404", func(t *testing.T) {
api, _, _, _ := mk()
api.External = staticExternal{p: owner}