OWASP / OWASP/cornucopia

Bug: `handle_info` in game_live/show.ex always sets `requested_round = rounds_played + 1`, breaking finished game summary view

Open
#2,548 5 comments 0 reactions 1 assignee Claimed by @Adarshkumar0509 View on GitHub
bug copi.owasp.org elixir help wanted
Dominant language
Python
Stars
146
Forks
97
Avg merge
1d 7h
Merged PRs (30d)
104

Description

## Describe the bug

In `copi.owasp.org/lib/copi_web/live/game_live/show.ex`, the `handle_info/2` callback that processes `game:updated` broadcasts always sets `requested_round` to `updated_game.rounds_played + 1` — regardless of whether the game has finished. This contradicts `handle_params/3`, which correctly uses `rounds_played` (without +1) for finished games. As a result, any `game:updated` broadcast received while viewing a finished game summary resets the view to a non-existent round.

## Affected file

`copi.owasp.org/lib/copi_web/live/game_live/show.ex`

## Code snippet

```elixir
# handle_params — CORRECTLY handles finished games (line 24-28):
current_round = if game.finished_at do
game.rounds_played # ← correct: last actual round
else
game.rounds_played + 1 # ← correct: current in-progress round
end

# handle_info — ALWAYS does +1, ignores finished_at (line 48-51):
def handle_info(%{topic: message_topic, event: "game:updated", payload: updated_game}, socket) do
cond do
topic(updated_game.id) == message_topic ->
{:noreply, assign(socket, :game, updated_game) |> assign(:requested_round, updated_game.rounds_played + 1)}
# ↑ BUG: adds +1 even when updated_game.finished_at is set
true ->
{:noreply, socket}
end
end
```

## Exact failure scenario

1. Game finishes with `rounds_played = N` and `finished_at` set.
2. `handle_params` correctly renders the game summary with `requested_round = N`.
3. Any subsequent `game:updated` broadcast fires (e.g., from a late-arriving player reconnect, the transition broadcast itself, or any other event).
4. `handle_info` sets `requested_round = N + 1` — a round that does not exist.
5. The game summary view now tries to show round `N + 1`, finds no cards, and renders a blank/broken summary page.

## Expected behavior

`handle_info` should mirror `handle_params` in how it computes `requested_round`:

```elixir
def handle_info(%{topic: message_topic, event: "game:updated", payload: updated_game}, socket) do
cond do
topic(updated_game.id) == message_topic ->
requested_round =
if updated_game.finished_at do
updated_game.rounds_played
else
updated_game.rounds_played + 1
end
{:noreply, assign(socket, :game, updated_game) |> assign(:requested_round, requested_round)}
true ->
{:noreply, socket}
end
end
```

## Steps to reproduce

1. Create and play a game to completion (all rounds done, `finished_at` set).
2. While on the game summary page (`/games/:game_id`), trigger any action that causes a `game:updated` broadcast (or simply wait if there is any background activity).
3. Observe: the summary page goes blank / shows "round not found" because `requested_round` is now one past the last round.

## Additional context

- This is distinct from issue #2418, which covers `player_live/show.ex`'s `handle_event("next_round")` double-broadcast bug.
- The fix is a one-line-to-five-line change in `handle_info` to mirror the `if game.finished_at` check already present in `handle_params`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.