Skip to content

fix(meetings): match restricted-meeting registrants by the user's verified emails (PCC-1570) - #3341

Open
zhenghchen wants to merge 2 commits into
mainfrom
fix/pcc-1570-restricted-join-verified-emails
Open

zhenghchen wants to merge 2 commits into
mainfrom
fix/pcc-1570-restricted-join-verified-emails

Conversation

@zhenghchen

@zhenghchen zhenghchen commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes the join failure in PCC-1570. A signed-in user without an LF username couldn't join a restricted meeting from their calendar invite. They got "You are not registered for this restricted meeting" even though they were registered, because their registrant row is stored under their meeting-invite email, not their login email.

restrictedMeetingCheck (POST /public/api/meetings/:id/join-url) looks up registrants by only two things:

  1. the LF username
  2. the login email

itx-service-zoom writes committee registrants with the member's Meeting email preference and rewrites them when that preference changes, so the stored address can be any of the user's verified emails. An account with no username whose rows hold another address matches neither lookup.

The email lookups also had a casing problem. They matched email with a lowercased value, but query-service term matching is case-sensitive and email keeps the stored casing, so a mixed-case stored address never matched.

Fix

  • Join check only: when username and email both miss, restrictedMeetingCheck retries once against the user's other verified emails, using MeetingService.getMeetingRegistrantsByVerifiedEmails.
    • It sends one filters_or query.
    • Matches are ranked by email priority. The join link is requested with the matched row's stored email.
  • New UserVerifiedEmailsService resolves those emails:
    • The meeting-invite preference, read with the user's own gateway token. It's skipped while impersonating, because that token belongs to the real session user.
    • The auth-service primary, only when the session email is verified (the badges rule).
    • Verified alternates.
  • Failure handling:
    • The preference is best-effort. meeting-service only lets it be set to a verified address, so auth-service also returns it.
    • If auth-service fails and nothing matched, the endpoint returns 503 SERVICE_ADVISORY ("Unable to verify your meeting registration right now…") rather than telling a registered user they aren't registered.
  • Case-insensitive matching: getMeetingRegistrantsByEmail and getMeetingRegistrantsForUser now match email or case_insensitive_email. Both fields are indexed on v1_meeting_registrant.
  • badges.controller reuses the shared collectAuthServiceVerifiedEmails helper. Its behaviour is unchanged.
  • A match logs at info with matched_source (meeting_invite_preference | auth_service).

Users with a username, or whose login email matches, see no change and trigger no extra calls. Anonymous callers are unchanged.

Ticket

PCC-1570

Testing

  • Unit tests, a 13-scenario route integration spec (public-meeting-join.integration.spec.ts), and the full suite, lint and type-check pass.

Tested on the dev preview (ui-pr-3341, head d8cbf21).

Setup: restricted meeting, guest added by email alias (+pcc1570b) before that alias was verified on the account, so the registrant row has no username link. Same account, meeting, row and password on both hosts.

  • Current dev: POST /public/api/meetings/:id/join-url -> 403 NOT_REGISTERED_FOR_MEETING
  • This preview: same call -> 200 with a join link

@zhenghchen
zhenghchen requested a review from a team as a code owner October 7, 2026 06:49
Copilot AI balanced review requested due to automatic review settings October 7, 2026 06:49
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 4d01dbb2-4583-4dbc-bde6-1cacb3375e23

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes authorization for restricted meeting joins and depends on auth-service/NATS email resolution; mis-ranking or outage handling could block legitimate joins or briefly allow wrong error semantics.

Overview
Fixes PCC-1570: restricted-meeting join (POST …/join-url) no longer fails when the registrant row is stored under a meeting-invite alias or another verified address instead of the session login email.

After username and direct email lookups miss, restrictedMeetingCheck now calls getMeetingRegistrantsByVerifiedEmails, which resolves the caller’s other verified emails (meeting-invite preference first, then auth-service primary/alternates via new UserVerifiedEmailsService) and queries registrants in one shot. Matches are priority-ordered; the join link uses the matched row’s stored email. If email sources fail with no match, the API returns 503 SERVICE_ADVISORY instead of 403 not registered.

