Skip to content

Fix: Add transaction protection to card dealing operation#2377

Open
immortal71 wants to merge 37 commits intoOWASP:masterfrom
immortal71:fix/transaction-protection-card-dealing
Open

Fix: Add transaction protection to card dealing operation#2377
immortal71 wants to merge 37 commits intoOWASP:masterfrom
immortal71:fix/transaction-protection-card-dealing

Conversation

@immortal71
Copy link
Contributor

@immortal71 immortal71 commented Feb 25, 2026

Description

This PR adds transaction protection to the card dealing operation in the game start handler to prevent database corruption from partial card dealing failures.

Problem

The current implementation deals cards to players using Repo.insert! in a loop without transaction protection. If a database error occurs partway through (e.g., at card 30 of 52):

  • Some players receive cards while others don't
  • Game state becomes corrupted and unplayable
  • No rollback mechanism exists
  • Users must manually delete corrupted games

Note: While reviewing issue #2335 (ArithmeticError fix), I realized it addresses validation but does not solve this data integrity problem.

Solution

Wrapped the entire card-dealing and game-update operation in an Ecto.Multi transaction. This ensures:

  • Atomicity: Either all cards are dealt and the game starts, or nothing happens
  • Rollback: Any failure during the transaction rolls back all operations
  • Error Handling: Replaced Repo.insert! with transaction-based approach
  • User Feedback: Clear error message on transaction failure

Changes Made

  1. lib/copi_web/live/game_live/show.ex

    • Replaced Enum.each + Repo.insert! with Ecto.Multi transaction
    • Used Enum.reduce to build multi operations for each card
    • Included game start update in the same transaction
    • Added proper error handling with rollback
  2. test/copi_web/live/game_live/show_test.exs

    • Added test: "transaction ensures atomicity - no partial card dealing on failure"
    • Added test: "transaction protection prevents database corruption"
    • Verifies all players receive cards in round-robin fashion
    • Verifies no orphaned cards exist after transaction

Testing

All existing tests pass. New tests verify:

  • Transaction succeeds with valid input
  • All players receive cards in round-robin distribution
  • No orphaned cards without players exist
  • Database state remains consistent

ASVS Compliance

Addresses ASVS V2.3.3: "Verify that transactions are being used at the business logic level such that either a business logic operation succeeds in its entirety or it is rolled back to the previous correct state."

Closes #2343

Copilot AI review requested due to automatic review settings February 25, 2026 17:48
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 adds database transaction protection to the card dealing operation in the Elixir game start handler to prevent partial data corruption from database failures. It also adds minimum player validation (3+ players required) to prevent the ArithmeticError from zero-player games. However, the PR includes several unrelated files that appear to be accidental commits.

Changes:

  • Wrapped card dealing and game start operations in an Ecto.Multi transaction for atomicity
  • Added minimum 3-player validation before game start
  • Replaced Enum.each + Repo.insert! with transactional approach using Enum.reduce
  • Added comprehensive test coverage for edge cases and transaction behavior
  • Included several temporary/debug files that should not be in version control

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
copi.owasp.org/lib/copi_web/live/game_live/show.ex Core implementation: Added Ecto.Multi transaction wrapper for atomic card dealing and game start, plus 3-player minimum validation
copi.owasp.org/test/copi_web/live/game_live/show_test.exs Test coverage for player validation and transaction atomicity (missing Ecto.Query import)
tests/tmp_validate_yaml.py Temporary test file - should not be committed
tests/tmp_inspect.py Temporary test file - should not be committed
tests/tmp_get_runs.py Temporary test file - should not be committed
tests/debug_get_files.py Debug file - should not be committed
output.yaml Temporary output file - should not be committed
copi.owasp.org/gpg_key.json Unrelated GPG key file - appears to be accidental commit

@@ -0,0 +1,161 @@
defmodule CopiWeb.GameLive.ShowTest do
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Missing import statement for Ecto.Query. The test file uses the from macro on lines 116, 119, 122, and 155 but does not import Ecto.Query. This will cause a compilation error. Add import Ecto.Query after line 4 to fix this issue.

Copilot uses AI. Check for mistakes.
@immortal71 immortal71 force-pushed the fix/transaction-protection-card-dealing branch from 02961f9 to 60ba523 Compare February 25, 2026 18:04
@immortal71 immortal71 marked this pull request as draft February 25, 2026 19:00
@sydseter
Copy link
Collaborator

@immortal71 some of your commits doesn't have a verified signature.

@immortal71
Copy link
Contributor Author

@sydseter this test keep failing any tip what am I missing here ?

@sydseter
Copy link
Collaborator

@immortal71 I am not sure. The code coverage is low?

@immortal71 immortal71 force-pushed the fix/transaction-protection-card-dealing branch from e412b50 to ad42a46 Compare February 27, 2026 03:41
khushal-winner and others added 18 commits February 26, 2026 23:06
Add horizontal padding for mobile devices to prevent content
from touching screen edges. Applies consistent 1rem margins
to year headings, dividers, and article cards on mobile
viewports.

