Skip to content

test(migrate): add live migrate tests and a weekly workflow - #611

Draft
royanger wants to merge 4 commits into
mainfrom
ra/migrate-live-tests
Draft

royanger wants to merge 4 commits into
mainfrom
ra/migrate-live-tests

Conversation

@royanger

@royanger royanger commented Nov 6, 2026

Copy link
Copy Markdown
Member

Warning

Do not merge yet. scripts/run-migrate-live-op.ts reads the test credentials from the 1Password Employee vault, which only I can read. Before merge, move the item to Shared and set OP_VAULT to "Shared".

It also needs #594 first: nothing here sets CLERK_EXPERIMENTAL, so the suite can't reach clerk migrate until the gate is gone.

Summary

This moves the live end-to-end tests for clerk migrate from migration-test-apps into test/migrate-live/. Each run seeds a real provider (Auth0, Auth.js, Better Auth, Clerk, Firebase, Supabase, WorkOS), exports and imports with this checkout's CLI, checks what landed in Clerk, then undoes it.

They never run in PR CI. A weekly workflow runs them from main, so each Monday tests whatever shipped that week.

Changes

  • test/migrate-live/: the test:migrate and test:custom suites, their seeders and graders, and the seed data and answer keys. The folder has its own package.json and lockfile so the provider SDKs stay out of the workspace.
  • bun run test:migrate-live and its :all, :custom, and :teardown variants run locally through op run, so no plaintext keys touch disk.
  • .github/workflows/migrate-live.yml runs every provider plus the custom sources on Mondays at 09:17 UTC, or one provider on workflow_dispatch. Scheduled failures post to Slack through notify-failure.yml.
  • Format, lint, and typecheck now cover the folder, except data/.
  • .claude/rules/migrate-live.md and a pointer in CONTRIBUTING.md.

Dependencies are pinned to exact versions. With caret ranges Bun picked better-auth 1.7.17, which writes an issuer column the seeder doesn't create, and the first variation failed.

Secrets

The test credentials are environment secrets in a new migrate-live GitHub Environment. Its deployment branches are limited to main.

  • Why an environment: a repository secret can be read by a workflow on any branch pushed to this repo. These are third-party credentials (Auth0 client secret, Supabase service role key, Firebase service accounts, Turso tokens, WorkOS key), so they're limited to jobs that run from main. clerk/javascript does the same for VERIFY_EVIDENCE_TOKEN.
  • The cost: this PR can't run the suite in CI, because the environment rejects PR branches. I ran it locally (below). The first CI run is a workflow_dispatch right after merge.
  • The alternative: plain repository Actions secrets, which is what this repo's e2e job uses for CLERK_PLATFORM_API_KEY. That would let the PR run the suite before merge, at the cost of the exposure above. Switching means moving the secrets and deleting one environment: line.
  • The Slack webhook (MIGRATION_LIVE_TESTS_SLACK_WEBHOOK_URL) is a repository secret: the job that calls notify-failure.yml can't use an environment.

Every secret is named MIGRATION_LIVE_TESTS_<ENV_VAR>, the same in 1Password and in Actions.

Testing

bun run test:migrate-live -p better-auth -v B0 passed against this checkout's CLI: 100 users exported, 100 created, 85 of 85 passwords verified.

test:migrate-live:custom and -p clerk haven't run yet. Both import into a pool-1 Clerk instance that doesn't exist yet.

Before merge

  1. Create the pool-1 instance, add its two keys to 1Password, and add CLERK_POOL_1_SECRET_KEY and CLERK_POOL_1_APP_ID to the list in scripts/run-migrate-live-op.ts. The workflow already maps them.
  2. Run bun run test:migrate-live:custom.
  3. Create the migrate-live environment and set its secrets, plus the Slack webhook repo secret.
  4. Move the 1Password item to Shared, set OP_VAULT, and drop the warning and the do not merge label.

After merge, a full workflow_dispatch from main is the suite's first CI run.

🤖 Generated with Claude Code

royanger and others added 4 commits November 5, 2026 20:00
Moves test:migrate and test:custom over from migration-test-apps. Each run
seeds a real provider, exports and imports with this checkout's CLI, checks
what landed in Clerk, then undoes it.

The folder keeps its own package.json and lockfile so the provider SDKs stay
out of the workspace. Dependencies are pinned exactly: better-auth 1.7.17
adds an issuer column the seeders don't create, and B0 fails on it.

Format, lint, and typecheck now cover the folder, except data/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bun run test:migrate-live and its :all, :custom, and :teardown variants
resolve their secrets through op run, so no plaintext keys touch disk.

The item sits in the Employee vault until it moves to Shared. OP_VAULT is the
one line to change then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Runs every provider plus the custom sources on Mondays at 09:17 UTC, or one
provider on dispatch. Secrets come from the migrate-live environment, which
only allows main, so a pushed branch can't edit the workflow to read them.
Scheduled failures post to Slack.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Nov 6, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 37b3f29

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 6, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

if (result.status === "failed") process.exitCode = 1;
}

console.log(`\nSeed password: ${seedPassword}`);

const total = await clerkClient().users.getCount();
console.log(`\nClerk now reports ${total} users.`);
console.log(`Seed password: ${seedPassword}`);
},
hmac_sha256: {
options: { hash: { algorithm: "HMAC_SHA256", key: HMAC_KEY } },
hash: () => createHmac("sha256", HMAC_KEY).update(seedPassword).digest(),
},
md5: {
options: { hash: { algorithm: "MD5", rounds: 0 } },
hash: () => createHash("md5").update(seedPassword).digest(),
count += page.users.length;
}
console.log(`\nDone. Firebase reports ${count} users.`);
console.log(`Seed password: ${seedPassword}`);

const [{ n }] = await sql<{ n: number }>("select count(*)::int as n from auth.users");
console.log(`\nDone. auth.users holds ${n} rows.`);
console.log(`Seed password: ${seedPassword}`);
bcrypt: await bcrypt.hash(seedPassword, 10),
argon2id:
"$argon2id$v=19$m=19456,t=2,p=1$bWlncmF0aW9uLXRlc3Qtc2FsdC0xNmI$gBbnEhvXQQCPhOB0CWeS82tBRGEQX2Lxu/aAZhtFEsU",
unknown: `sha256:${createHash("sha256").update(seedPassword).digest("hex")}`,
}

console.table(summary);
console.log(`Seed password: ${seedPassword}`);
const failures = await pool(users, 4, createUser, progressBar("created"));
reportFailures(failures);

console.log(`\nSeed password: ${seedPassword}`);
env: TARGET_ENV,
});
const log = (line: string) => {
console.log(line);
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