Email registrant queries now OR-match both email and case_insensitive_email to fix case-sensitive query-service matching. Shared types UserVerifiedEmails and MeetingRegistrantsByVerifiedEmails document the new flows.

Coverage adds unit tests, a 13-scenario HTTP integration spec for join-url, and service tests for verified-email resolution and lookup failure/impersonation behavior.

Reviewed by Cursor Bugbot for commit d9eb69c. Bugbot is set up for automated code reviews on this repo. Configure here.

dealako commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

@zhenghchen I'm starting review 1 of this pull request now (started 2026-10-07 06:52 UTC). This usually takes a few minutes — I'll update this comment with the summary when I'm done.


Hi @zhenghchen, thanks for the PR! This fixes the PCC-1570 restricted-meeting join failure by retrying the registrant lookup against the user's other verified emails. It also fixes the case-sensitivity gap by matching both email and case_insensitive_email. The scope is tight. The extra lookup runs only after the username and login-email lookups miss. Impersonation, anonymous callers, and unverified session emails are handled safely. A 503 is returned instead of a false "not registered" when auth-service is down. The unit tests and the 13-scenario integration spec cover the paths I traced.

No issues found in any dimension (correctness, security, privacy, performance, tests, style, docs).

✅ Approved

➡️ This auto-review agent is a preview. Please send feedback to @dealako.

dealako
dealako previously approved these changes Oct 7, 2026

@dealako dealako left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated review found no blocking, security, or privacy issues. Approved.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The identity handling, failure behavior, upstream query contract, and relevant edge cases are consistently implemented and thoroughly tested.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes restricted-meeting joins by matching registrants against the signed-in user’s verified email addresses.

Changes:

  • Adds prioritized verified-email resolution and case-insensitive registrant lookup.
  • Returns a retryable 503 when email verification is unavailable.
  • Adds unit and route-level integration coverage.
File Description
packages/​shared/​src/​interfaces/​user-profile.interface.ts Defines verified-email resolution results.
packages/​shared/​src/​interfaces/​meeting.interface.ts Defines verified-email registrant lookup results.
apps/​lfx-one/​src/​server/​services/​user-verified-emails.service.ts Resolves prioritized verified addresses.
apps/​lfx-one/​src/​server/​services/​user-verified-emails.service.spec.ts Tests email resolution and failure handling.
apps/​lfx-one/​src/​server/​services/​meeting.service.ts Adds case-insensitive, multi-email registrant matching.
apps/​lfx-one/​src/​server/​services/​meeting.service.spec.ts Tests query construction, ranking, and failures.
apps/​lfx-one/​src/​server/​controllers/​public-meeting.controller.ts Adds verified-email fallback to restricted joins.
apps/​lfx-one/​src/​server/​controllers/​public-meeting.controller.spec.ts Tests controller fallback behavior.
apps/​lfx-one/​src/​server/​controllers/​public-meeting-join.integration.spec.ts Exercises the complete restricted-join flow.
apps/​lfx-one/​src/​server/​controllers/​badges.controller.ts Reuses shared verified-email collection logic.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

🚀 Deployment Status

Your branch has been deployed to: https://ui-pr-3341.dev.v2.cluster.linuxfound.info

Deployment Details:

  • Environment: Development
  • Namespace: ui-pr-3341
  • ArgoCD App: ui-pr-3341

The deployment will be automatically removed when this PR is closed.

@MRashad26 MRashad26 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ran a full review plus the code-standards-enforcer agent (~/LFX/code-enforcer-agent.md), scoped to this PR's diff. 2 findings, neither blocking.

UserVerifiedEmailsService.getUserVerifiedEmails has zero logging, including on the incomplete: true path (user-verified-emails.service.ts:1126). When auth-service's user_emails.read NATS call fails/times out, EmailVerificationService.getUserEmails returns null and this service silently returns { incomplete: true, ... } with no trace at all — this violates .claude/rules/logging-patterns.md's rule to use logger.warning() for recoverable errors when returning null/empty. A production incident where verified-email join matching silently misses registrants would be invisible in logs today, since this file never calls logger.debug/info/warning. Suggested fix: add a warning log on the incomplete-lookup path.