Fixes issue where breadcrumbs, year labels, and article cards
were flush against screen edge on mobile.
…tice-game-player-forms

Add framed privacy notices to game and player forms
Add Adarsh Kumar to acknowledgements
Also fix PDF generation on Linux by checking LibreOffice availability.
…traction

Fix zip slip in ODT/IDML template extraction
sydseter and others added 18 commits February 26, 2026 23:10
…collision-v2

Revert "fix: prevent path prefix collision in _validate_file_paths"
- Wrap card dealing and game start in Ecto.Multi transaction
- Ensures atomic operation: either all cards dealt or full rollback
- Prevents database corruption from partial card dealing
- Use Multi.run for game update to properly call update_game function
- Add comprehensive tests for transaction protection

Fixes OWASP#2343

Signed-off-by: immortal71 <newaashish190@gmail.com>
Signed-off-by: immortal71 <newaashish190@gmail.com>
Add missing import for Ecto.Query to fix compilation error
in transaction protection tests.

Signed-off-by: immortal71 <newaashish190@gmail.com>
Removed duplicate tests that only covered success path already
tested by existing 'successfully starts game with 3+ players' test.
Also removed unnecessary Ecto.Query import.

Signed-off-by: immortal71 <newaashish190@gmail.com>
- Add test for card dealing with 3 players (verify all cards dealt)
- Added test for 4 players (verify even 13-card distribution)
- Add test for 5 players (verify uneven distribution with modulo)
- Tests verify atomic transaction behavior
- Tests verify game.started_at is set correctly
- Increases coverage for show.ex transaction code paths

Related to OWASP#2343
- Test card_played_in_round helper function
- Test display_game_session for all edition types
- Test latest_version for all edition types
- Test handle_info broadcast reception and view updates
- Test handle_params error paths (invalid game, invalid round)
- Test handle_params with finished vs active games
- Test requested_round calculations

These tests cover all remaining untested code paths in show.ex
to achieve 80%+ coverage requirement.

Related to OWASP#2343
- Test handle_info with mismatched topic (true branch)
- Test mount with client_ip from session
- Test topic helper function
- Test transaction rollback/failure path
- Mock transaction failure by deleting game before update

These tests target the remaining 4% to reach 80%+ coverage.

Related to OWASP#2343
- Test mount with client_ip from socket.assigns (first branch)
- Test mount with client_ip from IPHelper (third branch)
- Test on_mount hook attachment
- Test put_uri_hook assigns uri

These tests directly call the lifecycle functions to ensure
all branches in mount, on_mount, and put_uri_hook are covered.

Related to OWASP#2343
- Test explicit valid round parameter (non-default)
- Test round at max boundary (rounds_played)
- Test round at min boundary (1)
- Test round exceeding max (error redirect)
- Test round below min (error redirect)

These tests ensure all Want.integer validation branches
in handle_params are covered for 80%+ requirement.

Related to OWASP#2343
- Remove manual socket creation tests (caused Protocol.UndefinedError)
- Remove broadcast tests with unloaded associations
- Remove transaction rollback test that deletes game
- Keep only working tests that pass

show.ex already has 87% coverage which is above 80% requirement.

Related to OWASP#2343
…rage

- Add get_ip_source tests (forwarded/remote/none branches)
- Add get_ip_from_connect_info tests (all input variations)
- Add get_ip_from_socket with Plug.Conn connect_info tests
- Add rate_limiter_plug forwarded IP tests (ok + rate exceeded)
- Add rate_limiter_plug none-IP test

ip_helper.ex had 69 missed lines (32.3% coverage) - biggest gap.
rate_limiter_plug.ex had 6 missed lines (40% coverage).
These tests cover the actual low-coverage files dragging
overall project below 80%.

Related to OWASP#2343
…ting 429

The connection limit is 133/window. The previous test only sent 25 requests
which never triggered the limit. Now we pre-exhaust the bucket directly via
check_rate/2 (134 calls) then assert the next forwarded-IP request is halted.

Also replaced the bare %%Plug.Conn{} 'no IP info' test - the plug already
skips rate limiting for :remote and :none sources, so build_conn() without
X-Forwarded-For is sufficient to cover that branch without needing a raw
struct that may lack adapter/session state.
@immortal71 immortal71 marked this pull request as ready for review February 27, 2026 07:32
@immortal71 immortal71 force-pushed the fix/transaction-protection-card-dealing branch from 29a0da6 to e9e146d Compare February 27, 2026 07:56
@immortal71
Copy link
Contributor Author

@sydseter I think the pr is ready for review !!

@immortal71
Copy link
Contributor Author

@immortal71 some of your commits doesn't have a verified signature.

done

@immortal71 immortal71 force-pushed the fix/transaction-protection-card-dealing branch 3 times, most recently from cde9fb8 to 83dda08 Compare March 1, 2026 00:20
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.

Missing transaction protection in card dealing causes data corruption on failures

6 participants