Skip to content

fix: lifecycle guard for play_card API endpoint (#2631)#2708

Open
immortal71 wants to merge 2 commits intoOWASP:masterfrom
immortal71:fix/2631-play-card-lifecycle-guard
Open

fix: lifecycle guard for play_card API endpoint (#2631)#2708
immortal71 wants to merge 2 commits intoOWASP:masterfrom
immortal71:fix/2631-play-card-lifecycle-guard

Conversation

@immortal71
Copy link
Contributor

Summary

Fixes #2631

The PUT /api/games/:game_id/players/:player_id/card endpoint in api_controller.ex had no game lifecycle check, allowing cards to be played against games that had not yet started or had already finished.

Root Cause

The play_card/2 handler jumped straight to player and card lookups after finding the game, with no guard on game.started_at or game.finished_at.

Fix

Added a cond block at the top of the game-found branch that rejects the request with 422 Unprocessable Entity when:

  • game.started_at == nil - game has not started yet
  • game.finished_at != nil - game has already ended

All other existing checks (card already played, player already played in round) proceed unchanged once the lifecycle is confirmed.

Tests

  • Updated existing success and validation tests to set started_at before calling the endpoint.
  • Added: play_card returns 422 when game has not started
  • Added: play_card returns 422 when game has already ended

Copilot AI review requested due to automatic review settings March 20, 2026 14:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses issue #2631 by adding a game lifecycle guard to the PUT /api/games/:game_id/players/:player_id/card endpoint so cards can’t be played before a game starts or after it finishes.

Changes:

  • Add started_at / finished_at lifecycle checks to play_card/2, returning 422 Unprocessable Entity when invalid.
  • Update and extend controller tests to cover lifecycle validation and keep existing tests passing by setting started_at.
  • Adjust control flow in PlayerLive.Show’s "next_round" handler (block scoping change).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
copi.owasp.org/lib/copi_web/controllers/api_controller.ex Adds lifecycle cond guard to play_card/2 before allowing card play logic.
copi.owasp.org/test/copi_web/controllers/api_controller_test.exs Updates existing tests to set started_at and adds new 422 tests for unstarted/ended games.
copi.owasp.org/lib/copi_web/live/player_live/show.ex Changes block scoping in "next_round" to keep reload/broadcast/assign within the else branch.

Comment on lines +86 to +91
{:ok, updated_game} = Game.find(game.id)

CopiWeb.Endpoint.broadcast(topic(updated_game.id), "game:updated", updated_game)
CopiWeb.Endpoint.broadcast(topic(updated_game.id), "game:updated", updated_game)

{:noreply, assign(socket, :game, updated_game)}
{:noreply, assign(socket, :game, updated_game)}
end
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR description focuses on adding a lifecycle guard to the play_card API endpoint, but this diff also changes control-flow in handle_event("next_round", ...) by moving the Game.find/1 + broadcast + {:noreply, ...} block under the else branch (via the relocated end). If this behavioral change is intentional, it should be called out in the PR description (or split into a separate PR) and ideally covered by a test, since it affects LiveView round progression logic beyond the stated scope.

Copilot uses AI. Check for mistakes.
Reject card plays with 422 Unprocessable Entity when:
- game.started_at == nil (game has not started yet)
- game.finished_at != nil (game has already ended)

Add tests covering both lifecycle guard cases, and update existing
tests that exercise the success and card/player validation paths to
first start the game, since those paths now require an active game.
@immortal71 immortal71 force-pushed the fix/2631-play-card-lifecycle-guard branch from 1c7ebf1 to 0f774fb Compare March 20, 2026 14:57
@immortal71
Copy link
Contributor Author

@sydseter is this good to go ....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: play_card API endpoint allows playing cards on unstarted or finished games

2 participants