{{ message }}
Repository navigation
R&D: all our internally consumed PRs as of Apr 3, 2026 5:09p EST - #828
Merged
Merged
Conversation
Initial cleanup and tweaks
revert --rm containers
…y-union/videocall-rs into p7cc-poc
Show self in attendants + get latest main as of Aug/14
…ecurity-union#757) * helm: add Prometheus annotations, lower relay requests, add Dioxus UI chart - Add prometheus.io scrape annotations to WS and WT relay pods - Lower relay CPU/memory requests (limits unchanged) to prevent scheduling deadlocks on single-node clusters - Add Chart.yaml for Dioxus UI us-east region overlay * helm: remove defunct Singapore WS/WT URLs from us-east videocall-ui Singapore region was dropped; client was still configured to attempt connections to dead websocket-singapore and webtransport-singapore endpoints. --------- Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…protocol Feat/select protocol
Member
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…n a meeting (security-union#828) Removes the unconditional same-user-id eviction in the chat-server's JoinRoom handler so that a single authenticated user joining from multiple browser tabs / devices / instances appears as N distinct participants instead of collapsing to one. The user reported the symptom: opening the same meeting on 3 laptops while signed in as the same Google user only ever showed self in each instance. Backend (actix-api/src/actors/chat_server.rs): - Delete evict_same_user_session() helper. The unconditional call from the JoinRoom handler was the collapse point — it scanned room_members for any prior session with the same user_id and silently forgot it without broadcasting PARTICIPANT_LEFT, so peers never knew about more than one session per user. - Instance-id-based eviction (the upstream path that handles same-tab refresh / back-button) is preserved verbatim: each tab generates its own instance_id in sessionStorage, so a refresh keeps the same instance_id and correctly evicts the stranded session, while a new tab gets a fresh instance_id and coexists. - Replace the prior "latest joiner wins" policy comment with one that documents the new multi-session-per-user posture and references security-union#828. - 5 integration tests rewritten / renamed to assert coexistence: same_user_different_sessions_coexist_in_room, peer_sees_both_same_user_sessions_on_join, multi_tab_dup_no_instance_id_coexists, same_user_same_instance_still_evicts_on_refresh (regression lock-in for the preserved instance-id path), reconnection_grace_cancels_pending_departure. Frontend (videocall-client/src/client/video_call_client.rs): - The is_duplicate_peer_event toast-dedup filter previously keyed on (event_type, user_id) — a 30s window meant the second session's PARTICIPANT_JOINED for the same user_id would be silently filtered. Upgrade the key to (event_type, user_id, Option<session_id>) so per-session events for two distinct sessions of the same authed user both fire. Sibling is_duplicate_host_action (HOST_MUTE, HOST_DISABLE_VIDEO) intentionally stays user-keyed — those actions are per-user by design and the dual-transport collapse is still correct. - 4 wasm-bindgen unit tests added: distinct-session joins not deduped, same-(user, session) over dual transports still deduped, PARTICIPANT_LEFT mirrors the same scoping, host actions remain user-scoped. E2E (e2e/tests/same-user-multi-session.spec.ts): - New spec, 2 cases. Opens two then three Playwright BrowserContexts all authenticated as the same JWT identity, joins each into the same meeting, and asserts each side sees the expected number of distinct peer tiles (2 and 3 respectively) keyed by the canvas-generator's per-session peer-video-{session_id}-div id pattern. Out-of-scope follow-up flagged: pending_departures is currently keyed by (room, user_id). Two same-user sessions disconnecting in sequence will collide on this key — previously unreachable due to the eviction this PR removes; now a real edge case. Will file a separate issue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…s + is_self_peer + join toast (security-union#828) Follow-on to the original security-union#828 fix in this PR's first commit. A guest-flow audit on the head SHA surfaced four merge-blocking gaps (three on the backend, two on the frontend) where downstream consumers still keyed on user_id and silently broke when multi-session-per-user coexistence was enabled. Issue security-union#852 (pending_departures collision), originally filed as a fast-follow, is absorbed into this PR because the audit showed it's inseparable from a clean user-facing fix. Backend (actix-api/src/actors/chat_server.rs): - Rekey pending_departures from (room, user_id) to (room, instance_key) where instance_key = the per-tab instance_id (or a synthetic __session__:<sid> sentinel for legacy joins that don't carry one). instance_id is the right key because it persists across same-tab refresh (which is what reconnection-grace wants to detect) while separating distinct tabs of the same user. - Updated all four call sites: Disconnect (the replace-or-insert when registering a new pending departure), Leave (the explicit-leave grace cancel), JoinRoom reconnection-grace lookup (now requires instance_id to be Some to count as a reconnection), and forget_session (used by cross-server eviction). instance_key is sourced via the existing session_instance reverse map at the three session-id-driven sites. - Threaded instance_key through ExecutePendingDeparture so the handler reconstructs the right key at fire time, independent of session_instance state. - Added 4 new integration tests: disconnect_of_one_session_does_not_remove_sibling_same_user_session, disconnect_of_both_same_user_sessions_creates_two_independent_grace_entries, explicit_leave_of_one_session_does_not_cancel_sibling_grace, fresh_second_session_of_same_user_is_not_misclassified_as_reconnection. - Updated the two existing reconnection-grace tests (reconnection_grace_ cancels_pending_departure, test_reconnect_within_grace_skips_broadcast_ and_db_event) to model real sessionStorage behavior — same instance_id across the disconnect/reconnect cycle. The pre-fix tests passed different/None instance_ids, which was testing the buggy semantic. - Updated the struct doc on pending_departures and the JoinRoom comment block that previously called out the (room, user_id) collision as a known unresolved edge case. Frontend (videocall-client + dioxus-ui): - canvas_generator.rs: my_peer_id parameter renamed to my_session_id; all four compare sites (split-layout decision at :266, ScreenOnly self- suppression at :361, is_self_peer at :367, screen-share grid guard at :874) now compare against the local session_id (the canvas-generator's per-tile key parameter) rather than the local user_id. This was the cause of the sibling-tile rendering glitch where two same-user tabs (or two guest tabs sharing one guest:<uuid>) saw each other's tiles silently elide in split layouts. - peer_tile.rs: prop renamed my_peer_id -> my_session_id; the host-mute is_self_peer check (line 234) also fixed; my_session_id is forwarded to generate_for_peer. - attendants.rs: lifted let my_session_id = client.get_own_session_id() once per render; all five PeerTile { my_peer_id: ... } call sites switched to my_session_id; the join-toast suppression now prefers has_peer_with_session_id(session_id) over has_peer_with_user_id when the server stamped a session_id (which it always does in practice). - video_call_client.rs: widened the on_peer_joined and on_peer_left callback tuples to (display_name, user_id, session_id) so the attendants.rs suppression check can run synchronously with the session_id in hand. Added has_peer_with_session_id(session_id) helper on VideoCallClient. Added a wasm-bindgen empty-state regression test. - lib.rs: updated module-docs callback signatures. E2E (e2e/tests/same-user-multi-session.spec.ts): - 2 new cases appended to the spec the original security-union#828 fix added: "sibling same-user session renders the other session's screen-share in the ScreenOnly split panel" (locks in the is_self_peer fix), and "idle same-user session receives a join toast when a sibling session joins" (locks in the suppression fix; polls for .peer-toast.toast- joined before the second join to avoid the 8-second auto-dismiss race). Build verification (all green): - cargo fmt --all -- --check - cargo check / clippy -p videocall-api --tests -- -D warnings - cargo check / clippy --target wasm32-unknown-unknown -p videocall-ui -p videocall-client -- -D warnings - cd e2e && prettier --check + eslint + tsc --noEmit on the changed spec - cargo test -p videocall-api --lib actors::chat_server::tests: 53 passed (4 pre-existing failures unrelated to this change require DATABASE_URL) Closes security-union#852. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…tyle token guardrails CI The Style token guardrails script greps for hex-color literals via a regex that matches the issue-reference shorthand "security-union#828" as a 3-char hex color. Rewrites the 8 occurrences in attendants.rs / canvas_generator.rs / peer_tile.rs comments from "(HCL security-union#828)" to "(HCL issue 828)". Same semantic meaning, no longer matches the regex. Locally verified via bash scripts/check-hardcoded-colors.sh --unstaged returns "No new hardcoded color literals found outside allowlisted token files." The guardrails script regex should be tightened to exclude `#NNN` followed by non-hex / word-boundary in source comments, but that is a CI-script fix separate from this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…script flagged The previous chore commit ff38a81 rewrote `(HCL security-union#828)` → `(HCL issue 828)` but missed one occurrence of `pre-security-union#828 behaviour` in attendants.rs:1192 (different surrounding context — my grep was too narrow). The Style token guardrails CI check kept failing on this single line. Rewritten to `pre-issue-828 behaviour`. Locally verified via `bash scripts/check-hardcoded-colors.sh --unstaged` → "No new hardcoded color literals found outside allowlisted token files." Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…i-session (security-union#828) Follow-on to PR security-union#851. User reported: when one tab of a same-authenticated- user multi-session pair renames itself, the rename was being broadcast keyed by user_id only, so the sibling tab's display name also changed. Expected: only the renaming tab's name changes; sibling tabs keep their own names; all peers see the renaming tab's new name on that tab's tile. Root cause: the rename pipeline collapsed by user_id at 3 server-side layers. Client-side receive path was already correct (already branches on `meeting_packet.session_id != 0`), but the broadcast never populated that field — so the receive fallback `set_peer_display_name_by_user_id` fired and overwrote every peer with the matching user_id. Wire shape (videocall-meeting-types/src/requests.rs:97-108): - UpdateDisplayNameRequest gains `session_id: Option<u64>` with `#[serde(default, skip_serializing_if = "Option::is_none")]`. Legacy clients omitting the field still work; new clients pass their own per-tab session_id from `VideoCallClient::get_own_session_id()`. Client-side wiring (dioxus-ui + videocall-meeting-client + videocall-client): - videocall-meeting-client/src/participants.rs:146-170: `update_display_ name` takes `session_id: Option<u64>` and serializes it on the body. - dioxus-ui/src/meeting_api.rs:122-132: helper extended with the same parameter. - dioxus-ui/src/components/update_display_name_modal.rs:23: new prop `session_id: Option<u64>`; submit handler passes it through. - dioxus-ui/src/components/attendants.rs:3262-3292: at the modal call- site, reuse the `my_session_id: Option<String>` computed at :2294 (the same value already plumbed for the `is_self_peer` fix earlier in this PR). Parse to u64; fall back to `None` if unparseable / unassigned. - videocall-client/src/client/video_call_client.rs:2173-2187: receive branch `if meeting_packet.session_id != 0 { set_peer_display_name(...) } else { set_peer_display_name_by_user_id(...) }` was already in place — verified intact, no change needed at this site. With the broadcast now populated, the session-scoped path is the active path. Server-side wiring (meeting-api + actix-api): - meeting-api/src/nats_events.rs:175-205: `publish_participant_display_ name_changed` takes `session_id: Option<u64>` and writes it to `packet.session_id` (defaults to 0 on None). Added unit tests at :483-535 covering both populated and legacy paths. - meeting-api/src/routes/participants.rs:713-732: forwards `body.session _id` to the publisher. DB write at :707-710 is unchanged — per-session display names are intentionally not persisted; the DB stores the user's default name (what new joins inherit), and rename is an in- meeting decoration. - actix-api/src/actors/chat_server.rs:163-173: `UpdateMemberDisplayName` message gains `session_id: u64` (0 = legacy sentinel matching the proto default). - actix-api/src/actors/chat_server.rs:1118-1175 (handler): branches on session_id. Non-zero → look up the single `(session, user_id)` row and update only it. Zero → preserve user-id-wide iteration for legacy clients. - Stale / cross-user session_id validation: when `msg.session_id != 0` and no matching `(session, user_id)` row is found, the handler logs a `warn!` with both fields and no-ops. Does NOT fall through to user-id- wide update. This blocks both stale session_ids and request-smuggling attempts where one user sends another user's session_id. - actix-api/src/actors/chat_server.rs:1864-1894: extracts `inner. session_id` from the NATS MeetingPacket and forwards it on the `UpdateMemberDisplayName` message; preserves the field on the re-broadcast packet so peers can scope rendering. Cross-cutting concern noted: - session_logic::SessionLogic.display_name (session_logic.rs:190) is the JoinRoom-time name, used as the fallback in `PARTICIPANT_LEFT` at disconnect. Intentionally NOT updated on rename — the disconnect broadcast carries the name the participant joined with, not their live in-meeting name. Authoritative live name lives in `room_members [room][i].display_name`, which is what the handler updates. Tests: - chat_server.rs `mod tests`: 4 new `#[actix_rt::test] #[serial]` cases pinning the per-session semantics: - `rename_one_session_only_updates_that_sessions_room_members_row` - `rename_with_session_id_zero_falls_back_to_user_id_wide_update` - `rename_with_stale_session_id_no_ops_with_warn` - `rename_with_session_id_belonging_to_different_user_no_ops` - meeting-api/src/nats_events.rs:483-535: 2 new packet-shape unit tests. - meeting-api/tests/display_name_session_scoped_tests.rs (new file): 2 REST integration tests — accept-new-field and legacy-omitted-field. - videocall-client wasm-bindgen unit test `display_name_change_with_session_id_is_session_scoped` in `dedup_tests` module: two sibling sessions of the same user, rename one, assert the sibling is untouched. - E2E: new case `renaming one same-user session does not change a sibling session's display name` in `e2e/tests/same-user-multi- session.spec.ts`. Drives the actual rename modal on Tab A; inspects Tab B's self-row to confirm it still shows the original name. Build verification (all green): - cargo fmt --all -- --check - cargo clippy -p videocall-api -p meeting-api --tests -- -D warnings - cargo clippy --target wasm32-unknown-unknown -p videocall-client -p videocall-ui -- -D warnings - cd e2e && prettier --check + eslint + tsc --noEmit on the changed spec - chat_server::tests: 57/57 pass (existing security-union#851 tests still green) - meeting-api new tests: 2/2 pass; nats_events: 14/14 pass; rejoin regression: 3/3 pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…en guardrails) Two new occurrences in commit 4f1bda5's diff slipped past the same regex check that previously bit on (HCL security-union#828): `HCL issue security-union#828 follow-up` in `attendants.rs:3266` and `(HCL issue security-union#828 follow-up)` in `update_display_name_modal.rs:24`. The check-hardcoded-colors.sh script matches `security-union#828` as a 3-char hex shorthand color regardless of the surrounding word; dropping the `#` makes the pattern read as `issue 828` and the regex no longer matches. Locally verified via `bash scripts/check-hardcoded-colors.sh --unstaged` → "No new hardcoded color literals found outside allowlisted token files." Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…lf update doesn't fire on sibling-tab rename (security-union#828) Follow-on to 4f1bda5's per-session rename fix. The PR security-union#851 work correctly scoped the peer-tile updates (via session-keyed `set_peer_display_name`), but missed the local-self update path through the `on_display_name_changed` callback. The callback was keyed only on `user_id`, so when one tab of a same-user multi-session trio renamed itself, all 3 tabs' callbacks fired with matching user_id and updated their own `current_display_name` / context signal to the broadcast value. User-visible symptom: rename Tab A, Tabs B and C also show the new name on their own self-tile. Verified live on a localhost stack with 3 tabs of the same Google user: meeting-api logs showed per-session broadcasts being published correctly (different `session_id` per tab), confirming the bug was purely client-side. Fix: 1. Widen `Options::on_display_name_changed` callback signature from `Callback<(String, String)>` to `Callback<(String, String, u64)>` — the third tuple element is the renamed session_id from the wire packet (`meeting_packet.session_id`). - `videocall-client/src/client/video_call_client.rs:251`: public Options type, doc comment updated to describe the session_id gating contract. - `videocall-client/src/client/video_call_client.rs:328`: Inner options. - `videocall-client/src/client/video_call_client.rs:541`: clone site. 2. Update the emit site at `videocall-client/src/client/video_call_client.rs:2196-2211` to pass `meeting_packet.session_id` as the third tuple element. Legacy fallback (session_id=0 from older non-per-session broadcasts) is documented inline. 3. Update the consumer in `dioxus-ui/src/components/attendants.rs:1246-1322`: closure now captures `client_for_reconnect.clone()` so it can read the local tab's own session_id at event time, and applies the local-self update only when `event_session_id == 0` (legacy) or `event_session_id == own_session_id` (per-session match). Sibling-tab broadcasts are logged at info level and skipped. All other consumers of `on_display_name_changed` set it to `None` (verified: `videocall-client/src/lib.rs` docs, `screen_encoder.rs`, the three dioxus pages, the test scaffolding) — type-compatible with the new shape, no edits required. New wasm-bindgen test `display_name_change_callback_carries_session_id` builds a real MeetingPacket (PARTICIPANT_DISPLAY_NAME_CHANGED, session_id= 11_909_780_505_735_931_018) inside a PacketWrapper, pushes it through `on_inbound_media`, and asserts the registered callback receives `(user_id, "Tester 1", 11_909_780_505_735_931_018)`. Locks in the wire-shape contract — a regression that drops the third tuple element or zeros out session_id fails the test. Build verification (all green): - cargo fmt -p videocall-client -p videocall-ui -- --check - cargo check --target wasm32-unknown-unknown -p videocall-client -p videocall-ui --tests - cargo clippy --target wasm32-unknown-unknown -p videocall-client -p videocall-ui -- -D warnings (clean on touched code) - wasm-pack test --headless --firefox --lib videocall-client: new test passes, existing display-name tests pass (the 11 pre-existing failures in `peer_decode_manager::tests::*` keyframe / sequence tracker are unrelated and present on baseline). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
… rows don't collapse (security-union#828) Follow-on to PR security-union#851's per-tile and self-update rename fixes (1c1f103, 4f1bda5). The per-tile display names were rendering per-session correctly, but the attendee list sidebar was still collapsing N same-user sessions into a single row because the rendering pipeline was keyed on user_id throughout. User-visible symptom (reported live on a localhost stack with 3 same-user tabs): "the attendee list has a mixture of the last name changed and the host's display name. the tiles display name however is correct." Root cause: 1. attendants.rs:1974-1981 mapped display_peers (Vec<session_id>) to peers_for_display: Vec<user_id> via get_peer_user_id. With N same-user tabs, the resulting Vec contained N identical user_id strings. 2. peer_list.rs:91-95 built a reverse lookup `user_id_to_sid: HashMap<String, String>` by collecting from `client_ctx.sorted_peer_keys()`. HashMap::collect on duplicate keys keeps the LAST inserted value — so for 3 same-user sessions the map held one entry mapping the user_id to whichever session won the non-deterministic insertion race. Every same-user row then rendered the same display name (whichever session's broadcast arrived last). Fix — pivot the peer list to be keyed on session_id, not user_id. With multi-session-per-user landed, "one row per session" is the correct shape: each tab is its own participant for display purposes. Host actions (mute / disable-video) remain per-user by design per PR security-union#556's host-action contract — every session of a muted user gets muted. Changes: 1. New `pub struct PeerListEntry { session_id, user_id }` in peer_list.rs:38-48. Easier to evolve later than `(String, String)` and clearer at use-sites. 2. peer_list.rs:51 — `peers: Vec<PeerListEntry>` (was `Vec<String>` of user_ids). 3. peer_list.rs:114-120 — removed the `user_id_to_sid` HashMap collapse point. Replaced with `filter_peers_for_search` pure helper at :489-505 that matches search query against session_id, user_id, AND display_name (so users can find a session by any of the three). 4. peer_list.rs:340-446 — render loop now reads per-row state via `peer.session_id` (display_name, is_guest, audio/video/speaking state). Host actions (on_mute, on_disable_video callbacks; tooltip; is_peer_host indicator) still use `peer.user_id` to preserve the per-user host-action contract from PR security-union#556. 5. peer_list.rs:450 — row `key:` attribute now `peer.session_id` (was user_id, which guaranteed duplicate keys with same-user sessions and triggered Dioxus reconciliation warnings on the rsx node). 6. attendants.rs:1973-1990 — builds `Vec<PeerListEntry>` directly from `display_peers` (already session-keyed). Filter `peer_list::PeerListEntry` added to local `use` group. Per-row state map populators are unchanged — the audio/video/speaking state maps in peer_list.rs:480-578 already write with session_id keys (verified at videocall-client peer_decode_manager.rs:449 and neteq_audio_decoder.rs:219 — the `to_peer` metric carries `session_id.to_string()`). The bug was purely at the read side, going through user_id_to_sid. Tests: - 3 new inline `#[cfg(test)] mod tests` in peer_list.rs:585-748: - `filter_peers_keeps_all_same_user_sessions` (headline regression): 3 same-user PeerListEntry instances survive the filter; render-time per-session display-name lookup resolves to 3 distinct names. - `filter_peers_search_matches_display_name`. - `filter_peers_search_matches_session_id`. - New E2E case `three same-user sessions render as three distinct rows with distinct names in the attendants panel` in e2e/tests/same-user-multi-session.spec.ts:628-770 plus a `renameSelf()` helper at :779-808. Opens 3 BrowserContexts as the same Google-mock user; Tab B and Tab C rename themselves; asserts 3 `.peer_item` rows in `#peer-list-container` and 3 distinct cleaned display names. This is the test that would fail on the un-fixed pre-fix code (asserts on the rendered DOM); the inline tests lock in the forward-looking invariant. Build verification (all green): - cargo fmt --all -- --check - cargo check --target wasm32-unknown-unknown -p videocall-client -p videocall-ui --tests - cargo clippy --target wasm32-unknown-unknown -p videocall-client -p videocall-ui -- -D warnings - cargo test -p videocall-ui --lib peer_list::tests: 3/3 pass - cd e2e && npx prettier --check tests/same-user-multi-session.spec.ts && npx eslint tests/same-user-multi-session.spec.ts && npx tsc --noEmit: all clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testradav
pushed a commit
to testradav/videocall-rs
that referenced
this pull request
May 22, 2026
…-user-multiple-instances fix: allow same authed user to appear as multiple distinct sessions (security-union#828)
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.

#765
#766
#776
#826