-
Notifications
You must be signed in to change notification settings - Fork 0
fix: handle collective multiple host on destinationCalendar #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: eval-pr-4-target-1759088940839
Are you sure you want to change the base?
fix: handle collective multiple host on destinationCalendar #2
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7 issues found across 22 files
Prompt for AI agents (all 7 issues)
Understand the root cause of the following 7 issues and fix them.
<file name="apps/web/pages/api/cron/bookingReminder.ts">
<violation number="1" location="apps/web/pages/api/cron/bookingReminder.ts:107">
For collective events with multiple hosts, this logic only considers the primary destination calendar (`booking.destinationCalendar`). It fails to load all calendar events from the booking's references, leading to incomplete data for reminders. The `CalendarEvent` object is constructed with only a single host's calendar, which is incorrect for multi-host bookings.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: Insufficient in-file evidence to confirm the multi-host calendar requirement. The claim depends on architecture outside the visible context; to minimize false positives, filter this.</violation>
</file>
<file name="packages/trpc/server/routers/viewer/organizations/create.handler.ts">
<violation number="1" location="packages/trpc/server/routers/viewer/organizations/create.handler.ts:151">
The new ternary reverses the slug assignment logic: when team billing is disabled we now omit the slug, preventing organization creation in the default configuration. Please restore the previous condition so slugs are still stored when team billing is off.</violation>
</file>
<file name="packages/features/bookings/lib/handleCancelBooking.ts">
<violation number="1" location="packages/features/bookings/lib/handleCancelBooking.ts:423">
Broken access control: non-owners can cancel future bookings; the new loop deletes events across all calendar integrations, amplifying impact.</violation>
</file>
<file name="packages/app-store/office365calendar/lib/CalendarService.ts">
<violation number="1" location="packages/app-store/office365calendar/lib/CalendarService.ts:73">
The new destructuring assumes `event.destinationCalendar` is always an array; when it is still a single object (common for older bookings), this throws at runtime because the object is not iterable. Please keep compatibility with object values.</violation>
</file>
<file name="packages/features/ee/payments/api/paypal-webhook.ts">
<violation number="1" location="packages/features/ee/payments/api/paypal-webhook.ts:152">
Passing [] for destinationCalendar can cause EventManager.create to read `.integration` of undefined, crashing when location is Google Meet.</violation>
</file>
<file name="packages/app-store/googlecalendar/lib/CalendarService.ts">
<violation number="1" location="packages/app-store/googlecalendar/lib/CalendarService.ts:256">
When `externalCalendarId` is null, this fallback never finds a match, so `calendarId` becomes undefined and the subsequent `events.update` call fails. Please restore a real fallback (e.g., the host’s calendar) instead of matching against the null input.</violation>
</file>
<file name="packages/core/EventManager.ts">
<violation number="1" location="packages/core/EventManager.ts:119">
Runtime TypeError: unsafe access of integration on possibly undefined destination calendar
*DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.*</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
|
|
||
| const attendeesList = await Promise.all(attendeesListPromises); | ||
|
|
||
| const selectedDestinationCalendar = booking.destinationCalendar || user.destinationCalendar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For collective events with multiple hosts, this logic only considers the primary destination calendar (booking.destinationCalendar). It fails to load all calendar events from the booking's references, leading to incomplete data for reminders. The CalendarEvent object is constructed with only a single host's calendar, which is incorrect for multi-host bookings.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• GPT-5: Insufficient in-file evidence to confirm the multi-host calendar requirement. The claim depends on architecture outside the visible context; to minimize false positives, filter this.
Prompt for AI agents
Address the following comment on apps/web/pages/api/cron/bookingReminder.ts at line 107:
<comment>For collective events with multiple hosts, this logic only considers the primary destination calendar (`booking.destinationCalendar`). It fails to load all calendar events from the booking's references, leading to incomplete data for reminders. The `CalendarEvent` object is constructed with only a single host's calendar, which is incorrect for multi-host bookings.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: Insufficient in-file evidence to confirm the multi-host calendar requirement. The claim depends on architecture outside the visible context; to minimize false positives, filter this.</comment>
<file context>
@@ -104,7 +104,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const attendeesList = await Promise.all(attendeesListPromises);
-
+ const selectedDestinationCalendar = booking.destinationCalendar || user.destinationCalendar;
const evt: CalendarEvent = {
type: booking.title,
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: System Design Agent
| create: { | ||
| name, | ||
| ...(!IS_TEAM_BILLING_ENABLED && { slug }), | ||
| ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new ternary reverses the slug assignment logic: when team billing is disabled we now omit the slug, preventing organization creation in the default configuration. Please restore the previous condition so slugs are still stored when team billing is off.
Prompt for AI agents
Address the following comment on packages/trpc/server/routers/viewer/organizations/create.handler.ts at line 151:
<comment>The new ternary reverses the slug assignment logic: when team billing is disabled we now omit the slug, preventing organization creation in the default configuration. Please restore the previous condition so slugs are still stored when team billing is off.</comment>
<file context>
@@ -148,9 +148,9 @@ export const createHandler = async ({ input, ctx }: CreateOptions) => {
create: {
name,
- ...(!IS_TEAM_BILLING_ENABLED && { slug }),
+ ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}),
metadata: {
- ...(IS_TEAM_BILLING_ENABLED && { requestedSlug: slug }),
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: General AI Review Agent
| ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}), | |
| ...(!IS_TEAM_BILLING_ENABLED ? { slug } : {}), |
| const deletedEvent = await calendar?.deleteEvent(uid, evt, externalCalendarId); | ||
| apiDeletes.push(deletedEvent); | ||
| if (bookingCalendarReference.length > 0) { | ||
| for (const reference of bookingCalendarReference) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken access control: non-owners can cancel future bookings; the new loop deletes events across all calendar integrations, amplifying impact.
Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleCancelBooking.ts at line 423:
<comment>Broken access control: non-owners can cancel future bookings; the new loop deletes events across all calendar integrations, amplifying impact.</comment>
<file context>
@@ -411,58 +415,71 @@ async function handler(req: CustomRequest) {
- const deletedEvent = await calendar?.deleteEvent(uid, evt, externalCalendarId);
- apiDeletes.push(deletedEvent);
+ if (bookingCalendarReference.length > 0) {
+ for (const reference of bookingCalendarReference) {
+ const { credentialId, uid, externalCalendarId } = reference;
+ // If the booking calendar reference contains a credentialId
</file context>
[internal] Confidence score: 8/10
[internal] Posted by: Security Vulnerabilities Agent
| } | ||
|
|
||
| async createEvent(event: CalendarEvent): Promise<NewCalendarEventType> { | ||
| const [mainHostDestinationCalendar] = event.destinationCalendar ?? []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new destructuring assumes event.destinationCalendar is always an array; when it is still a single object (common for older bookings), this throws at runtime because the object is not iterable. Please keep compatibility with object values.
Prompt for AI agents
Address the following comment on packages/app-store/office365calendar/lib/CalendarService.ts at line 73:
<comment>The new destructuring assumes `event.destinationCalendar` is always an array; when it is still a single object (common for older bookings), this throws at runtime because the object is not iterable. Please keep compatibility with object values.</comment>
<file context>
@@ -70,9 +70,10 @@ export default class Office365CalendarService implements Calendar {
}
async createEvent(event: CalendarEvent): Promise<NewCalendarEventType> {
+ const [mainHostDestinationCalendar] = event.destinationCalendar ?? [];
try {
- const eventsUrl = event.destinationCalendar?.externalId
</file context>
[internal] Confidence score: 7/10
[internal] Posted by: General AI Review Agent
| const [mainHostDestinationCalendar] = event.destinationCalendar ?? []; | |
| const mainHostDestinationCalendar = Array.isArray(event.destinationCalendar) | |
| ? event.destinationCalendar[0] | |
| : event.destinationCalendar ?? undefined; |
| attendees: attendeesList, | ||
| uid: booking.uid, | ||
| destinationCalendar: booking.destinationCalendar || user.destinationCalendar, | ||
| destinationCalendar: booking.destinationCalendar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing [] for destinationCalendar can cause EventManager.create to read .integration of undefined, crashing when location is Google Meet.
Prompt for AI agents
Address the following comment on packages/features/ee/payments/api/paypal-webhook.ts at line 152:
<comment>Passing [] for destinationCalendar can cause EventManager.create to read `.integration` of undefined, crashing when location is Google Meet.</comment>
<file context>
@@ -149,7 +149,11 @@ export async function handlePaymentSuccess(
attendees: attendeesList,
uid: booking.uid,
- destinationCalendar: booking.destinationCalendar || user.destinationCalendar,
+ destinationCalendar: booking.destinationCalendar
+ ? [booking.destinationCalendar]
+ : user.destinationCalendar
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: Functional Bugs Agent
| const selectedCalendar = externalCalendarId | ||
| ? externalCalendarId | ||
| : event.destinationCalendar?.externalId; | ||
| : event.destinationCalendar?.find((cal) => cal.externalId === externalCalendarId)?.externalId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When externalCalendarId is null, this fallback never finds a match, so calendarId becomes undefined and the subsequent events.update call fails. Please restore a real fallback (e.g., the host’s calendar) instead of matching against the null input.
Prompt for AI agents
Address the following comment on packages/app-store/googlecalendar/lib/CalendarService.ts at line 256:
<comment>When `externalCalendarId` is null, this fallback never finds a match, so `calendarId` becomes undefined and the subsequent `events.update` call fails. Please restore a real fallback (e.g., the host’s calendar) instead of matching against the null input.</comment>
<file context>
@@ -244,7 +253,7 @@ export default class GoogleCalendarService implements Calendar {
const selectedCalendar = externalCalendarId
? externalCalendarId
- : event.destinationCalendar?.externalId;
+ : event.destinationCalendar?.find((cal) => cal.externalId === externalCalendarId)?.externalId;
calendar.events.update(
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: General AI Review Agent
| if (evt.location === MeetLocationType && evt.destinationCalendar?.integration !== "google_calendar") { | ||
| // @NOTE: destinationCalendar it's an array now so as a fallback we will only check the first one | ||
| const [mainHostDestinationCalendar] = evt.destinationCalendar ?? []; | ||
| if (evt.location === MeetLocationType && mainHostDestinationCalendar.integration !== "google_calendar") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runtime TypeError: unsafe access of integration on possibly undefined destination calendar
DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.
Prompt for AI agents
Address the following comment on packages/core/EventManager.ts at line 119:
<comment>Runtime TypeError: unsafe access of integration on possibly undefined destination calendar
*DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.*</comment>
<file context>
@@ -114,7 +114,9 @@ export default class EventManager {
- if (evt.location === MeetLocationType && evt.destinationCalendar?.integration !== "google_calendar") {
+ // @NOTE: destinationCalendar it's an array now so as a fallback we will only check the first one
+ const [mainHostDestinationCalendar] = evt.destinationCalendar ?? [];
+ if (evt.location === MeetLocationType && mainHostDestinationCalendar.integration !== "google_calendar") {
evt["location"] = "integrations:daily";
}
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: Functional Bugs Agent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
14 issues found across 22 files
Prompt for AI agents (all 14 issues)
Understand the root cause of the following 14 issues and fix them.
<file name="packages/trpc/server/routers/viewer/organizations/create.handler.ts">
<violation number="1" location="packages/trpc/server/routers/viewer/organizations/create.handler.ts:151">
This change assigns `slug` when team billing is enabled, but the original logic (and surrounding metadata) expects the slug to be reserved only when team billing is disabled. Please restore the `!IS_TEAM_BILLING_ENABLED` guard so team-billing organizations don’t wrongly claim the slug.</violation>
</file>
<file name="packages/features/bookings/lib/handleCancelBooking.ts">
<violation number="1" location="packages/features/bookings/lib/handleCancelBooking.ts:418">
Broken access control: Any authenticated user can cancel another user's future booking (and trigger external deletions/refunds).</violation>
<violation number="2" location="packages/features/bookings/lib/handleCancelBooking.ts:454">
When cancelling all remaining occurrences, we now iterate each host credential but still pull the first `_calendar` reference from every booking. With multiple hosts this will pick the wrong UID/externalCalendarId, so only one host’s event gets deleted while the others remain.</violation>
</file>
<file name="packages/core/EventManager.ts">
<violation number="1" location="packages/core/EventManager.ts:119">
Accessing `mainHostDestinationCalendar.integration` without guarding for a missing destination calendar will throw when the array is empty. Please add a safety check (e.g., optional chaining) before reading the integration.</violation>
<violation number="2" location="packages/core/EventManager.ts:344">
Broken Access Control/IDOR: Fetching and using calendar credentials by raw ID without ownership/authorization checks allows unauthorized calendar actions using another user’s credentials.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: Speculative IDOR; destination.credentialId appears server-managed and is first matched against in-memory authenticated credentials. DB fallback by ID supports multi-host scheduling; no evidence of user-controlled input here.</violation>
</file>
<file name="packages/features/bookings/lib/handleNewBooking.ts">
<violation number="1" location="packages/features/bookings/lib/handleNewBooking.ts:731">
Dynamic collective bookings need each host’s organization slug for downstream logic, but the new Prisma query omits selecting `organization`. Restore selecting the relation to avoid runtime `user.organization` access errors.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: No runtime access to user.organization or slug for dynamically loaded users. eventType.hosts already selects organization.slug; other logic references organizationId only. The omission won’t cause a runtime error in this file.</violation>
<violation number="2" location="packages/features/bookings/lib/handleNewBooking.ts:1078">
Team calendars are ignored when organizer lacks destination calendar due to optional push; COLLECTIVE bookings miss team member calendar events.</violation>
<violation number="3" location="packages/features/bookings/lib/handleNewBooking.ts:1877">
The application creates a booking record in the database by connecting it to only the first destination calendar from the list of hosts for a collective event. This breaks the multi-host calendar feature, as information about other hosts' calendars is lost upon booking creation. Subsequent operations like updates or cancellations will only be performed on the organizer's calendar, not the entire collective team's calendars.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: Based on this file, updates/reschedules rely on booking.references created per calendar by EventManager, not on booking.destinationCalendar. The single connect does not conclusively break multi-host behavior without verified schema/other handler evidence. To minimize false positives, filter.</violation>
</file>
<file name="packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts">
<violation number="1" location="packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts:241">
If `bookingToReschedule.destinationCalendar` is already a `DestinationCalendar[]`, wrapping it in another array turns the payload into a nested array, breaking multi-host event data. Return the array as-is when it is already an array.
*DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.*
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: bookingToReschedule.destinationCalendar is a single DestinationCalendar relation (not an array) per Prisma schema/types; CalendarEvent.destinationCalendar expects DestinationCalendar[]. Wrapping the single value in [] correctly shapes the payload and does not create DestinationCalendar[][]. This is consistent with other handlers and the PR intent.</violation>
</file>
<file name="packages/core/builders/CalendarEvent/builder.ts">
<violation number="1" location="packages/core/builders/CalendarEvent/builder.ts:1">
Reversed guard in buildUIDCalendarEvent causes incorrect throw and potential TypeError when users missing.</violation>
</file>
<file name="packages/app-store/googlecalendar/lib/CalendarService.ts">
<violation number="1" location="packages/app-store/googlecalendar/lib/CalendarService.ts:147">
If no destination calendar matches this credential, `selectedCalendar` stays undefined; while the insert falls back to "primary", the subsequent patch reuses the undefined value and Google rejects the request because `calendarId` is required. Please default `selectedCalendar` to a valid ID before it is reused.</violation>
<violation number="2" location="packages/app-store/googlecalendar/lib/CalendarService.ts:256">
When `externalCalendarId` is not passed we now end up with `selectedCalendar` undefined, so the Google update call is made without a calendarId and fails. Restore a real fallback (e.g. the first destination calendar) instead of searching for `externalCalendarId` again.</violation>
<violation number="3" location="packages/app-store/googlecalendar/lib/CalendarService.ts:256">
updateEvent may pass undefined calendarId; createEvent follow-up patch may pass undefined calendarId; organizer attendee email set to calendarId; and patch errors are swallowed</violation>
</file>
<file name="packages/app-store/larkcalendar/lib/CalendarService.ts">
<violation number="1" location="packages/app-store/larkcalendar/lib/CalendarService.ts:129">
The calendar services for Lark, Office365, and iCal have not been correctly updated to handle multiple destination calendars. They consistently only process the first calendar in the `destinationCalendar` array, which will cause the feature to fail for any users with these integrations. Furthermore, their `createEvent` method signatures are not updated to match the `Calendar` interface, which now requires a `credentialId`.
*DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.*</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| create: { | ||
| name, | ||
| ...(!IS_TEAM_BILLING_ENABLED && { slug }), | ||
| ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change assigns slug when team billing is enabled, but the original logic (and surrounding metadata) expects the slug to be reserved only when team billing is disabled. Please restore the !IS_TEAM_BILLING_ENABLED guard so team-billing organizations don’t wrongly claim the slug.
Prompt for AI agents
Address the following comment on packages/trpc/server/routers/viewer/organizations/create.handler.ts at line 151:
<comment>This change assigns `slug` when team billing is enabled, but the original logic (and surrounding metadata) expects the slug to be reserved only when team billing is disabled. Please restore the `!IS_TEAM_BILLING_ENABLED` guard so team-billing organizations don’t wrongly claim the slug.</comment>
<file context>
@@ -148,9 +148,9 @@ export const createHandler = async ({ input, ctx }: CreateOptions) => {
create: {
name,
- ...(!IS_TEAM_BILLING_ENABLED && { slug }),
+ ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}),
metadata: {
- ...(IS_TEAM_BILLING_ENABLED && { requestedSlug: slug }),
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: General AI Review Agent
| ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}), | |
| ...(!IS_TEAM_BILLING_ENABLED ? { slug } : {}), |
| .map(async (credential) => { | ||
| const calendar = await getCalendar(credential); | ||
| for (const updBooking of updatedBookings) { | ||
| const bookingRef = updBooking.references.find((ref) => ref.type.includes("_calendar")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When cancelling all remaining occurrences, we now iterate each host credential but still pull the first _calendar reference from every booking. With multiple hosts this will pick the wrong UID/externalCalendarId, so only one host’s event gets deleted while the others remain.
Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleCancelBooking.ts at line 454:
<comment>When cancelling all remaining occurrences, we now iterate each host credential but still pull the first `_calendar` reference from every booking. With multiple hosts this will pick the wrong UID/externalCalendarId, so only one host’s event gets deleted while the others remain.</comment>
<file context>
@@ -411,58 +415,71 @@ async function handler(req: CustomRequest) {
+ .map(async (credential) => {
+ const calendar = await getCalendar(credential);
+ for (const updBooking of updatedBookings) {
+ const bookingRef = updBooking.references.find((ref) => ref.type.includes("_calendar"));
+ if (bookingRef) {
+ const { uid, externalCalendarId } = bookingRef;
</file context>
[internal] Confidence score: 8/10
[internal] Posted by: General AI Review Agent
| if (evt.location === MeetLocationType && evt.destinationCalendar?.integration !== "google_calendar") { | ||
| // @NOTE: destinationCalendar it's an array now so as a fallback we will only check the first one | ||
| const [mainHostDestinationCalendar] = evt.destinationCalendar ?? []; | ||
| if (evt.location === MeetLocationType && mainHostDestinationCalendar.integration !== "google_calendar") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessing mainHostDestinationCalendar.integration without guarding for a missing destination calendar will throw when the array is empty. Please add a safety check (e.g., optional chaining) before reading the integration.
Prompt for AI agents
Address the following comment on packages/core/EventManager.ts at line 119:
<comment>Accessing `mainHostDestinationCalendar.integration` without guarding for a missing destination calendar will throw when the array is empty. Please add a safety check (e.g., optional chaining) before reading the integration.</comment>
<file context>
@@ -114,7 +114,9 @@ export default class EventManager {
- if (evt.location === MeetLocationType && evt.destinationCalendar?.integration !== "google_calendar") {
+ // @NOTE: destinationCalendar it's an array now so as a fallback we will only check the first one
+ const [mainHostDestinationCalendar] = evt.destinationCalendar ?? [];
+ if (evt.location === MeetLocationType && mainHostDestinationCalendar.integration !== "google_calendar") {
evt["location"] = "integrations:daily";
}
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: General AI Review Agent
| if (evt.location === MeetLocationType && mainHostDestinationCalendar.integration !== "google_calendar") { | |
| if (evt.location === MeetLocationType && mainHostDestinationCalendar?.integration !== "google_calendar") { |
| let credential = this.calendarCredentials.find((c) => c.id === destination.credentialId); | ||
| if (!credential) { | ||
| // Fetch credential from DB | ||
| const credentialFromDB = await prisma.credential.findUnique({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken Access Control/IDOR: Fetching and using calendar credentials by raw ID without ownership/authorization checks allows unauthorized calendar actions using another user’s credentials.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• GPT-5: Speculative IDOR; destination.credentialId appears server-managed and is first matched against in-memory authenticated credentials. DB fallback by ID supports multi-host scheduling; no evidence of user-controlled input here.
Prompt for AI agents
Address the following comment on packages/core/EventManager.ts at line 344:
<comment>Broken Access Control/IDOR: Fetching and using calendar credentials by raw ID without ownership/authorization checks allows unauthorized calendar actions using another user’s credentials.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: Speculative IDOR; destination.credentialId appears server-managed and is first matched against in-memory authenticated credentials. DB fallback by ID supports multi-host scheduling; no evidence of user-controlled input here.</comment>
<file context>
@@ -332,29 +334,52 @@ export default class EventManager {
+ let credential = this.calendarCredentials.find((c) => c.id === destination.credentialId);
+ if (!credential) {
+ // Fetch credential from DB
+ const credentialFromDB = await prisma.credential.findUnique({
+ include: {
+ app: {
</file context>
[internal] Confidence score: 8/10
[internal] Posted by: Security Vulnerabilities Agent
| throw new Error("dynamicUserList is not properly defined or empty."); | ||
| } | ||
|
|
||
| const users = await prisma.user.findMany({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamic collective bookings need each host’s organization slug for downstream logic, but the new Prisma query omits selecting organization. Restore selecting the relation to avoid runtime user.organization access errors.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• GPT-5: No runtime access to user.organization or slug for dynamically loaded users. eventType.hosts already selects organization.slug; other logic references organizationId only. The omission won’t cause a runtime error in this file.
Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleNewBooking.ts at line 731:
<comment>Dynamic collective bookings need each host’s organization slug for downstream logic, but the new Prisma query omits selecting `organization`. Restore selecting the relation to avoid runtime `user.organization` access errors.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: No runtime access to user.organization or slug for dynamically loaded users. eventType.hosts already selects organization.slug; other logic references organizationId only. The omission won’t cause a runtime error in this file.</comment>
<file context>
@@ -722,31 +721,46 @@ async function handler(
+ throw new Error("dynamicUserList is not properly defined or empty.");
+ }
+
+ const users = await prisma.user.findMany({
where: {
- username: {
</file context>
[internal] Confidence score: 6/10
[internal] Posted by: General AI Review Agent
| destinationCalendar: | ||
| evt.destinationCalendar && evt.destinationCalendar.length > 0 | ||
| ? { | ||
| connect: { id: evt.destinationCalendar[0].id }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The application creates a booking record in the database by connecting it to only the first destination calendar from the list of hosts for a collective event. This breaks the multi-host calendar feature, as information about other hosts' calendars is lost upon booking creation. Subsequent operations like updates or cancellations will only be performed on the organizer's calendar, not the entire collective team's calendars.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• GPT-5: Based on this file, updates/reschedules rely on booking.references created per calendar by EventManager, not on booking.destinationCalendar. The single connect does not conclusively break multi-host behavior without verified schema/other handler evidence. To minimize false positives, filter.
Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleNewBooking.ts at line 1877:
<comment>The application creates a booking record in the database by connecting it to only the first destination calendar from the list of hosts for a collective event. This breaks the multi-host calendar feature, as information about other hosts' calendars is lost upon booking creation. Subsequent operations like updates or cancellations will only be performed on the organizer's calendar, not the entire collective team's calendars.
DEV MODE: This violation would have been filtered out by GPT-5.
Reasoning:
• **GPT-5**: Based on this file, updates/reschedules rely on booking.references created per calendar by EventManager, not on booking.destinationCalendar. The single connect does not conclusively break multi-host behavior without verified schema/other handler evidence. To minimize false positives, filter.</comment>
<file context>
@@ -1843,11 +1871,12 @@ async function handler(
+ destinationCalendar:
+ evt.destinationCalendar && evt.destinationCalendar.length > 0
+ ? {
+ connect: { id: evt.destinationCalendar[0].id },
+ }
+ : undefined,
</file context>
[internal] Confidence score: 10/10
[internal] Posted by: System Design Agent
| let eventRespData; | ||
| const calendarId = event.destinationCalendar?.externalId; | ||
| const [mainHostDestinationCalendar] = event.destinationCalendar ?? []; | ||
| const calendarId = mainHostDestinationCalendar?.externalId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calendar services for Lark, Office365, and iCal have not been correctly updated to handle multiple destination calendars. They consistently only process the first calendar in the destinationCalendar array, which will cause the feature to fail for any users with these integrations. Furthermore, their createEvent method signatures are not updated to match the Calendar interface, which now requires a credentialId.
DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.
Prompt for AI agents
Address the following comment on packages/app-store/larkcalendar/lib/CalendarService.ts at line 129:
<comment>The calendar services for Lark, Office365, and iCal have not been correctly updated to handle multiple destination calendars. They consistently only process the first calendar in the `destinationCalendar` array, which will cause the feature to fail for any users with these integrations. Furthermore, their `createEvent` method signatures are not updated to match the `Calendar` interface, which now requires a `credentialId`.
*DEV MODE: This violation would have been filtered out by screening filters. Failing filters: typescriptUnderstanding.*</comment>
<file context>
@@ -125,7 +125,8 @@ export default class LarkCalendarService implements Calendar {
let eventRespData;
- const calendarId = event.destinationCalendar?.externalId;
+ const [mainHostDestinationCalendar] = event.destinationCalendar ?? [];
+ const calendarId = mainHostDestinationCalendar?.externalId;
if (!calendarId) {
throw new Error("no calendar id");
</file context>
[internal] Confidence score: 10/10
[internal] Posted by: System Design Agent
| }; | ||
|
|
||
| if (isTeamEventType && eventType.schedulingType === "COLLECTIVE") { | ||
| evt.destinationCalendar?.push(...teamDestinationCalendars); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Team calendars are ignored when organizer lacks destination calendar due to optional push; COLLECTIVE bookings miss team member calendar events.
Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleNewBooking.ts at line 1078:
<comment>Team calendars are ignored when organizer lacks destination calendar due to optional push; COLLECTIVE bookings miss team member calendar events.</comment>
<file context>
@@ -1040,16 +1060,24 @@ async function handler(
};
+ if (isTeamEventType && eventType.schedulingType === "COLLECTIVE") {
+ evt.destinationCalendar?.push(...teamDestinationCalendars);
+ }
+
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: Functional Bugs Agent
| const selectedCalendar = externalCalendarId | ||
| ? externalCalendarId | ||
| : event.destinationCalendar?.externalId; | ||
| : event.destinationCalendar?.find((cal) => cal.externalId === externalCalendarId)?.externalId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updateEvent may pass undefined calendarId; createEvent follow-up patch may pass undefined calendarId; organizer attendee email set to calendarId; and patch errors are swallowed
Prompt for AI agents
Address the following comment on packages/app-store/googlecalendar/lib/CalendarService.ts at line 256:
<comment>updateEvent may pass undefined calendarId; createEvent follow-up patch may pass undefined calendarId; organizer attendee email set to calendarId; and patch errors are swallowed</comment>
<file context>
@@ -244,7 +253,7 @@ export default class GoogleCalendarService implements Calendar {
const selectedCalendar = externalCalendarId
? externalCalendarId
- : event.destinationCalendar?.externalId;
+ : event.destinationCalendar?.find((cal) => cal.externalId === externalCalendarId)?.externalId;
calendar.events.update(
</file context>
[internal] Confidence score: 9/10
[internal] Posted by: Functional Bugs Agent
| const apiDeletes = []; | ||
|
|
||
| const bookingCalendarReference = bookingToDelete.references.find((reference) => | ||
| const bookingCalendarReference = bookingToDelete.references.filter((reference) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken access control: Any authenticated user can cancel another user's future booking (and trigger external deletions/refunds).
Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleCancelBooking.ts at line 418:
<comment>Broken access control: Any authenticated user can cancel another user's future booking (and trigger external deletions/refunds).</comment>
<file context>
@@ -411,58 +415,71 @@ async function handler(req: CustomRequest) {
const apiDeletes = [];
- const bookingCalendarReference = bookingToDelete.references.find((reference) =>
+ const bookingCalendarReference = bookingToDelete.references.filter((reference) =>
reference.type.includes("_calendar")
);
</file context>
[internal] Confidence score: 8/10
[internal] Posted by: Security Vulnerabilities Agent
Summary by cubic
Add multi-calendar support for collective events by changing destinationCalendar from a single value to an array and ensuring events are created/updated/deleted on each host’s calendar. This fixes syncing issues for multi-host bookings and aligns calendar selection with the correct credential.
Bug Fixes
Refactors