Skip to content

Merge PRs #14, #15, #16: auth fix, async CPU moves, lobby a11y#17

Merged
Horus0305 merged 2 commits intomainfrom
copilot/verify-and-merge-prs
Feb 21, 2026
Merged

Merge PRs #14, #15, #16: auth fix, async CPU moves, lobby a11y#17
Horus0305 merged 2 commits intomainfrom
copilot/verify-and-merge-prs

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 21, 2026

Incorporates three validated open PRs into main. All had clean merge state and successful Vercel preview deployments.

PR #14 — Fix missing auth on /auth/migrate-formats (CRITICAL)

  • /auth/migrate-formats was publicly accessible — anyone could trigger DB migrations or cause DoS via repeated calls
  • Added X-Admin-Secret header requirement with secrets.compare_digest (timing-safe)
  • ADMIN_SECRET sourced from env var; hard failure in production if unset, dev fallback otherwise
  • Added test_auth.py covering missing/invalid/valid secret scenarios

PR #15 — Non-blocking CPU move selection

  • cpu_pick_move runs synchronous DB queries directly on the asyncio event loop, blocking all WebSocket clients during CPU turns
  • Wrapped all 4 call sites in asyncio.to_thread(), consistent with existing patterns in realtime/cpu.py
  • Fixed test mock signature (fixed_do_toss now accepts caller=None)
# Before — blocks event loop
pending["bat"] = cpu_pick_move(manager, room, "bat", innings.striker)

# After — offloaded to thread pool
pending["bat"] = await asyncio.to_thread(cpu_pick_move, manager, room, "bat", innings.striker)

PR #16 — Lobby accessibility improvements

  • Icon-only buttons (Team A/B, crown, Remove CPU) had no ARIA labels — screen reader dead zones
  • Added aria-label + title to each; focus-visible:ring-2 for keyboard navigation visibility
  • Minor package-lock.json cleanup (redundant "peer": true entries removed)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh gh auth status (http block)

If you need me to access, download, or install something from one of these locations, you can either:


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
very-important-study-material Ready Ready Preview, Comment Feb 21, 2026 5:33pm

Co-authored-by: Horus0305 <98160215+Horus0305@users.noreply.github.com>
Copilot AI changed the title [WIP] Review and validate incoming pull requests for merging Merge PRs #14, #15, #16: auth fix, async CPU moves, lobby a11y Feb 21, 2026
Copilot AI requested a review from Horus0305 February 21, 2026 17:34
@Horus0305 Horus0305 marked this pull request as ready for review February 21, 2026 17:37
Copilot AI review requested due to automatic review settings February 21, 2026 17:37
@Horus0305 Horus0305 merged commit 40bfe50 into main Feb 21, 2026
2 of 3 checks passed
Copilot AI requested a review from Horus0305 February 21, 2026 17:38
Copilot stopped work on behalf of Horus0305 due to an error February 21, 2026 17:38
Copy link
Copy Markdown

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 merges three previously-validated changesets into main: securing the /auth/migrate-formats maintenance endpoint, preventing event-loop blocking during CPU turns in the realtime server, and improving Lobby accessibility.

Changes:

  • Added X-Admin-Secret header validation to protect /auth/migrate-formats, plus a new auth test file.
  • Offloaded synchronous CPU move selection to asyncio.to_thread() in realtime CPU flows.
  • Added ARIA labels/tooltips/focus-visible ring styles for icon-only Lobby buttons; cleaned up package-lock.json.

Reviewed changes

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

Show a summary per file
File Description
CricketGame/backend/api/auth.py Requires X-Admin-Secret for /auth/migrate-formats and rejects invalid secrets.
CricketGame/backend/core/config.py Introduces ADMIN_SECRET config behavior for admin-protected routes.
CricketGame/backend/realtime/cpu.py Wraps CPU move selection in asyncio.to_thread() to avoid blocking the event loop.
CricketGame/backend/test_game_engine.py Adjusts a test mock signature to match updated call patterns.
CricketGame/backend/test_auth.py Adds tests for the new admin-secret protection on /auth/migrate-formats.
CricketGame/frontend/src/components/Lobby.tsx Improves accessibility for icon-only controls with ARIA labels/titles and focus styles.
CricketGame/frontend/package-lock.json Removes redundant "peer": true entries.
Files not reviewed (1)
  • CricketGame/frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +18
ADMIN_SECRET = os.getenv("ADMIN_SECRET")
if not ADMIN_SECRET:
if APP_ENV in ("production", "prod"):
raise ValueError("ADMIN_SECRET is required in production")
ADMIN_SECRET = "super-secret-admin-key"
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

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

ADMIN_SECRET falls back to a hardcoded value when unset. That makes the /auth/migrate-formats admin protection effectively guessable in any non-production environment that’s accidentally exposed. Prefer requiring ADMIN_SECRET in all environments, or generate a random per-process value (and log it only for local dev) so there isn’t a shared default secret across deployments.

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +29
client = TestClient(app)

def test_migrate_formats_no_header():
# Expect 422 because the header is required (Header(...))
response = client.get("/auth/migrate-formats")
assert response.status_code == 422

def test_migrate_formats_wrong_header():
# Expect 403 because the secret is invalid
response = client.get("/auth/migrate-formats", headers={"X-Admin-Secret": "wrong-secret"})
assert response.status_code == 403
assert response.json()["detail"] == "Invalid admin secret"

def test_migrate_formats_correct_header():
# Expect 200 because the secret matches
response = client.get("/auth/migrate-formats", headers={"X-Admin-Secret": ADMIN_SECRET})
assert response.status_code == 200
data = response.json()
assert "format_stats_2v2_merged" in data
assert "duplicate_rows_removed" in data
assert "match_history_fixed" in data
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

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

This test module creates a global TestClient(app) at import time and never closes it. Since the app has a lifespan that starts the learning processor, this can leak background threads/resources and may cause the test process to hang or interfere with other tests. Use a context-managed client (with TestClient(app) as client:) or explicitly call client.close()/provide a per-test fixture so lifespan shutdown runs reliably.

Suggested change
client = TestClient(app)
def test_migrate_formats_no_header():
# Expect 422 because the header is required (Header(...))
response = client.get("/auth/migrate-formats")
assert response.status_code == 422
def test_migrate_formats_wrong_header():
# Expect 403 because the secret is invalid
response = client.get("/auth/migrate-formats", headers={"X-Admin-Secret": "wrong-secret"})
assert response.status_code == 403
assert response.json()["detail"] == "Invalid admin secret"
def test_migrate_formats_correct_header():
# Expect 200 because the secret matches
response = client.get("/auth/migrate-formats", headers={"X-Admin-Secret": ADMIN_SECRET})
assert response.status_code == 200
data = response.json()
assert "format_stats_2v2_merged" in data
assert "duplicate_rows_removed" in data
assert "match_history_fixed" in data
def test_migrate_formats_no_header():
# Expect 422 because the header is required (Header(...))
with TestClient(app) as client:
response = client.get("/auth/migrate-formats")
assert response.status_code == 422
def test_migrate_formats_wrong_header():
# Expect 403 because the secret is invalid
with TestClient(app) as client:
response = client.get("/auth/migrate-formats", headers={"X-Admin-Secret": "wrong-secret"})
assert response.status_code == 403
assert response.json()["detail"] == "Invalid admin secret"
def test_migrate_formats_correct_header():
# Expect 200 because the secret matches
with TestClient(app) as client:
response = client.get("/auth/migrate-formats", headers={"X-Admin-Secret": ADMIN_SECRET})
assert response.status_code == 200
data = response.json()
assert "format_stats_2v2_merged" in data
assert "duplicate_rows_removed" in data
assert "match_history_fixed" in data

Copilot uses AI. Check for mistakes.
data = response.json()
assert "format_stats_2v2_merged" in data
assert "duplicate_rows_removed" in data
assert "match_history_fixed" in data
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

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

This new test file uses pytest-style discovery, but the existing backend tests in this repo are standalone scripts with run_all_tests() + a __main__ block (and pytest isn’t listed in backend/requirements.txt). As-is, this file likely won’t be executed by the current test workflow. Either adapt it to the repo’s script-style convention or add pytest + CI wiring so these tests actually run.

Suggested change
assert "match_history_fixed" in data
assert "match_history_fixed" in data
def run_all_tests() -> None:
"""
Run all tests in this module.
This mirrors the standalone script-style convention used by other backend tests,
so the existing test workflow can execute these tests without pytest.
"""
test_migrate_formats_no_header()
test_migrate_formats_wrong_header()
test_migrate_formats_correct_header()
if __name__ == "__main__":
run_all_tests()

Copilot uses AI. Check for mistakes.
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.

3 participants