Skip to content

CS-656 Create script to Migrate all users from old domain to new domain - remove duplicate people records#3304

Open
github-actions[bot] wants to merge 10 commits into
mainfrom
chas/email-migration-script
Open

CS-656 Create script to Migrate all users from old domain to new domain - remove duplicate people records#3304
github-actions[bot] wants to merge 10 commits into
mainfrom
chas/email-migration-script

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

This is an automated pull request to merge chas/email-migration-script into dev.
It was created by the [Auto Pull Request] action.


Summary by cubic

Adds trigger tasks merge-duplicate-user and migrate-org-email-domain to merge duplicate users during org email-domain migrations. Completes CS-656 by consolidating all references and removing the old user to prevent conflicts.

  • New Features
    • Atomic DB transaction (30s) with org:{organizationId} tagging and improved logging.
    • Reassigns member refs across policies (assignee/approver/signedBy), policy versions, tasks/task items, risks, vendors, findings, comments, audit logs, devices, trust access, offboarding, and SOA/ISMS approvals.
    • Re-points user-level relations (OAuth accounts/tokens/consents, fleet policy results, integration logs, audit logs), deletes McpOrgBinding, clears sessions, updates invitations, dedupes training/background checks/offboarding items, and deletes the old user record.
    • migrate-org-email-domain scans active members, lowercases emails/domains, matches local-part from oldDomainnewDomain, triggers merges per pair, and returns merged/failed counts; no-op if normalized domains match.

Written for commit fc47152. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comp-framework-editor Ready Ready Preview, Comment Jun 30, 2026 7:42pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app Skipped Skipped Jun 30, 2026 7:42pm
portal Skipped Skipped Jun 30, 2026 7:42pm

Request Review

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

4 issues found across 1 file

Confidence score: 2/5

  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, there is no guard for oldEmail === newEmail, so a self-merge can delete the very user/member being kept; merging as-is risks destructive data loss on valid-looking input — add an explicit equality short-circuit before any delete/update steps.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, the training completion migration drops id and then later updates by id, which can make that migration fail or silently affect zero rows; this creates a concrete partial-migration/regression risk — keep id in the projection (or change downstream updates to available keys) and verify with a targeted migration test before merging.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, resolving members outside the transaction introduces a TOCTOU window where merge targets can change mid-operation, leading to inconsistent merges under concurrency — move member resolution inside the same transaction (or lock rows) before merge.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, the final merge log reports deleted IDs as survivors, which can mislead incident response and audits after a bad merge — correct survivor/deleted ID mapping in the log payload before shipping.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts Outdated
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
@vercel vercel Bot temporarily deployed to Preview – portal June 30, 2026 17:00 Inactive
@vercel vercel Bot temporarily deployed to Preview – app June 30, 2026 17:00 Inactive
@chasprowebdev chasprowebdev changed the title [dev] [chasprowebdev] chas/email-migration-script CS-656 Create script to Migrate all users from old domain to new domain - remove duplicate people records Jun 30, 2026
@linear

linear Bot commented Jun 30, 2026

Copy link
Copy Markdown

CS-656

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/migrate-org-email-domain.ts Outdated
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts Outdated

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/migrate-org-email-domain.ts
@chasprowebdev

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review it

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review it

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

3 issues found across 2 files

Confidence score: 2/5

  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, deleting oldUser before re-pointing user-level relations can cascade/null fields like AuditLog.userId, which risks losing historical attribution after a duplicate merge — migrate those relations to the surviving user first, then delete.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, SOA/ISMS approverId values are not migrated before old-member deletion, so pending/approved document approver assignments can be cleared as a side effect — add an explicit approver reassignment step before the delete.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, OffboardingAccessRevocation.revokedById is matched using member IDs instead of user IDs, so the actor link can be silently missed and revocation history becomes inaccurate — switch the comparison/update logic to user IDs before merging.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – app June 30, 2026 18:51 Inactive
@vercel vercel Bot temporarily deployed to Preview – portal June 30, 2026 18:51 Inactive
@chasprowebdev

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review this.

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review this.

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 2 files

Confidence score: 2/5

  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, the org-scoped duplicate merge can still perform a global delete of oldUser, which is risky if that user still belongs to other orgs; merging as-is could remove valid cross-org access/data unexpectedly — gate deletion on zero remaining memberships (or merge all memberships first) before deleting.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, memberId rewrites may hit unique constraints when both duplicates already map to the same logical row, so the task can fail mid-merge and leave partial updates — add per-table dedupe/skip handling ahead of updates to avoid collisions.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts Outdated

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

3 issues found across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts Outdated
Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/api/src/trigger/tasks/people/merge-duplicate-user.ts">

<violation number="1" location="apps/api/src/trigger/tasks/people/merge-duplicate-user.ts:355">
P1: Merge completion log labels the deleted old user and member as the surviving IDs, contradicting the actual survivors and the return payload.</violation>

<violation number="2" location="apps/api/src/trigger/tasks/people/merge-duplicate-user.ts:355">
P1: Global User record is deleted in an org-scoped migration without verifying the user has no other memberships or un-migrated relations.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic


// ── Delete old user sessions and the user record ─────────────────────
await tx.session.deleteMany({ where: { userId: oldUser.id } });
await tx.user.delete({ where: { id: oldUser.id } });

@cubic-dev-ai cubic-dev-ai Bot Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Merge completion log labels the deleted old user and member as the surviving IDs, contradicting the actual survivors and the return payload.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, line 355:

<comment>Merge completion log labels the deleted old user and member as the surviving IDs, contradicting the actual survivors and the return payload.</comment>

<file context>
@@ -350,8 +350,9 @@ export const mergeDuplicateUser = schemaTask({
-        // ── Delete old user sessions. ─────────────────────
+        // ── Delete old user sessions and the user record ─────────────────────
         await tx.session.deleteMany({ where: { userId: oldUser.id } });
+        await tx.user.delete({ where: { id: oldUser.id } });
 
         // ── Update pending invitations ───────────────────────────────────────
</file context>
Fix with cubic


// ── Delete old user sessions and the user record ─────────────────────
await tx.session.deleteMany({ where: { userId: oldUser.id } });
await tx.user.delete({ where: { id: oldUser.id } });

@cubic-dev-ai cubic-dev-ai Bot Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Global User record is deleted in an org-scoped migration without verifying the user has no other memberships or un-migrated relations.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, line 355:

<comment>Global User record is deleted in an org-scoped migration without verifying the user has no other memberships or un-migrated relations.</comment>

<file context>
@@ -350,8 +350,9 @@ export const mergeDuplicateUser = schemaTask({
-        // ── Delete old user sessions. ─────────────────────
+        // ── Delete old user sessions and the user record ─────────────────────
         await tx.session.deleteMany({ where: { userId: oldUser.id } });
+        await tx.user.delete({ where: { id: oldUser.id } });
 
         // ── Update pending invitations ───────────────────────────────────────
</file context>
Fix with cubic

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants