Skip to content

feat(e2e): add staging instance settings validation#8094

Open
jacekradko wants to merge 4 commits intomainfrom
jacek/validate-staging-instances
Open

feat(e2e): add staging instance settings validation#8094
jacekradko wants to merge 4 commits intomainfrom
jacek/validate-staging-instances

Conversation

@jacekradko
Copy link
Member

@jacekradko jacekradko commented Mar 17, 2026

Summary

  • Add scripts/validate-staging-instances.mjs — compares FAPI /v1/environment responses between production and staging Clerk instance pairs
  • Detects configuration drift that causes cryptic E2E failures (auth strategies, MFA, required user fields, org settings, password requirements, etc.)
  • Add a non-blocking validate-instances job to the e2e-staging.yml workflow that runs before integration tests

What it compares

  • auth_config — session mode, reverification, first/second factors
  • user_settings.attributes — enabled, required, factor settings for email/phone/username/password/web3/passkey
  • user_settings.social — OAuth providers (only those enabled in at least one env)
  • user_settings.sign_in — MFA settings
  • user_settings.sign_up — mode, legal consent
  • user_settings.password_settings — length and complexity requirements
  • organization_settings — enabled, force selection

What it skips

  • Resource IDs, logo URLs, captcha settings, HIBP enforcement, disabled social providers

Example output

Validating 1 staging instance pair(s)...

❌ with-email-codes (15 mismatches)

  Auth Config
                                             prod           staging
    identification_requirements              missing on staging: oauth_custom_e2e_oauth_provider, web3_wallet
    first_factors                            missing on staging: oauth_custom_e2e_oauth_provider, web3_metamask_signature
    second_factors                           missing on staging: backup_code, totp
    single_session_mode                      false          true
    reverification                           false          true

  Organization Settings
                                             prod           staging
    enabled                                  true           false

  Attributes
                                             prod           staging
    web3_wallet.enabled                      true           false
    authenticator_app.enabled                true           false
    backup_code.enabled                      true           false

  Social Providers
                                             prod           staging
    oauth_custom_e2e_oauth_provider          present        missing
    oauth_google.block_email_subaddresses    false          true

  Password Settings
                                             prod           staging
    min_length                               8              0
    require_special_char                     true           false

Summary: 1 of 1 instance pair(s) have mismatches

Local usage

node scripts/validate-staging-instances.mjs

Test plan

  • Tested locally against real production/staging instance pair — correctly identifies 15 mismatches with grouped, readable output
  • Gracefully handles missing key files (exits 0)
  • Non-blocking — always exits 0 even on mismatches or errors

Summary by CodeRabbit

  • Chores
    • Added automated validation of staging instances to the CI workflow so staging configurations are compared against production before integration tests run, with per-instance reports and summarized results.
  • Tests
    • Extended pre-test validation steps to surface configuration mismatches early and prevent downstream test noise.

Compares FAPI /v1/environment responses between production and staging
instance pairs to detect configuration drift (auth strategies, MFA,
org settings, user requirements, etc.).

Runs as a non-blocking warning step in the e2e-staging workflow before
integration tests. Also runnable locally via:
  node scripts/validate-staging-instances.mjs
@vercel
Copy link

vercel bot commented Mar 17, 2026

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Mar 17, 2026 2:57am

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Mar 17, 2026

🦋 Changeset detected

Latest commit: ba1e1b0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

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

Not sure what this means? Click here to learn what changesets are.

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 17, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@8094

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8094

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8094

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8094

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8094

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@8094

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8094

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8094

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8094

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8094

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8094

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8094

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8094

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8094

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8094

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8094

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8094

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8094

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8094

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8094

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8094

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8094

commit: ba1e1b0

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7da3b24-3e3a-4d73-b47d-d6bbe58645b5

📥 Commits

Reviewing files that changed from the base of the PR and between a933a2a and ba1e1b0.

📒 Files selected for processing (1)
  • .changeset/validate-staging-instances.md

📝 Walkthrough

Walkthrough

Adds a new "Validate Staging Instances" job to the e2e-staging GitHub Actions workflow that runs before the Integration Tests. The job checks out only scripts/validate-staging-instances.mjs, sets environment variables from secrets (INTEGRATION_INSTANCE_KEYS, INTEGRATION_STAGING_INSTANCE_KEYS), and runs that Node script. The script loads production and staging keys (env or JSON), pairs instances, derives deployment domains, fetches each instance's /v1/environment, performs a recursive path-based diff with ignored paths and special handling for user_settings.subsections, social providers, and attribute-enabled flags, collapses certain mismatches, prints per-pair reports, and summarizes results.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(e2e): add staging instance settings validation' clearly and specifically describes the main change: a new feature for E2E testing that validates staging instance settings against production.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/e2e-staging.yml:
- Around line 57-59: The workflow's integration-tests job is missing an explicit
dependency on the validate-instances job, so add needs: [validate-instances] to
the integration-tests job definition (reference job name integration-tests and
validate-instances) to ensure validation runs beforehand; additionally, add
tests to cover the new validation behavior and workflow ordering—create/modify
CI tests that assert the validate-instances step is required before
integration-tests and add unit/integration tests for the validation script
behavior to prevent regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 42251c79-33eb-4f74-a042-a5e40ebb8646

📥 Commits

Reviewing files that changed from the base of the PR and between 291733c and 959aa36.

