Skip to content

Comments

fix(event-types): harden email normalization and clean up CSP#25863

Open
prithamnandavaram wants to merge 13 commits intocalcom:mainfrom
prithamnandavaram:pr-22651
Open

fix(event-types): harden email normalization and clean up CSP#25863
prithamnandavaram wants to merge 13 commits intocalcom:mainfrom
prithamnandavaram:pr-22651

Conversation

@prithamnandavaram
Copy link

@prithamnandavaram prithamnandavaram commented Dec 14, 2025

What does this PR do?

It addresses code review feedback from PR #22651 to fix potential runtime errors and remove unrelated changes.

  • Fixes potential crash in CalendarService.ts when optional guest emails are undefined.
  • Removes unrelated ui-avatars domain from csp.ts.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A (Documentation change not required)
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Create an event type with optional guests.
  2. Ensure no runtime errors occur during event creation/update, even if guest emails are malformed.
  3. Verify that the application builds correctly with the CSP changes.

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project
  • I have checked if my changes generate no new warnings

husniabad and others added 5 commits September 21, 2025 20:19
Adds a setting to event types to automatically invite selected team members as optional attendees to meetings. This does not check their availability. Closes CAL-5091
Copilot AI review requested due to automatic review settings December 14, 2025 14:08
@prithamnandavaram prithamnandavaram requested a review from a team as a code owner December 14, 2025 14:08
@prithamnandavaram prithamnandavaram requested a review from a team December 14, 2025 14:08
@CLAassistant
Copy link

CLAassistant commented Dec 14, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ husniabad
✅ prithamnandavaram
❌ nandavarampritham
You have signed the CLA already but the status is still pending? Let us recheck it.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Dec 14, 2025
@github-actions github-actions bot added the ❗️ migrations contains migration files label Dec 14, 2025
@vercel
Copy link

vercel bot commented Dec 14, 2025

@nandavarampritham is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Contributor

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Pr 22651". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses code review feedback from PR #22651 by adding a feature to designate team members as optional guests for event types, while also fixing potential runtime errors and removing unrelated CSP changes.

  • Adds database schema and migration for optional guest team members
  • Implements validation logic to prevent duplicate optional guests and ensure proper team membership
  • Updates calendar service integrations to properly handle optional attendees

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/prisma/schema.prisma Adds many-to-many relation between EventType and User for optional guest team members
packages/prisma/migrations/20250716153028_add_team_member_as_optional_guest/migration.sql Creates join table for optional guest team members relation
packages/types/Calendar.d.ts Adds optionalGuestTeamMembers field to CalendarEvent interface
packages/trpc/server/routers/viewer/eventTypes/types.ts Adds validation schema for optionalGuestTeamMembers input
packages/trpc/server/routers/viewer/eventTypes/heavy/update.handler.ts Implements validation logic to check duplicates and team membership for optional guests
packages/lib/server/repository/eventTypeRepository.ts Includes optionalGuestTeamMembers in event type queries
packages/features/eventtypes/lib/types.ts Adds optionalGuestTeamMembers to FormValues type
packages/features/eventtypes/lib/defaultEvents.ts Initializes optionalGuestTeamMembers as empty array
packages/features/eventtypes/components/tabs/advanced/OptionalTeamGuestSetting.tsx New component for managing optional guest team members in event type settings
packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx Integrates OptionalTeamGuestSetting component
packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts Includes optionalGuestTeamMembers in booking query
packages/features/bookings/lib/handleNewBooking.ts Passes optional guest team members to calendar event builder
packages/features/CalendarEventBuilder.ts Adds method to set optional guest team members on calendar events
packages/platform/atoms/event-types/hooks/useEventTypeForm.ts Initializes optionalGuestTeamMembers in form defaults
packages/app-store/zohocalendar/lib/CalendarService.ts Updates attendee handling to mark optional guests with attendance code
packages/app-store/larkcalendar/lib/CalendarService.ts Filters optional guests from required attendees and adds them as optional
packages/app-store/googlecalendar/lib/CalendarService.ts Filters optional guests from required attendees and adds them with optional flag
packages/app-store/feishucalendar/lib/CalendarService.ts Prevents duplicate attendees and properly marks optional guests
packages/app-store/exchangecalendar/lib/CalendarService.ts Adds optional guests to OptionalAttendees instead of RequiredAttendees
packages/app-store/exchange2013calendar/lib/CalendarService.ts Adds optional guests to OptionalAttendees and clears attendees on update
packages/app-store/exchange2016calendar/lib/CalendarService.ts Properly handles optional guests with null-safe email checking
packages/app-store/googlecalendar/lib/tests/CalendarService.test.ts Adjusts test expectations to allow timezone handling differences
apps/web/public/static/locales/en/common.json Adds localization strings for optional guest feature
apps/web/lib/csp.ts Removes ui-avatars domain from CSP img-src

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// 1. Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.

// Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.

// 1. Create a Set of optional guest emails for easy lookup
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.
appointment.Body = new MessageBody(event.description || "");
// Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.
appointment.OptionalAttendees.Clear();

const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.
appointment.Body = new MessageBody(event.description || ""); // you can not use any special character or escape the content
// Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.
appointment.OptionalAttendees.Clear();

const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The code calls .toLowerCase() on guest.email without optional chaining. While the type definition specifies email as a required string, defensive programming is needed here. If the email is undefined or null at runtime, this will throw an error. Use optional chaining and filter out falsy values like in ZohoCalendar (line 487): guest.email?.toLowerCase() followed by .filter(Boolean).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.map((guest) => guest.email?.toLowerCase()).filter(Boolean) ?? []

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 24 files

