Replace ban notice text with structured banned message#1084
Conversation
📝 WalkthroughWalkthroughThe PR converts ban error messages from human-readable notice payloads to a structured ChangesBan Message Serialization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
server/lobbyconnection.py (1)
225-226: ⚡ Quick winDecouple ban disconnect logging from legacy
BanError.message()Line 226 still builds the old humanized message path just for abort logging. Using the structured payload here keeps ban handling fully protocol-agnostic and unblocks cleanup of legacy ban-text code paths.
Proposed refactor
except BanError as e: - await self.send(e.to_dict()) - await self.abort(e.message()) + banned_payload = e.to_dict() + await self.send(banned_payload) + await self.abort( + f"Banned user rejected: reason={banned_payload['reason']!r}, " + f"expires_at={banned_payload['expires_at']}" + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/lobbyconnection.py` around lines 225 - 226, The code calls await self.abort(e.message()) which rebuilds legacy humanized ban text; change it to pass the structured payload returned by e.to_dict() instead so ban handling stays protocol-agnostic. Update the call in lobbyconnection.py to await self.abort(e.to_dict()), leaving the preceding await self.send(e.to_dict()) intact, and ensure abort(self, payload) accepts and forwards the structured dict (not a string) from the BanError instance (referenced as e with methods to_dict() and message()).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/integration_tests/test_login.py`:
- Around line 41-43: The test currently only asserts that "expires_at" exists in
msg; instead parse msg["expires_at"] (used in the assertions around the msg
dict) as an ISO-8601 timestamp and validate it represents UTC (either tzinfo ==
timezone.utc or an offset of +00:00 / a trailing "Z") and that parsing does not
raise; replace the simple presence check with this parse+UTC-check for both
occurrences (the block asserting msg["command"]=="banned" / msg["reason"] and
the similar asserts at lines 70-72) so the test fails if the server returns a
non-ISO or non-UTC timestamp.
---
Nitpick comments:
In `@server/lobbyconnection.py`:
- Around line 225-226: The code calls await self.abort(e.message()) which
rebuilds legacy humanized ban text; change it to pass the structured payload
returned by e.to_dict() instead so ban handling stays protocol-agnostic. Update
the call in lobbyconnection.py to await self.abort(e.to_dict()), leaving the
preceding await self.send(e.to_dict()) intact, and ensure abort(self, payload)
accepts and forwards the structured dict (not a string) from the BanError
instance (referenced as e with methods to_dict() and message()).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e48cb2f9-a457-4183-9ad3-e7d0bda0513d
📒 Files selected for processing (5)
server/exceptions.pyserver/lobbyconnection.pytests/integration_tests/test_login.pytests/integration_tests/test_server.pytests/unit_tests/test_lobbyconnection.py
| assert msg["command"] == "banned" | ||
| assert msg["reason"] == "Test permanent ban" | ||
| assert "expires_at" in msg |
There was a problem hiding this comment.
Assert expires_at is UTC ISO-8601, not just present
Current checks won’t fail if the server returns a non-ISO or non-UTC timestamp. Parse and validate timezone to lock the contract required by Issue #640.
Proposed test hardening
+from datetime import datetime, timezone
from time import time
@@
msg = await proto.read_message()
assert msg["command"] == "banned"
assert msg["reason"] == "Test permanent ban"
- assert "expires_at" in msg
+ expires_at = datetime.fromisoformat(msg["expires_at"])
+ assert expires_at.tzinfo is not None
+ assert expires_at.utcoffset() == timezone.utc.utcoffset(expires_at)
@@
msg = await proto.read_message()
assert msg["command"] == "banned"
assert msg["reason"] == "Test permanent ban"
- assert "expires_at" in msg
+ expires_at = datetime.fromisoformat(msg["expires_at"])
+ assert expires_at.tzinfo is not None
+ assert expires_at.utcoffset() == timezone.utc.utcoffset(expires_at)Also applies to: 70-72
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/integration_tests/test_login.py` around lines 41 - 43, The test
currently only asserts that "expires_at" exists in msg; instead parse
msg["expires_at"] (used in the assertions around the msg dict) as an ISO-8601
timestamp and validate it represents UTC (either tzinfo == timezone.utc or an
offset of +00:00 / a trailing "Z") and that parsing does not raise; replace the
simple presence check with this parse+UTC-check for both occurrences (the block
asserting msg["command"]=="banned" / msg["reason"] and the similar asserts at
lines 70-72) so the test fails if the server returns a non-ISO or non-UTC
timestamp.
Summary
bannedcommand when a user is rejected for an active banexpires_atvalue for client-side localizationValidation
python -m py_compile FAForever-server\server\exceptions.py FAForever-server\server\lobbyconnection.py FAForever-server\tests\integration_tests\test_login.py FAForever-server\tests\integration_tests\test_server.py FAForever-server\tests\unit_tests\test_lobbyconnection.pypython -m pytest tests\unit_tests\test_lobbyconnection.py::test_abort_connection_if_banned tests\integration_tests\test_login.py::test_server_ban tests\integration_tests\test_login.py::test_server_ban_token tests\integration_tests\test_server.py::test_server_ban_prevents_hosting --mysql_database=faf -qResult: 13 passed, 8 warnings from test RSA key length.
Closes #640
Summary by CodeRabbit
Bug Fixes