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 29 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 29 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 reassigning org-scoped references, deleting the old member, and keeping the old user; user-level relations move and sessions clear only when the old user is single-org.

  • New Features

    • 30s atomic DB transaction with org:{organizationId} tags and clearer logs; recomputes old-user org-membership inside the transaction to avoid races.
    • Re-points org-scoped refs across policies (incl. signedBy arrays), policy versions, tasks/items, risks, vendors, findings, comments, audit logs, devices, trust access (requests/grants), SOA/ISMS approvals, and ISMS objective owners; dedupes background checks, offboarding checklist/revocations, and training completions; updates invitations.
    • User-level handling: never deletes the old user; when single-org, moves OAuth accounts/tokens/consents, fleet policy results, integration logs/errors, evidence submissions, integration results, audit logs, findings created-by, and offboarding actors, then clears sessions; otherwise skips user-level changes.
    • migrate-org-email-domain lowercases emails/domains, no-ops if normalized domains match, pairs old→new by local-part among active members, triggers merges, and returns merged/failed counts with pair details.
    • Adds an idempotent seed script and Jest tests.
  • Bug Fixes

    • Only re-points OffboardingAccessRevocation.revokedById when the old user has no other orgs; skips it for multi-org users.
    • Validates that newEmail differs from oldEmail case-insensitively to prevent invalid merges.

Written for commit 842eb0a. 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)
app Ready Ready Preview, Comment Jul 6, 2026 1:50pm
comp-framework-editor Ready Ready Preview, Comment Jul 6, 2026 1:50pm
portal Ready Ready Preview, Comment Jul 6, 2026 1:50pm

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 Outdated
@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 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 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.

No issues found across 7 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Re-trigger cubic

@vercel vercel Bot temporarily deployed to Preview – app July 2, 2026 18:28 Inactive
@vercel vercel Bot temporarily deployed to Preview – portal July 2, 2026 18:28 Inactive
@chasprowebdev

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review it.

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 2, 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.

1 issue found across 7 files

Confidence score: 3/5

  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, ISMS records can retain ownerMemberId references to the merged-away member, which risks orphaned ownership links or broken ownership lookups after deduplication; migrate ownerMemberId from old member ID to new member ID in the same transaction before deleting the old member.
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:273">
P1: This migration can rewrite revocation actor attribution outside the target org, because `revokedById` is updated globally by userId even when the old user still has memberships elsewhere. Scoping this update by `organizationId` (or moving it into the user-level branch) avoids cross-org data changes.</violation>
</file>

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/trigger/tasks/people/merge-duplicate-user.ts
@vercel vercel Bot temporarily deployed to Preview – app July 3, 2026 12:06 Inactive
@vercel vercel Bot temporarily deployed to Preview – portal July 3, 2026 12:06 Inactive
@chasprowebdev

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review it.

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 3, 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.

2 issues found across 7 files

Confidence score: 2/5

  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, the merge path can resolve oldEmail and newEmail to the same membership id and still execute tx.member.delete({ id: o }), which risks deleting the surviving target membership and breaking account/org access after merge — add an explicit same-member guard (or schema-level inequality constraint) before allowing delete and verify with a same-account test before merging.
  • In apps/api/src/trigger/tasks/people/merge-duplicate-user.ts, oldUserHasOtherOrgs is computed before the transaction, so concurrent membership changes can make that safety check stale and lead to incorrect merge decisions under load — recompute membership state inside the same transaction (or lock/read consistently) to de-risk race conditions before merge.
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:7">
P1: This task can delete the target membership when `oldEmail` and `newEmail` are the same account, because the merge still reaches `tx.member.delete({ id: o })` after resolving both members to one id. A schema-level inequality guard for the two emails would prevent this destructive path.</violation>

<violation number="2" location="apps/api/src/trigger/tasks/people/merge-duplicate-user.ts:62">
P2: User-level merge safety is decided from a pre-transaction membership count, so concurrent org-membership writes can make `oldUserHasOtherOrgs` stale during execution. Recomputing that condition inside the same transaction (or locking rows) would keep relation migration aligned with final membership state.</violation>

<violation number="3" location="apps/api/src/trigger/tasks/people/merge-duplicate-user.ts:273">
P1: This migration can rewrite revocation actor attribution outside the target org, because `revokedById` is updated globally by userId even when the old user still has memberships elsewhere. Scoping this update by `organizationId` (or moving it into the user-level branch) avoids cross-org data changes.</violation>
</file>

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Fix all with cubic | Re-trigger cubic

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 Outdated
@vercel vercel Bot temporarily deployed to Preview – portal July 3, 2026 13:20 Inactive
@vercel vercel Bot temporarily deployed to Preview – app July 3, 2026 13:20 Inactive
@chasprowebdev

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review it.

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 3, 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.

No issues found across 7 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Re-trigger 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.

3 participants