Prompt for AI agents (all 4 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/app-store/googlecalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/googlecalendar/lib/CalendarService.ts:113">
P1: Missing null check before `toLowerCase()`. If `guest.email` is undefined (the scenario this PR claims to fix), this line will throw a runtime error. Consider filtering out guests without emails first.</violation>
</file>

<file name="packages/app-store/zohocalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/zohocalendar/lib/CalendarService.ts:506">
P1: Step 4 adds optional guests without filtering out members with undefined emails, unlike steps 1 and 3 which properly handle this case. This could result in attendees with `email: undefined` being sent to the Zoho API.</violation>
</file>

<file name="packages/app-store/exchange2016calendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchange2016calendar/lib/CalendarService.ts:98">
P1: Missing null check for `member.email` before adding to OptionalAttendees. The PR claims to fix crashes from undefined emails, but this code path still directly accesses `member.email` without validation. Consider applying the same filter used for team members.</violation>
</file>

<file name="packages/app-store/feishucalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/feishucalendar/lib/CalendarService.ts:421">
P1: Potential runtime error: `guest.email.toLowerCase()` will throw if `guest.email` is undefined or null. Add a filter to remove invalid emails before mapping, consistent with the defensive checks in `addUniqueAttendee`.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR


// Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 14, 2025

Choose a reason for hiding this comment

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

P1: Missing null check before toLowerCase(). If guest.email is undefined (the scenario this PR claims to fix), this line will throw a runtime error. Consider filtering out guests without emails first.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/googlecalendar/lib/CalendarService.ts, line 113:

<comment>Missing null check before `toLowerCase()`. If `guest.email` is undefined (the scenario this PR claims to fix), this line will throw a runtime error. Consider filtering out guests without emails first.</comment>

<file context>
@@ -102,18 +102,25 @@ export default class GoogleCalendarService implements Calendar {
 
+    // Create a set of optional guest emails for easy lookup.
+    const optionalGuestEmails = new Set(
+      event.optionalGuestTeamMembers?.map((guest) =&gt; guest.email.toLowerCase()) ?? []
+    );
+
</file context>
Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.filter((guest) => guest.email).map((guest) => guest.email.toLowerCase()) ?? []
Fix with Cubic

Comment on lines 506 to 511
if (event.optionalGuestTeamMembers) {
const optionalGuests = event.optionalGuestTeamMembers.map((member) => ({
email: member.email,
// 2 signifies an optional guest in the Zoho API
attendance: 2,
}));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 14, 2025

Choose a reason for hiding this comment

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

P1: Step 4 adds optional guests without filtering out members with undefined emails, unlike steps 1 and 3 which properly handle this case. This could result in attendees with email: undefined being sent to the Zoho API.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/zohocalendar/lib/CalendarService.ts, line 506:

<comment>Step 4 adds optional guests without filtering out members with undefined emails, unlike steps 1 and 3 which properly handle this case. This could result in attendees with `email: undefined` being sent to the Zoho API.</comment>

<file context>
@@ -480,4 +480,38 @@ export default class ZohoCalendarService implements Calendar {
+    }
+
+    // 4. Add the OPTIONAL team members with the correct attendance code.
+    if (event.optionalGuestTeamMembers) {
+      const optionalGuests = event.optionalGuestTeamMembers.map((member) =&gt; ({
+        email: member.email,
</file context>
Suggested change
if (event.optionalGuestTeamMembers) {
const optionalGuests = event.optionalGuestTeamMembers.map((member) => ({
email: member.email,
// 2 signifies an optional guest in the Zoho API
attendance: 2,
}));
if (event.optionalGuestTeamMembers) {
const optionalGuests = event.optionalGuestTeamMembers
.filter((member) => member.email)
.map((member) => ({
email: member.email,
// 2 signifies an optional guest in the Zoho API
attendance: 2,
}));

✅ Addressed in c450a1d

// Add optional members to the optional list
if (event.optionalGuestTeamMembers) {
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 14, 2025

Choose a reason for hiding this comment

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

P1: Missing null check for member.email before adding to OptionalAttendees. The PR claims to fix crashes from undefined emails, but this code path still directly accesses member.email without validation. Consider applying the same filter used for team members.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2016calendar/lib/CalendarService.ts, line 98:

<comment>Missing null check for `member.email` before adding to OptionalAttendees. The PR claims to fix crashes from undefined emails, but this code path still directly accesses `member.email` without validation. Consider applying the same filter used for team members.</comment>

<file context>
@@ -70,14 +70,32 @@ export default class ExchangeCalendarService implements Calendar {
+      // Add optional members to the optional list
+      if (event.optionalGuestTeamMembers) {
+        event.optionalGuestTeamMembers.forEach((member) =&gt; {
+          appointment.OptionalAttendees.Add(new Attendee(member.email));
         });
       }
</file context>

✅ Addressed in 6fb1b14


// 1. Create a Set of optional guest emails for easy lookup
const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 14, 2025

Choose a reason for hiding this comment

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

P1: Potential runtime error: guest.email.toLowerCase() will throw if guest.email is undefined or null. Add a filter to remove invalid emails before mapping, consistent with the defensive checks in addUniqueAttendee.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/feishucalendar/lib/CalendarService.ts, line 421:

<comment>Potential runtime error: `guest.email.toLowerCase()` will throw if `guest.email` is undefined or null. Add a filter to remove invalid emails before mapping, consistent with the defensive checks in `addUniqueAttendee`.</comment>

<file context>
@@ -401,27 +401,45 @@ export default class FeishuCalendarService implements Calendar {
+
+    // 1. Create a Set of optional guest emails for easy lookup
+    const optionalGuestEmails = new Set(
+      event.optionalGuestTeamMembers?.map((guest) =&gt; guest.email.toLowerCase()) ?? []
+    );
+
</file context>
Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.filter((guest) => guest.email).map((guest) => guest.email.toLowerCase()) ?? []

✅ Addressed in 6fb1b14

@prithamnandavaram prithamnandavaram changed the title Pr 22651 fix(event-types): harden email normalization and clean up CSP Dec 14, 2025
Copy link
Member

@dhairyashiil dhairyashiil left a comment

Choose a reason for hiding this comment

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

Could you please address Cubic’s comments and resolve the merge conflicts as well?

Also, about the conflicts: is this PR trying to fix the same issue as the other PR, or is it a follow-up based on the review comments there?

@dhairyashiil dhairyashiil marked this pull request as draft December 15, 2025 06:12
@prithamnandavaram
Copy link
Author

prithamnandavaram commented Dec 15, 2025

Could you please address Cubic’s comments and resolve the merge conflicts as well?

Also, about the conflicts: is this PR trying to fix the same issue as the other PR, or is it a follow-up based on the review comments there?
Thanks for the review!

This PR is trying to fix the same issue. I opened this new PR to take over the work, resolve the merge conflicts that were blocking the original one, and address the pending review feedback to get it merged.

I have now:

  1. Resolved all conflicts, including the ones in RegularBookingService and CalendarEventBuilder.

  2. Addressed Cubic's comments by removing the unrelated CSP changes.

  3. Fixed the crash by hardening the email normalization logic (checking for undefined/null before toLowerCase). I applied this same fix to Exchange2016 as well as Google, Lark, Feishu, and Exchange2013 to prevent similar runtime errors elsewhere.

Ready for another look!

@prithamnandavaram prithamnandavaram marked this pull request as ready for review December 15, 2025 06:54
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

9 issues found across 24 files

Prompt for AI agents (all 9 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/features/eventtypes/components/tabs/advanced/OptionalTeamGuestSetting.tsx">

<violation number="1" location="packages/features/eventtypes/components/tabs/advanced/OptionalTeamGuestSetting.tsx:42">
P2: Replace hardcoded string `&quot;No Email&quot;` with `t()` for proper localization.</violation>
</file>

<file name="packages/app-store/zohocalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/zohocalendar/lib/CalendarService.ts:507">
P1: Optional guests with undefined emails are not filtered out. If `member.email` is undefined, this will add an attendee with `email: undefined` to the array, potentially causing issues with the Zoho API. Consider filtering similar to step 3.</violation>
</file>

<file name="apps/web/public/static/locales/en/common.json">

<violation number="1" location="apps/web/public/static/locales/en/common.json:1685">
P3: Grammatical inconsistency: The description uses singular form (&quot;as an optional guest&quot;, &quot;an optional invite&quot;) while referring to plural &quot;team members&quot;. Consider using plural form for consistency with the title string.</violation>
</file>

<file name="packages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts">

<violation number="1" location="packages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts:294">
P2: The 1-hour tolerance for &#39;DST handling differences&#39; is questionable since all test inputs use UTC timestamps (ending with &#39;Z&#39;), which are not subject to DST. If there&#39;s actually a 1-hour discrepancy between dayjs and native Date implementations for UTC timestamps, this indicates a bug in the new implementation that should be investigated rather than masked by relaxed assertions. Consider either: (1) using strict equality if both implementations should produce identical results for UTC, or (2) documenting the actual root cause if the tolerance is genuinely needed.</violation>
</file>

<file name="packages/app-store/larkcalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/larkcalendar/lib/CalendarService.ts:442">
P1: Missing email validation. Step 1 checks `guest?.email` before use, but step 4 adds optional guests without validating that `email` exists. This could pass undefined/null to the Lark API, contradicting the PR&#39;s goal of fixing crashes when guest emails are undefined.</violation>
</file>

<file name="apps/web/lib/csp.ts">

<violation number="1" location="apps/web/lib/csp.ts:33">
P0: Removing `https://eu.ui-avatars.com/api/` from `img-src` will break placeholder avatars. The `getPlaceholderAvatar` function in `packages/lib/defaultAvatarImage.ts` actively uses this domain to generate fallback avatar images for users/teams without custom avatars. This change will cause CSP violations and broken images throughout the application.</violation>
</file>

<file name="packages/app-store/exchange2016calendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchange2016calendar/lib/CalendarService.ts:89">
P2: Inconsistent email normalization in updateEvent: add `.trim()` to match the Set-building logic.</violation>

<violation number="2" location="packages/app-store/exchange2016calendar/lib/CalendarService.ts:98">
P1: Missing null check for `member.email` in updateEvent (same issue as createEvent). Add a filter to avoid passing undefined to `new Attendee()`.</violation>
</file>

<file name="packages/app-store/exchangecalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchangecalendar/lib/CalendarService.ts:126">
P1: Missing null check for `guest.email` - this could crash if any guest has undefined email. The `createEvent` method correctly guards with `if (guest?.email)`, but `updateEvent` does not. Also missing `.trim()` for consistency.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

acc.push({
value: option.user.id.toString(),
avatar: option.user.avatarUrl || "",
label: option.user.email || "No Email",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P2: Replace hardcoded string "No Email" with t() for proper localization.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/features/eventtypes/components/tabs/advanced/OptionalTeamGuestSetting.tsx, line 42:

<comment>Replace hardcoded string `&quot;No Email&quot;` with `t()` for proper localization.</comment>

<file context>
@@ -0,0 +1,107 @@
+        acc.push({
+          value: option.user.id.toString(),
+          avatar: option.user.avatarUrl || &quot;&quot;,
+          label: option.user.email || &quot;No Email&quot;,
+          isFixed: true,
+          groupId: null,
</file context>

✅ Addressed in c450a1d


// 4. Add the OPTIONAL team members with the correct attendance code.
if (event.optionalGuestTeamMembers) {
const optionalGuests = event.optionalGuestTeamMembers.map((member) => ({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Optional guests with undefined emails are not filtered out. If member.email is undefined, this will add an attendee with email: undefined to the array, potentially causing issues with the Zoho API. Consider filtering similar to step 3.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/zohocalendar/lib/CalendarService.ts, line 507:

<comment>Optional guests with undefined emails are not filtered out. If `member.email` is undefined, this will add an attendee with `email: undefined` to the array, potentially causing issues with the Zoho API. Consider filtering similar to step 3.</comment>

<file context>
@@ -480,4 +480,38 @@ export default class ZohoCalendarService implements Calendar {
+
+    // 4. Add the OPTIONAL team members with the correct attendance code.
+    if (event.optionalGuestTeamMembers) {
+      const optionalGuests = event.optionalGuestTeamMembers.map((member) =&gt; ({
+        email: member.email,
+        // 2 signifies an optional guest in the Zoho API
</file context>
Suggested change
const optionalGuests = event.optionalGuestTeamMembers.map((member) => ({
const optionalGuests = event.optionalGuestTeamMembers
.filter((member) => member.email)
.map((member) => ({

✅ Addressed in c450a1d

"event_advanced_tab_description": "Calendar settings & more...",
"event_advanced_tab_title": "Advanced",
"optional_guest_team_members": "Add team members as optional guests",
"optional_guest_team_members_description": "Adding team members as an optional guest will always send an optional invite, but not check their availability.",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P3: Grammatical inconsistency: The description uses singular form ("as an optional guest", "an optional invite") while referring to plural "team members". Consider using plural form for consistency with the title string.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/public/static/locales/en/common.json, line 1685:

<comment>Grammatical inconsistency: The description uses singular form (&quot;as an optional guest&quot;, &quot;an optional invite&quot;) while referring to plural &quot;team members&quot;. Consider using plural form for consistency with the title string.</comment>

<file context>
@@ -1681,6 +1681,8 @@
   &quot;event_advanced_tab_description&quot;: &quot;Calendar settings &amp; more...&quot;,
   &quot;event_advanced_tab_title&quot;: &quot;Advanced&quot;,
+  &quot;optional_guest_team_members&quot;: &quot;Add team members as optional guests&quot;,
+  &quot;optional_guest_team_members_description&quot;: &quot;Adding team members as an optional guest will always send an optional invite, but not check their availability.&quot;,
   &quot;event_payments_tab_description&quot;: &quot;Set up payments for event&quot;,
   &quot;event_setup_multiple_duration_error&quot;: &quot;Event Setup: Multiple durations requires at least 1 option.&quot;,
</file context>

✅ Addressed in c450a1d

for (let i = 0; i < oldChunks.length; i++) {
expect(newChunks[i].start).toBe(oldChunks[i].start);
expect(newChunks[i].end).toBe(oldChunks[i].end);
// Allow for small timezone differences (up to 1 hour) due to DST handling differences
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P2: The 1-hour tolerance for 'DST handling differences' is questionable since all test inputs use UTC timestamps (ending with 'Z'), which are not subject to DST. If there's actually a 1-hour discrepancy between dayjs and native Date implementations for UTC timestamps, this indicates a bug in the new implementation that should be investigated rather than masked by relaxed assertions. Consider either: (1) using strict equality if both implementations should produce identical results for UTC, or (2) documenting the actual root cause if the tolerance is genuinely needed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts, line 294:

<comment>The 1-hour tolerance for &#39;DST handling differences&#39; is questionable since all test inputs use UTC timestamps (ending with &#39;Z&#39;), which are not subject to DST. If there&#39;s actually a 1-hour discrepancy between dayjs and native Date implementations for UTC timestamps, this indicates a bug in the new implementation that should be investigated rather than masked by relaxed assertions. Consider either: (1) using strict equality if both implementations should produce identical results for UTC, or (2) documenting the actual root cause if the tolerance is genuinely needed.</comment>

<file context>
@@ -287,15 +287,23 @@ describe(&quot;Date Optimization Benchmarks&quot;, () =&gt; {
       for (let i = 0; i &lt; oldChunks.length; i++) {
-        expect(newChunks[i].start).toBe(oldChunks[i].start);
-        expect(newChunks[i].end).toBe(oldChunks[i].end);
+        // Allow for small timezone differences (up to 1 hour) due to DST handling differences
+        const oldStart = new Date(oldChunks[i].start).getTime();
+        const newStart = new Date(newChunks[i].start).getTime();
</file context>

✅ Addressed in c450a1d


// 4. Add the OPTIONAL team members.
if (event.optionalGuestTeamMembers) {
event.optionalGuestTeamMembers.forEach(({ email }) => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Missing email validation. Step 1 checks guest?.email before use, but step 4 adds optional guests without validating that email exists. This could pass undefined/null to the Lark API, contradicting the PR's goal of fixing crashes when guest emails are undefined.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/larkcalendar/lib/CalendarService.ts, line 442:

<comment>Missing email validation. Step 1 checks `guest?.email` before use, but step 4 adds optional guests without validating that `email` exists. This could pass undefined/null to the Lark API, contradicting the PR&#39;s goal of fixing crashes when guest emails are undefined.</comment>

<file context>
@@ -401,27 +401,53 @@ export default class LarkCalendarService implements Calendar {
 
+    // 4. Add the OPTIONAL team members.
+    if (event.optionalGuestTeamMembers) {
+      event.optionalGuestTeamMembers.forEach(({ email }) =&gt; {
+        attendeeArray.push({
+          type: &quot;third_party&quot;,
</file context>
Suggested change
event.optionalGuestTeamMembers.forEach(({ email }) => {
event.optionalGuestTeamMembers
.filter(({ email }) => email)
.forEach(({ email }) => {

✅ Addressed in c450a1d

} app.cal.com;
font-src 'self';
img-src 'self' ${WEBAPP_URL} https://img.youtube.com https://eu.ui-avatars.com/api/ data:;
img-src 'self' ${WEBAPP_URL} https://img.youtube.com data:;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P0: Removing https://eu.ui-avatars.com/api/ from img-src will break placeholder avatars. The getPlaceholderAvatar function in packages/lib/defaultAvatarImage.ts actively uses this domain to generate fallback avatar images for users/teams without custom avatars. This change will cause CSP violations and broken images throughout the application.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/lib/csp.ts, line 33:

<comment>Removing `https://eu.ui-avatars.com/api/` from `img-src` will break placeholder avatars. The `getPlaceholderAvatar` function in `packages/lib/defaultAvatarImage.ts` actively uses this domain to generate fallback avatar images for users/teams without custom avatars. This change will cause CSP violations and broken images throughout the application.</comment>

<file context>
@@ -30,7 +30,7 @@ function getCspPolicy(nonce: string) {
     } app.cal.com;
 	  font-src &#39;self&#39;;
-	  img-src &#39;self&#39; ${WEBAPP_URL} https://img.youtube.com https://eu.ui-avatars.com/api/ data:;
+	  img-src &#39;self&#39; ${WEBAPP_URL} https://img.youtube.com data:;
     connect-src &#39;self&#39;
 	`;
</file context>
Suggested change
img-src 'self' ${WEBAPP_URL} https://img.youtube.com data:;
img-src 'self' ${WEBAPP_URL} https://img.youtube.com https://eu.ui-avatars.com/api/ data:;

✅ Addressed in c450a1d

event.team.members.forEach((member) => {
appointment.RequiredAttendees.Add(new Attendee(member.email));
event.team.members
.filter((member) => member.email && !optionalGuestEmails.has(member.email.toLowerCase()))
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P2: Inconsistent email normalization in updateEvent: add .trim() to match the Set-building logic.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2016calendar/lib/CalendarService.ts, line 89:

<comment>Inconsistent email normalization in updateEvent: add `.trim()` to match the Set-building logic.</comment>

<file context>
@@ -70,14 +70,32 @@ export default class ExchangeCalendarService implements Calendar {
-        event.team.members.forEach((member) =&gt; {
-          appointment.RequiredAttendees.Add(new Attendee(member.email));
+        event.team.members
+          .filter((member) =&gt; member.email &amp;&amp; !optionalGuestEmails.has(member.email.toLowerCase()))
+          .forEach((member) =&gt; {
+            appointment.RequiredAttendees.Add(new Attendee(member.email));
</file context>
Suggested change
.filter((member) => member.email && !optionalGuestEmails.has(member.email.toLowerCase()))
.filter((member) => member.email && !optionalGuestEmails.has(member.email.trim().toLowerCase()))
Fix with Cubic

// Add optional members to the optional list
if (event.optionalGuestTeamMembers) {
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Missing null check for member.email in updateEvent (same issue as createEvent). Add a filter to avoid passing undefined to new Attendee().

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2016calendar/lib/CalendarService.ts, line 98:

<comment>Missing null check for `member.email` in updateEvent (same issue as createEvent). Add a filter to avoid passing undefined to `new Attendee()`.</comment>

<file context>
@@ -70,14 +70,32 @@ export default class ExchangeCalendarService implements Calendar {
+      // Add optional members to the optional list
+      if (event.optionalGuestTeamMembers) {
+        event.optionalGuestTeamMembers.forEach((member) =&gt; {
+          appointment.OptionalAttendees.Add(new Attendee(member.email));
         });
       }
</file context>

✅ Addressed in 6fb1b14

appointment.OptionalAttendees.Clear();

const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Missing null check for guest.email - this could crash if any guest has undefined email. The createEvent method correctly guards with if (guest?.email), but updateEvent does not. Also missing .trim() for consistency.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchangecalendar/lib/CalendarService.ts, line 126:

<comment>Missing null check for `guest.email` - this could crash if any guest has undefined email. The `createEvent` method correctly guards with `if (guest?.email)`, but `updateEvent` does not. Also missing `.trim()` for consistency.</comment>

<file context>
@@ -96,12 +117,32 @@ export default class ExchangeCalendarService implements Calendar {
+    appointment.OptionalAttendees.Clear();
+
+    const optionalGuestEmails = new Set(
+      event.optionalGuestTeamMembers?.map((guest) =&gt; guest.email.toLowerCase()) ?? []
+    );
+
</file context>
Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers?.filter((guest) => guest?.email).map((guest) => guest.email.trim().toLowerCase()) ?? []

✅ Addressed in c450a1d

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 14 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 156 to 158
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
});
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Missing email validation: when adding optional members to the optional attendee list, there's no check to ensure 'member.email' exists before creating a new Attendee. This could cause a runtime error if an optional guest has a null or undefined email. Add a conditional check similar to line 147 in the updateEvent method.

Suggested change
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
});
event.optionalGuestTeamMembers
.filter((member) => member.email)
.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
});

Copilot uses AI. Check for mistakes.
Comment on lines 88 to 89
event.optionalGuestTeamMembers.forEach((member: { email: string }) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Missing email validation: the code iterates over optionalGuestTeamMembers without checking if 'member.email' exists before creating a new Attendee. According to the CalendarEvent type definition, the email field can be 'string | null', so this could cause a runtime error. Add a conditional check to filter out null/undefined emails.

Suggested change
event.optionalGuestTeamMembers.forEach((member: { email: string }) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
event.optionalGuestTeamMembers.forEach((member: { email: string | null }) => {
if (member.email) {
appointment.OptionalAttendees.Add(new Attendee(member.email));
}

Copilot uses AI. Check for mistakes.
Comment on lines 97 to 99
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
});
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Missing email validation: when adding optional members to the optional attendee list, there's no check to ensure 'member.email' exists before creating a new Attendee. This could cause a runtime error if an optional guest has a null or undefined email. Add a conditional check similar to the pattern used in the filter at line 89.

Suggested change
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
});
event.optionalGuestTeamMembers
.filter((member) => member.email)
.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
});

Copilot uses AI. Check for mistakes.
Comment on lines +406 to +407
// 1. Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set<string>();
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Duplicate comment: the comment "Create a set of optional guest emails for easy lookup." appears twice on consecutive lines. Remove the duplicate on line 406.

Suggested change
// 1. Create a set of optional guest emails for easy lookup.
const optionalGuestEmails = new Set<string>();
const optionalGuestEmails = new Set<string>();

Copilot uses AI. Check for mistakes.
};

// 1. Create a Set of optional guest emails for easy lookup
// 1. Create a Set of optional guest emails for easy lookup
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Duplicate comment: the comment "Create a set of optional guest emails for easy lookup." appears twice on consecutive lines. Remove the duplicate on line 420.

Suggested change
// 1. Create a Set of optional guest emails for easy lookup

Copilot uses AI. Check for mistakes.
appointment.OptionalAttendees.Clear();

const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Potential runtime error: when creating the Set of optional guest emails, the code calls 'guest.email.toLowerCase()' without first checking if 'guest.email' exists. If any guest object has a null or undefined email, this will throw an error. The code should filter out null/undefined emails before calling toLowerCase(), similar to the pattern used in the createEvent method (lines 76-78).

Suggested change
event.optionalGuestTeamMembers?.map((guest) => guest.email.toLowerCase()) ?? []
event.optionalGuestTeamMembers
?.filter((guest) => guest.email)
.map((guest) => guest.email.toLowerCase()) ?? []

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +148
if (member.email) {
appointment.OptionalAttendees.Add(new Attendee(member.email));
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Missing email validation: when adding optional members to the optional attendee list, there's no check to ensure 'member.email' exists before creating a new Attendee. This could cause a runtime error if an optional guest has a null or undefined email.

Suggested change
if (member.email) {
appointment.OptionalAttendees.Add(new Attendee(member.email));
if (
typeof member.email === "string" &&
member.email.trim().length > 0
) {
appointment.OptionalAttendees.Add(new Attendee(member.email.trim()));

Copilot uses AI. Check for mistakes.
];

// Create a set of optional guest emails for easy lookup.
// Create a set of optional guest emails for easy lookup.
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Duplicate comment: the comment "Create a set of optional guest emails for easy lookup." appears twice on consecutive lines. Remove the duplicate on line 102.

Suggested change
// Create a set of optional guest emails for easy lookup.

Copilot uses AI. Check for mistakes.
appointment.Location = event.location || "Location not defined!";
appointment.Body = new MessageBody(event.description || ""); // you can not use any special character or escape the content
// Create a set of optional guest emails for easy lookup.
// Create a set of optional guest emails for easy lookup.
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Duplicate comment: the comment "Create a set of optional guest emails for easy lookup." appears twice on consecutive lines. Remove the duplicate on line 73.

Suggested change
// Create a set of optional guest emails for easy lookup.

Copilot uses AI. Check for mistakes.
*/
export class RegularBookingService implements IBookingService {
constructor(private readonly deps: IBookingServiceDependencies) {}
constructor(private readonly deps: IBookingServiceDependencies) { }
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

Unnecessary whitespace: the constructor has extra spacing inside the curly braces. The formatting should be consistent with the rest of the codebase, using either no space or proper spacing.

Suggested change
constructor(private readonly deps: IBookingServiceDependencies) { }
constructor(private readonly deps: IBookingServiceDependencies) {}

Copilot uses AI. Check for mistakes.
@prithamnandavaram
Copy link
Author

@cubic-dev-ai review

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Dec 15, 2025

@cubic-dev-ai review

@prithamnandavaram I have started the AI code review. It will take a few minutes to complete.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 24 files

Prompt for AI agents (all 3 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/app-store/exchange2013calendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchange2013calendar/lib/CalendarService.ts:97">
P1: Missing email validation when adding optional attendees. The code checks for `guest?.email` when building the Set, but doesn&#39;t verify email exists when adding to `OptionalAttendees`. Filter members with valid emails to prevent potential runtime errors.</violation>

<violation number="2" location="packages/app-store/exchange2013calendar/lib/CalendarService.ts:138">
P2: Inconsistent email normalization between `createEvent` and `updateEvent`. The `createEvent` method uses `.trim().toLowerCase()` when building `optionalGuestEmails`, but `updateEvent` only uses `.toLowerCase()`. Add `.trim()` for consistent behavior.</violation>
</file>

<file name="packages/app-store/exchange2016calendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchange2016calendar/lib/CalendarService.ts:96">
P1: Missing `.filter((member) =&gt; member.email)` in `updateEvent` that exists in `createEvent`. This could cause a runtime error if any optional guest has an undefined email, which the PR description explicitly aims to prevent.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

const optionalGuestEmails = new Set(
event.optionalGuestTeamMembers
?.filter((guest) => guest?.email)
.map((guest) => guest.email.toLowerCase()) ?? []
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P2: Inconsistent email normalization between createEvent and updateEvent. The createEvent method uses .trim().toLowerCase() when building optionalGuestEmails, but updateEvent only uses .toLowerCase(). Add .trim() for consistent behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2013calendar/lib/CalendarService.ts, line 138:

<comment>Inconsistent email normalization between `createEvent` and `updateEvent`. The `createEvent` method uses `.trim().toLowerCase()` when building `optionalGuestEmails`, but `updateEvent` only uses `.toLowerCase()`. Add `.trim()` for consistent behavior.</comment>

<file context>
@@ -109,14 +127,38 @@ export default class ExchangeCalendarService implements Calendar {
+      const optionalGuestEmails = new Set(
+        event.optionalGuestTeamMembers
+          ?.filter((guest) =&gt; guest?.email)
+          .map((guest) =&gt; guest.email.toLowerCase()) ?? []
+      );
+
</file context>
Suggested change
.map((guest) => guest.email.toLowerCase()) ?? []
.map((guest) => guest.email.trim().toLowerCase()) ?? []

✅ Addressed in 371def0

// Add optional members to the optional list
if (event.optionalGuestTeamMembers) {
event.optionalGuestTeamMembers.forEach((member) => {
appointment.OptionalAttendees.Add(new Attendee(member.email));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Missing email validation when adding optional attendees. The code checks for guest?.email when building the Set, but doesn't verify email exists when adding to OptionalAttendees. Filter members with valid emails to prevent potential runtime errors.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2013calendar/lib/CalendarService.ts, line 97:

<comment>Missing email validation when adding optional attendees. The code checks for `guest?.email` when building the Set, but doesn&#39;t verify email exists when adding to `OptionalAttendees`. Filter members with valid emails to prevent potential runtime errors.</comment>

<file context>
@@ -69,14 +69,32 @@ export default class ExchangeCalendarService implements Calendar {
+      // Add optional members to the optional list
+      if (event.optionalGuestTeamMembers) {
+        event.optionalGuestTeamMembers.forEach((member) =&gt; {
+          appointment.OptionalAttendees.Add(new Attendee(member.email));
         });
       }
</file context>

✅ Addressed in 371def0

}

// Add optional members to the optional list
if (event.optionalGuestTeamMembers) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Missing .filter((member) => member.email) in updateEvent that exists in createEvent. This could cause a runtime error if any optional guest has an undefined email, which the PR description explicitly aims to prevent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2016calendar/lib/CalendarService.ts, line 96:

<comment>Missing `.filter((member) =&gt; member.email)` in `updateEvent` that exists in `createEvent`. This could cause a runtime error if any optional guest has an undefined email, which the PR description explicitly aims to prevent.</comment>

<file context>
@@ -70,15 +70,35 @@ export default class ExchangeCalendarService implements Calendar {
+      }
+
+      // Add optional members to the optional list
+      if (event.optionalGuestTeamMembers) {
+        event.optionalGuestTeamMembers
+          .filter((member) =&gt; member.email)
</file context>

✅ Addressed in 371def0

@prithamnandavaram
Copy link
Author

@cubic-dev-ai review

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Dec 15, 2025

@cubic-dev-ai review

@prithamnandavaram I have started the AI code review. It will take a few minutes to complete.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 24 files

Prompt for AI agents (all 4 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/app-store/exchangecalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchangecalendar/lib/CalendarService.ts:79">
P2: Inconsistent email normalization: the Set lookup is missing `.trim()`. The Set is built with `guest.email.trim().toLowerCase()` but the filter uses `member.email.toLowerCase()` without `.trim()`. This could cause duplicate attendees if emails have whitespace. The `updateEvent` method correctly uses `.trim().toLowerCase()` for both operations.</violation>
</file>

<file name="packages/app-store/exchange2013calendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/exchange2013calendar/lib/CalendarService.ts:96">
P1: Missing null check for `member.email` in `updateEvent`. The `createEvent` method correctly checks `if (member.email)` before adding optional attendees, but this check is missing here. This could cause a runtime error if `member.email` is undefined.</violation>
</file>

<file name="packages/app-store/larkcalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/larkcalendar/lib/CalendarService.ts:429">
P2: Email normalization is inconsistent. Step 1 uses `trim().toLowerCase()` but step 3 only uses `toLowerCase()`. If `member.email` has whitespace, it won&#39;t match the trimmed entry in the set.</violation>

<violation number="2" location="packages/app-store/larkcalendar/lib/CalendarService.ts:440">
P1: Destructuring `({ email })` directly can crash if any item in `optionalGuestTeamMembers` is `null` or `undefined`. Step 1 uses `guest?.email` defensively, suggesting items may be nullish. Apply the same pattern here for consistency and to prevent runtime errors.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

event.team.members.forEach((member: Person) => {
appointment.RequiredAttendees.Add(new Attendee(member.email));
event.team.members
.filter((member) => member.email && !optionalGuestEmails.has(member.email.toLowerCase()))
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P2: Inconsistent email normalization: the Set lookup is missing .trim(). The Set is built with guest.email.trim().toLowerCase() but the filter uses member.email.toLowerCase() without .trim(). This could cause duplicate attendees if emails have whitespace. The updateEvent method correctly uses .trim().toLowerCase() for both operations.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchangecalendar/lib/CalendarService.ts, line 79:

<comment>Inconsistent email normalization: the Set lookup is missing `.trim()`. The Set is built with `guest.email.trim().toLowerCase()` but the filter uses `member.email.toLowerCase()` without `.trim()`. This could cause duplicate attendees if emails have whitespace. The `updateEvent` method correctly uses `.trim().toLowerCase()` for both operations.</comment>

<file context>
@@ -60,12 +60,34 @@ export default class ExchangeCalendarService implements Calendar {
-      event.team.members.forEach((member: Person) =&gt; {
-        appointment.RequiredAttendees.Add(new Attendee(member.email));
+      event.team.members
+        .filter((member) =&gt; member.email &amp;&amp; !optionalGuestEmails.has(member.email.toLowerCase()))
+        .forEach((member: Person) =&gt; {
+          appointment.RequiredAttendees.Add(new Attendee(member.email));
</file context>
Suggested change
.filter((member) => member.email && !optionalGuestEmails.has(member.email.toLowerCase()))
.filter((member) => member.email && !optionalGuestEmails.has(member.email.trim().toLowerCase()))

✅ Addressed in 6ac0c41

Comment on lines +96 to +98
event.optionalGuestTeamMembers.forEach((member) => {
if (member.email) {
appointment.OptionalAttendees.Add(new Attendee(member.email));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Missing null check for member.email in updateEvent. The createEvent method correctly checks if (member.email) before adding optional attendees, but this check is missing here. This could cause a runtime error if member.email is undefined.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/exchange2013calendar/lib/CalendarService.ts, line 96:

<comment>Missing null check for `member.email` in `updateEvent`. The `createEvent` method correctly checks `if (member.email)` before adding optional attendees, but this check is missing here. This could cause a runtime error if `member.email` is undefined.</comment>

<file context>
@@ -69,14 +69,34 @@ export default class ExchangeCalendarService implements Calendar {
+
+      // Add optional members to the optional list
+      if (event.optionalGuestTeamMembers) {
+        event.optionalGuestTeamMembers.forEach((member) =&gt; {
+          if (member.email) {
+            appointment.OptionalAttendees.Add(new Attendee(member.email));
</file context>
Suggested change
event.optionalGuestTeamMembers.forEach((member) => {
if (member.email) {
appointment.OptionalAttendees.Add(new Attendee(member.email));
event.optionalGuestTeamMembers.forEach((member) => {
if (member.email) {
appointment.OptionalAttendees.Add(new Attendee(member.email));
}
});

✅ Addressed in 6ac0c41

if (
member.email &&
member.email !== this.credential.user?.email &&
!optionalGuestEmails.has(member.email.toLowerCase())
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P2: Email normalization is inconsistent. Step 1 uses trim().toLowerCase() but step 3 only uses toLowerCase(). If member.email has whitespace, it won't match the trimmed entry in the set.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/larkcalendar/lib/CalendarService.ts, line 429:

<comment>Email normalization is inconsistent. Step 1 uses `trim().toLowerCase()` but step 3 only uses `toLowerCase()`. If `member.email` has whitespace, it won&#39;t match the trimmed entry in the set.</comment>

<file context>
@@ -401,27 +401,54 @@ export default class LarkCalendarService implements Calendar {
+      if (
+        member.email &amp;&amp;
+        member.email !== this.credential.user?.email &amp;&amp;
+        !optionalGuestEmails.has(member.email.toLowerCase())
+      ) {
+        attendeeArray.push({
</file context>
Suggested change
!optionalGuestEmails.has(member.email.toLowerCase())
!optionalGuestEmails.has(member.email.trim().toLowerCase())

✅ Addressed in 6ac0c41

});

// 4. Add the OPTIONAL team members.
if (event.optionalGuestTeamMembers) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 15, 2025

Choose a reason for hiding this comment

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

P1: Destructuring ({ email }) directly can crash if any item in optionalGuestTeamMembers is null or undefined. Step 1 uses guest?.email defensively, suggesting items may be nullish. Apply the same pattern here for consistency and to prevent runtime errors.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/larkcalendar/lib/CalendarService.ts, line 440:

<comment>Destructuring `({ email })` directly can crash if any item in `optionalGuestTeamMembers` is `null` or `undefined`. Step 1 uses `guest?.email` defensively, suggesting items may be nullish. Apply the same pattern here for consistency and to prevent runtime errors.</comment>

<file context>
@@ -401,27 +401,54 @@ export default class LarkCalendarService implements Calendar {
     });
 
+    // 4. Add the OPTIONAL team members.
+    if (event.optionalGuestTeamMembers) {
+      event.optionalGuestTeamMembers.forEach(({ email }) =&gt; {
+        if (email) {
</file context>

✅ Addressed in 6ac0c41

@prithamnandavaram
Copy link
Author

@cubic-dev-ai review

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Dec 15, 2025

@cubic-dev-ai review

@prithamnandavaram I have started the AI code review. It will take a few minutes to complete.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 24 files

@prithamnandavaram
Copy link
Author

Ready for review! cc @alannnc @zomars

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

});
}


Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

There are two consecutive blank lines here which is inconsistent with the rest of the codebase formatting. This should be reduced to a single blank line.

Suggested change

Copilot uses AI. Check for mistakes.
@prithamnandavaram
Copy link
Author

Ready for review! cc @dhairyashiil

@github-actions
Copy link
Contributor

This PR has been marked as stale due to inactivity. If you're still working on it or need any help, please let us know or update the PR to keep it active.

@github-actions github-actions bot added Stale and removed Stale labels Dec 24, 2025
@github-actions
Copy link
Contributor

This PR has been marked as stale due to inactivity. If you're still working on it or need any help, please let us know or update the PR to keep it active.

@github-actions
Copy link
Contributor

Devin AI is resolving merge conflicts

This PR has merge conflicts with the main branch. A Devin session has been created to automatically resolve them.

View Devin Session

Devin will:

  1. Merge the latest main into this branch
  2. Resolve any conflicts intelligently
  3. Run lint/type checks to ensure validity
  4. Push the resolved changes

If you prefer to resolve conflicts manually, you can close the Devin session and handle it yourself.

@calcom-bot calcom-bot requested a review from a team as a code owner January 12, 2026 14:12
@github-actions github-actions bot removed the Stale label Jan 13, 2026
@devin-ai-integration devin-ai-integration bot added the Medium priority Created by Linear-GitHub Sync label Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Created by Linear-GitHub Sync Medium priority Created by Linear-GitHub Sync ❗️ migrations contains migration files size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants