From 0666d8d308d922b69bd10da7a9be6f620446522e Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Tue, 1 Sep 2026 21:12:06 +0100 Subject: [PATCH] fix(multiplayer): verify recovered arena annotations --- server/agones/allocation.go | 5 ++++- server/agones/allocation_test.go | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/server/agones/allocation.go b/server/agones/allocation.go index 7857a79d..0cacffdc 100644 --- a/server/agones/allocation.go +++ b/server/agones/allocation.go @@ -146,6 +146,9 @@ func (c Client) RecoverAllocation(ctx context.Context, request domain.Allocation if item.Metadata.Annotations["cosmic-clash.io/match-id"] != request.MatchID { return AllocatedServer{}, false, domain.ErrConflict } + if request.ArenaPath != "" && item.Metadata.Annotations["cosmic-clash.io/arena-path"] != request.ArenaPath { + return AllocatedServer{}, false, domain.ErrConflict + } if item.Metadata.Labels["cosmic-clash.io/region"] != request.Region || item.Metadata.Labels["cosmic-clash.io/build"] != request.Build || item.Metadata.Labels["cosmic-clash.io/protocol"] != strconv.Itoa(request.Protocol) || item.Metadata.Labels["cosmic-clash.io/transport"] != request.Transport { return AllocatedServer{}, false, domain.ErrConflict } @@ -217,7 +220,7 @@ func (c Client) Allocate(ctx context.Context, request domain.AllocationRequest, if err != nil { return AllocatedServer{}, err } - if request.AllocationID == "" || request.MatchID == "" || (request.Region != "EU" && request.Region != "NA") || request.Build == "" || request.Protocol <= 0 || (request.Transport != "enet" && request.Transport != "steam_sdr") || now.IsZero() { + if request.AllocationID == "" || request.MatchID == "" || (request.Region != "EU" && request.Region != "NA") || request.Build == "" || request.Protocol <= 0 || (request.Transport != "enet" && request.Transport != "steam_sdr") || (request.Playlist == domain.Ranked && !domain.IsRankedArenaPath(request.ArenaPath)) || (request.ArenaPath != "" && !domain.IsRankedArenaPath(request.ArenaPath)) || now.IsZero() { return AllocatedServer{}, domain.ErrAllocationInput } if len(labels) == 0 { diff --git a/server/agones/allocation_test.go b/server/agones/allocation_test.go index 021eac89..f94a2eec 100644 --- a/server/agones/allocation_test.go +++ b/server/agones/allocation_test.go @@ -184,6 +184,18 @@ func TestRecoverAllocationRejectsMismatchedBinding(t *testing.T) { } } +func TestRecoverAllocationRejectsMissingRankedArenaAnnotation(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(`{"items":[{"metadata":{"name":"gs-ranked","labels":{"cosmic-clash.io/region":"EU","cosmic-clash.io/build":"build-1","cosmic-clash.io/protocol":"1","cosmic-clash.io/transport":"enet"},"annotations":{"cosmic-clash.io/allocation-id":"allocation-1","cosmic-clash.io/match-id":"match-1"}},"status":{"state":"Allocated","address":"127.0.0.1","ports":[{"name":"default","port":31001}]}}]}`)) + })) + defer server.Close() + recoveryRequest := request() + recoveryRequest.ArenaPath = "res://scenes/arena_01.tscn" + if _, found, err := (Client{BaseURL: server.URL, Namespace: "games", HTTP: server.Client()}).RecoverAllocation(context.Background(), recoveryRequest, time.Unix(1000, 0)); err == nil || found { + t.Fatalf("ranked recovery without arena annotation accepted: found=%t err=%v", found, err) + } +} + func TestRecoverAllocationRejectsDuplicateProviderMatches(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"items":[{"metadata":{"name":"gs-one","labels":{"cosmic-clash.io/region":"EU","cosmic-clash.io/build":"build-1","cosmic-clash.io/protocol":"1","cosmic-clash.io/transport":"enet"},"annotations":{"cosmic-clash.io/allocation-id":"allocation-1","cosmic-clash.io/match-id":"match-1"}},"status":{"state":"Allocated","address":"127.0.0.1","ports":[{"name":"default","port":31001}]}},{"metadata":{"name":"gs-two","labels":{"cosmic-clash.io/region":"EU","cosmic-clash.io/build":"build-1","cosmic-clash.io/protocol":"1","cosmic-clash.io/transport":"enet"},"annotations":{"cosmic-clash.io/allocation-id":"allocation-1","cosmic-clash.io/match-id":"match-1"}},"status":{"state":"Allocated","address":"127.0.0.1","ports":[{"name":"default","port":31002}]}}]}`))