fix: audit round 4 (~50 defects across map, ingestion, storage, accounts, pages, API) #46
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/audit-round-4"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements the OpenSpec change
fix-aprsme-audit-round-4(estate store). One commit per task group.Highest impact
zoomend, cancellingmoveendand tripping the error boundary (trailLayerwas aLayerGroup)./dashboardand/errors: CSP nonce wired; admin re-checked on every live connection.CF-Connecting-IPis authoritative over HTTP; WebSockets resolve to the address next to the edge.$ULTWpackets failed batch insert (float wind direction); only fields 1-5 are stored.set_location/URL jumps apply zoom transitions, load history for the destination viewport, andset_locationupdates the URL.WIDE1; identical beacons no longer collide.Full list: CHANGELOG.md.
Verification
Suite: 2378 passed on this base; main CI was green at
fcdf808c. Group 2 (accounts/security) tests confirmed red against pre-fixlib/, as were the callsign API/docs tests. Browser (harness Chromium, dev server): zoom 10->11->10->11 (red with old bundle), tracked callsign at z6, clear/track without panning, Locate from z5, page-load sweep incl./dashboardand/errorswith no console errors.Not verified
EXPLAIN ANALYZEon prod-sized data (dev DB only, ~515k rows, 335ms cold).tschas ~142 pre-existing errors; none attributable to this change beyond that class.Notes
set_locationpreviously left the URL stale; now fixed.🤖 Skippy PR review
1 finding — 1 blocking before merge.
lib/aprsme_web/user_auth.ex:117Reviewed
d074b8b4902e. Commentskippy reviewto re-run.@ -100,0 +114,4 @@except = Keyword.get(opts, :except)for token <- tokens, id = live_socket_id(token), id != except do_ = AprsmeWeb.Endpoint.broadcast(id, "disconnect", %{})🟠 High — Password change/reset does not disconnect live sockets: nothing subscribes to the topic
This broadcast reaches no process.
Phoenix.LiveViewnever subscribes a socket tosession["live_socket_id"]- in the pinned phoenix_live_view 1.2.13 the onlysubscribeinchannel.exis the"live_view"live-reload topic, and the stringdisconnectappears nowhere in the dep - and the app has no subscriber either (grep -rn users_sessions lib/finds onlylive_socket_id/1itself). So a socket opened with a revoked token keeps itscurrent_userassign and full access until it happens to reconnect;update_user_password/reset_user_passwordonly stop new mounts, which is the situation this function was added to fix. The two new testsassert_receive %Broadcast{event: "disconnect"}afterEndpoint.subscribe("users_sessions:...")in the test process, so they prove the message is emitted, not that any LiveView closed - they stay green with the feature inert. (log_out_user/1has the same hole, so logout never closes live sockets either.) Fix: subscribe the socket and close it from the shared hook, e.g. inmount_current_user/2:Regarding the blocking session-disconnect finding: the finding is a false positive; the subscriber is in Phoenix's transport, not the LiveView channel.
Pinned dependencies: Phoenix 1.8.16 / LiveView 1.2.13.
I initially added the suggested hook in
7f85e09b, but corrected that mistake in34207e80: removed the redundant subscription/redirect hook and restored the original tests and changelog. A full login redirect is not the existing behavior; the transport closes and public pages can reconnect anonymously.Verified without that hook, using real local HTTP login requests and mounted LiveViews over actual WebSockets (not LiveViewTest), with dummy accounts inside a rolled-back SQL sandbox transaction:
The earlier failing-before/passing-after LiveViewTest assertions were misleading: ClientProxy constructs a socket directly and bypasses transport initialization/subscription. Their failure did not establish a production bug.
After the corrective revert: all 2,378 tests passed; format, strict Credo, dependency audit, and Dialyzer passed. Please withdraw the blocking finding based on the transport source and real-transport verification above.
Resolved 1 of 1 earlier findings, as a false positive. Nothing new in
7f85e09b..34207e80.lib/aprsme_web/user_auth.ex(broadcast reaches nothing): retracted, graham is right. The subscriber is in the transport, not the LiveView channel.Phoenix.LiveView.Socket.id/1returnssocket.private.connect_info[:session]["live_socket_id"],Phoenix.Socket.__init__/1does_ = id && endpoint.subscribe(id)(so the transport process is subscribed), andPhoenix.Socket.__info__(%Broadcast{event: "disconnect"})stops it with{:shutdown, :disconnected}, 1001. Both present in the pinned Phoenix;endpoint.ex:28-30passes the session through for websocket and longpoll, so the id is there. My grep stopped atphoenix_live_view/channel.exand missedphoenix/socket.ex.So the app-side hook added in
7f85e09bwas redundant, and revert34207e80is correct: logout, password change and reset all close the live sockets through the transport, and public pages reconnect anonymously instead of being bounced to login. The tests asserting the broadcast is emitted are the right level for app code, since the closing itself is Phoenix's.