restrictedMeetingCheck now chains up to 3 sequential query-service/NATS round-trips on the latency-sensitive public join-url path (public-meeting.controller.ts:1011). Any caller whose registrant record isn't matched by username or login email — the exact case this PR targets — now pays for 2 sequential query-service calls plus 2 more NATS round-trips before getting a response on POST /public/api/meetings/:id/join-url. The codebase already folds email+username into one filters_or query (getMeetingRegistrantsForUser); the verified-email clauses could in principle be merged into a single combined query once the verified emails are known, instead of adding a third strictly-sequential leg.

Everything else checked out clean: no correctness bugs found across 8 finder angles. Upstream assumptions verified against the real repos — case_insensitive_email is a genuinely indexed GSI field on the registrant model in lfx-v2-meeting-service, and filters/filters_or semantics in lfx-v2-query-service's OpenSearch query template match what this PR assumes. Impersonation handling, email-priority ranking, and lookupFailed/incomplete propagation are all covered by accompanying unit + integration tests (timeout, auth-service down, impersonation, mixed casing, anonymous caller). code-standards-enforcer: PASS — license headers, shared-interface placement, member ordering, kebab-case naming, 160-char lines, no console.log, fixture-email conventions all correctly followed.

Posting as Comment — both findings worth a look, neither a hard blocker.

Copilot AI balanced review requested due to automatic review settings October 8, 2026 17:18

dealako commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

@zhenghchen I'm starting review 2 of this pull request now (started 2026-10-08 17:30 UTC). This usually takes a few minutes — I'll update this comment with the summary when I'm done.


Hi @zhenghchen, thanks for the quick follow-up and for acting on the earlier feedback! The new commit is small and focused: it adds a warning log when the auth-service email lookup is unavailable, with a matching assertion in the spec. The logger call matches the logger.warning(req, operation, message, metadata) signature, and it logs only a boolean (no emails), so there is no privacy concern.

👏 Nice work: the log carries just has_preference as metadata, so it is useful for diagnosing silent registrant misses without leaking any email addresses, and the spec asserts it.

  • ✅ Resolved — missing logging on the incomplete: true path in UserVerifiedEmailsService (d8cbf21).
  • ℹ️ The earlier note about sequential round-trips on the join-url path was optional and isn't a blocker.

No new issues found in any dimension.

✅ Approved

➡️ This auto-review agent is a preview. Please send feedback to @dealako.

dealako
dealako previously approved these changes Oct 8, 2026

@dealako dealako left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow-up review: the new commit adds the requested warning log on the incomplete verified-email path. No blocking, security, or privacy issues. Approved.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

It changes a public authorization path and depends on cross-service identity and query contracts requiring human confirmation.

0 open findings

🧠 Review effort: Balanced

…s (PCC-1570)

A signed-in user without an LF username could not join a restricted meeting when their registrant row was stored under their meeting-invite email. The join check now retries once against the user's verified emails, and the email lookups match case-insensitively.

Signed-off-by: zhenghchen <zhenghchen2024@gmail.com>
Signed-off-by: zhenghchen <zhenghchen2024@gmail.com>
@zhenghchen
zhenghchen force-pushed the fix/pcc-1570-restricted-join-verified-emails branch from d8cbf21 to d9eb69c Compare October 12, 2026 19:15
Copilot AI balanced review requested due to automatic review settings October 12, 2026 19:15

dealako commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

@zhenghchen I'm starting review 3 of this pull request now (started 2026-10-12 19:20 UTC). This usually takes a few minutes — I'll update this comment with the summary when I'm done.


Hi @zhenghchen, thanks for keeping this branch current! This push rebased the PR onto the latest main. The two commits (the verified-email fallback and the incomplete-lookup warning log) are unchanged in content from the revision I approved in review 2, and the logger.warning call still matches the logger signature.

  • ✅ Resolved — all prior feedback (the warning log on the incomplete: true path) remains in place at the new head.

No new issues found in any dimension.

✅ Approved

➡️ This auto-review agent is a preview. Please send feedback to @dealako.

@dealako dealako left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow-up review: the branch was rebased onto current main; the content is unchanged from the previously approved revision (verified-email fallback plus the incomplete-lookup warning log). No blocking, security, or privacy issues. Approved.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The identity handling, upstream query contract, failure behavior, and test coverage are consistent and complete.

0 open findings

🧠 Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants