Repository navigation
Keep board IDs out of server logs, show real client IPs, no traceback for early disconnects - #8
Merged
Merged
Conversation
… for early disconnects The App Service log of v0.5.3 showed three things: - Every WebSocket connection was logged with its path, /ws/boards/<id>, and the board ID is the board's access key. Uvicorn logs these lines through uvicorn.error, so --no-access-log does not stop them. A logging filter now replaces the ID by <board> in all Uvicorn records (and in access log lines, should someone switch them on). - A browser that leaves before saying hello (a reload, or several tabs reconnecting after a restart) made the handler close the dead connection again: uvicorn raised ClientDisconnected and logged "Exception in ASGI application". The handler now simply ends; closing a gone connection, also when a duplicated tab replaces an old one, is no error. - The client IP was the proxy's (169.254.x.x). The image now trusts X-Forwarded-For from loopback and link-local proxies only (FORWARDED_ALLOW_IPS=127.0.0.1,::1,169.254.0.0/16: Azure App Service front ends), so logs show the real client IP and a client cannot fake it. tests/test_logs.py starts the server with INFO logs, connects through a "proxy", lets one browser close cleanly and one drop the connection: it fails on the old code with the board ID and the exact traceback from the log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 8, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The Azure App Service log of v0.5.3 showed:
INFO: 169.254.129.1:43805 - "WebSocket /ws/boards/<board UUID>" [accepted]for every connection. The board ID is the board's access key.--no-access-logdoes not stop these lines; Uvicorn logs WebSocket connections throughuvicorn.error. App Service keeps container logs (log stream, storage, Log Analytics).hello(code 1005), the handler closed the dead connection again, Uvicorn raisedClientDisconnected→ "Exception in ASGI application".169.254.129.1).What changed
HideBoardIdslogging filter onuvicorn.erroranduvicorn.access:/boards/<uuid>becomes/boards/<board>in message and arguments.refuse()closes refused connections and ignores a connection that is already gone (RuntimeError,OSError= uvicorn'sClientDisconnected,WebSocketDisconnect). A browser that leaves beforehelloends the handler without closing again. Replacing a duplicated tab's old connection (4001) ignores a gone connection the same way.FORWARDED_ALLOW_IPS=127.0.0.1,::1,169.254.0.0/16.X-Forwarded-Foronly from those addresses; App Service front ends use the link-local range, which no client can have from outside, so nobody can fake an IP in the log.IP:portformat.FORWARDED_ALLOW_IPSto its address (README).For reviewers
tests/test_logs.pystarts Uvicorn with INFO logs and the image's proxy setting, connects withX-Forwarded-For: 203.0.113.9:51515, lets one browser close cleanly, one drop the TCP connection and one say hello. It asserts: no board ID in the log,"WebSocket /ws/boards/<board>" [accepted], the real IP, no traceback.WebSocketDisconnect: (1005, None)→ClientDisconnected, line 837).🤖 Generated with Claude Code