📒 Files selected for processing (2)
  • .github/workflows/e2e-staging.yml
  • scripts/validate-staging-instances.mjs

Group mismatches by section with aligned columns, collapse child fields
when a parent attribute is disabled, show array diffs as missing/extra
items instead of raw JSON, and collapse wholly missing social providers.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/validate-staging-instances.mjs`:
- Around line 61-67: The fetchEnvironment function makes an unbounded network
call and the validation summary can falsely report all pairs matched even when
some fetches failed; modify fetchEnvironment to accept a timeout parameter and
implement AbortController (or equivalent) so the fetch is aborted after the
timeout and throws a clear error, then update the validation loop that currently
skips pairs on fetch errors to record failures separately (e.g., maintain
matchedCount and failedCount or a map of pair->status) so any fetch/validation
error marks that pair as "failed" rather than silently skipping it, and change
the final summary logic that prints "all N instance pair(s) matched" to only
claim all matched when failedCount is zero and matchedCount equals totalPairs,
otherwise report exact counts and exit non-zero if any failures occurred.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: b1b644e7-d86b-440e-a314-b6ddc1626cb1

📥 Commits

Reviewing files that changed from the base of the PR and between 959aa36 and f638955.

📒 Files selected for processing (1)
  • scripts/validate-staging-instances.mjs

Add 10s fetch timeout via AbortSignal. Track fetch failures separately
so the summary never falsely reports 'all matched' when fetches failed.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/validate-staging-instances.mjs`:
- Around line 39-42: The loadKeys function currently
JSON.parse(process.env[envVar]) directly which can throw and abort the whole
run; change loadKeys to catch JSON.parse errors and validate each returned pair
has a string pair.*.pk, converting malformed JSON or invalid pairs into explicit
load/pair failures instead of throwing (e.g., return a result object {ok: false,
error: "..."} or an array where invalid entries are flagged), and update the
callers that consume loadKeys (and similar code paths referenced by the other
occurrences using the same logic) to handle these failure objects by recording a
per-pair validation error rather than letting the exception short-circuit the
script; ensure main().catch still exits non-zero only for fatal errors while
per-pair errors are reported in the summary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 066433e0-a7f5-44dc-b344-fe0da2802266

📥 Commits

Reviewing files that changed from the base of the PR and between f638955 and a933a2a.

📒 Files selected for processing (1)
  • scripts/validate-staging-instances.mjs

Comment on lines +39 to +42
function loadKeys(envVar, filePath) {
if (process.env[envVar]) {
return JSON.parse(process.env[envVar]);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Don’t let malformed keys short-circuit the entire validation run.

A bad INTEGRATION_*_KEYS JSON value or a missing/non-string pair.*.pk throws before the per-pair recovery path. In CI that stops validation for every remaining pair, then main().catch exits 0, so the job stays green without an accurate summary. Please validate/catch these inputs locally and turn them into explicit load/pair failures instead of aborting the whole script.

Suggested fix
 function loadKeys(envVar, filePath) {
   if (process.env[envVar]) {
-    return JSON.parse(process.env[envVar]);
+    try {
+      return JSON.parse(process.env[envVar]);
+    } catch (err) {
+      console.error(`Invalid ${envVar}: ${err.message}`);
+      return null;
+    }
   }
   try {
     return JSON.parse(readFileSync(resolve(filePath), 'utf-8'));
   } catch {
     return null;
@@
 function parseFapiDomain(pk) {
+  if (typeof pk !== 'string') {
+    throw new Error('Missing publishable key');
+  }
   const parts = pk.split('_');
+  if (parts.length < 3) {
+    throw new Error(`Invalid publishable key: ${pk}`);
+  }
   const encoded = parts.slice(2).join('_');
   const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
   return decoded.replace(/\$$/, '');
 }
@@
   for (const pair of pairs) {
-    const prodDomain = parseFapiDomain(pair.prod.pk);
-    const stagingDomain = parseFapiDomain(pair.staging.pk);
-
     let prodEnv, stagingEnv;
     try {
+      const prodDomain = parseFapiDomain(pair.prod?.pk);
+      const stagingDomain = parseFapiDomain(pair.staging?.pk);
       [prodEnv, stagingEnv] = await Promise.all([fetchEnvironment(prodDomain), fetchEnvironment(stagingDomain)]);
     } catch (err) {
       fetchFailCount++;
-      console.log(`⚠️  ${pair.name}: failed to fetch environment`);
+      console.log(`⚠️  ${pair.name}: failed to load or fetch environment`);
       console.log(`   ${err.message}\n`);
       continue;
     }

Also applies to: 52-57, 320-325, 349-352

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/validate-staging-instances.mjs` around lines 39 - 42, The loadKeys
function currently JSON.parse(process.env[envVar]) directly which can throw and
abort the whole run; change loadKeys to catch JSON.parse errors and validate
each returned pair has a string pair.*.pk, converting malformed JSON or invalid
pairs into explicit load/pair failures instead of throwing (e.g., return a
result object {ok: false, error: "..."} or an array where invalid entries are
flagged), and update the callers that consume loadKeys (and similar code paths
referenced by the other occurrences using the same logic) to handle these
failure objects by recording a per-pair validation error rather than letting the
exception short-circuit the script; ensure main().catch still exits non-zero
only for fatal errors while per-pair errors are reported in the summary.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant