Skip to content

Fix client config env guard for local builds - #7386

Merged
lawrencecchen merged 2 commits into
mainfrom
fix-client-config-env-guard
Jul 5, 2026
Merged

lawrencecchen merged 2 commits into
mainfrom
fix-client-config-env-guard

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary\n- require CMUX_CLIENT_CONFIG_RATE_LIMIT_ID only when VERCEL_ENV is explicitly non-preview\n- keep production deployment validation for missing limiter IDs\n- add subprocess coverage for local Vercel-like builds and production validation\n\n## Tests\n- bun test tests/client-config-env.test.ts tests/client-config-route.test.ts\n- env VERCEL=1 VERCEL_PREVIEW_COMMENTS_ENABLED=0 RESEND_API_KEY=test-resend CMUX_FEEDBACK_FROM_EMAIL=hello@example.com CMUX_FEEDBACK_RATE_LIMIT_ID=feedback-rule STACK_SECRET_SERVER_KEY=stack-secret NEXT_PUBLIC_STACK_PROJECT_ID=00000000-0000-4000-8000-000000000000 NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=stack-public ./node_modules/.bin/next build && bun tools/build-docs-search.mjs


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

Low Risk
Narrower env validation for one optional server var; deployed production still requires the limiter ID, with new tests locking in the behavior.

Overview
Fixes false env validation failures when building locally with VERCEL=1 but no VERCEL_ENV (e.g. Vercel CLI–like setups). CMUX_CLIENT_CONFIG_RATE_LIMIT_ID is now required only when isVercelNonPreviewDeployment is true: VERCEL=1, VERCEL_ENV is a defined string, and it is not preview. Previously, an undefined VERCEL_ENV still satisfied !== "preview", so the limiter ID was incorrectly enforced.

Production behavior is unchanged: explicit VERCEL_ENV=production (or other non-preview values) still fails validation without the limiter ID.

Adds client-config-env.test.ts with subprocess imports of ./app/env covering local Vercel-like builds, failing production without the ID, and passing production with it.

Reviewed by Cursor Bugbot for commit 0c59f4e. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Relaxed env validation for client config limiter. We now require CMUX_CLIENT_CONFIG_RATE_LIMIT_ID only for explicit Vercel non-preview deployments, while allowing local and Vercel-like builds to run without it.

  • Bug Fixes
    • Added isVercelNonPreviewDeployment guard to limit checks to VERCEL=1 with non-preview VERCEL_ENV.
    • Added tests for local builds and production validation using subprocess import.

Written for commit 3af8cfb. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved deployment environment detection to ensure client configuration validation behaves correctly across preview and non-preview deployments.
    • Refined environment value handling to reduce misleading validation failures when deployment variables are missing or unexpected.
  • Tests
    • Added automated coverage for client configuration environment validation in Node-run scenarios, including success and failure cases based on deployment settings.

@vercel

vercel Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 5, 2026 10:55am
cmux-staging Building Building Preview, Comment Jul 5, 2026 10:55am

@coderabbitai

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Vercel non-preview deployment check in web/app/env.ts was refactored into an explicit isVercelNonPreviewDeployment boolean with a string-type guard on VERCEL_ENV. A new Bun test suite validates the resulting environment behavior across multiple Vercel env combinations.

Changes

Vercel Deployment Validation

Layer / File(s) Summary
Refined Vercel detection
web/app/env.ts
Replaces the inline VERCEL_ENV !== "preview" condition with isVercelNonPreviewDeployment, adding an explicit typeof process.env.VERCEL_ENV === "string" check before the validation issue is emitted.
Spawned env validation tests
web/tests/client-config-env.test.ts
Adds a Bun test suite with a shared environment baseline, a Node spawn helper, and three cases covering missing and present client config under Vercel production and preview conditions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as Bun test case
  participant Helper as importEnv
  participant Node as Spawned Node process
  participant EnvModule as ./app/env

  Test->>Helper: importEnv(env)
  Helper->>Node: spawn node import
  Node->>EnvModule: load module with env vars
  EnvModule-->>Node: validate config
  Node-->>Helper: exitCode, stderr
  Helper-->>Test: result object
  Test->>Test: assert exit code and stderr text
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Cmux User-Facing Error Privacy ❌ Error env.ts adds a runtime validation error that prints the raw env var name CMUX_CLIENT_CONFIG_RATE_LIMIT_ID, violating the user-facing error privacy rule. Change the message to generic product terms, and keep env-var names/internal deployment details in logs or telemetry rather than emitted errors.
✅ Passed checks (24 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing client config env validation for local builds.
Description check ✅ Passed The description covers the required Summary and Testing sections, with only optional template sections like demo video and checklist missing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: The PR only changes web TS env/test files; no Swift source or SwiftUI actor-isolation code is modified.
Cmux Swift Blocking Runtime ✅ Passed PASS — the PR only changes a TypeScript test file; there are no Swift diff hunks or blocking/synchronization changes to review.
Cmux Browser Automation Off-Main ✅ Passed PR only changes a client env test; no browser.* automation, mainActor, or worker-router code was touched.
Cmux Expensive Synchronous Load ✅ Passed Only web/tests/client-config-env.test.ts changed; no Swift or main-actor/session-load paths were added or moved.
Cmux Cache Substitution Correctness ✅ Passed No cache/persistence substitution appears in the diff; the only change is a test harness swap from Bun.spawnSync to node:child_process spawnSync.
Cmux No Hacky Sleeps ✅ Passed The PR only changes env validation and a test helper; no fixed sleeps, timers, polling, or wall-clock waits were introduced in runtime code.
Cmux Algorithmic Complexity ✅ Passed env.ts only adds constant-time env-var checks; no scalable collection scans or hot-path sorting/filtering were introduced, and the new file is test-only.
Cmux Swift Concurrency ✅ Passed Commit 0c59f4e changes only web/tests/client-config-env.test.ts; no Swift files or concurrency patterns are present, so the Swift rule is not applicable.
Cmux Swift @Concurrent ✅ Passed No Swift files or Swift concurrency changes are in the diff; the Swift @concurrent rule is not applicable.
Cmux Swift File And Package Boundaries ✅ Passed No Swift files were changed; the PR only touches web/tests, so the Swift file/package boundary rule is not applicable.
Cmux Swiftpm Lockfiles ✅ Passed Diff only changes web/tests/client-config-env.test.ts; no SwiftPM, Xcode, .gitignore, workflow, or dependency files are touched.
Cmux Swift Logging ✅ Passed The PR changes only a TypeScript test file; no Swift runtime code or logging statements were added or modified.
Cmux Full Internationalization ✅ Passed Only env validation logic and tests changed; no user-facing UI/copy or locale files were added or modified.
Cmux Swiftui State Layout ✅ Passed PR only changes env validation and a Bun test; no SwiftUI views, state objects, GeometryReader, lazy-row store refs, or render-time mutation.
Cmux Architecture Rethink ✅ Passed PASS: The PR only changes TypeScript env validation and tests; it doesn't touch Swift lifecycle wiring or introduce any of the banned architectural patterns.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Diff only changes web/tests/client-config-env.test.ts; no Swift window code was added or modified, so the auxiliary-window shortcut rule is not triggered.
Cmux Source Artifacts ✅ Passed Only intentional source/test files changed; no generated logs, caches, scratch dirs, or other artifact paths were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Only web/tests/client-config-env.test.ts changed; no Swift file under production Sources/ was modified, so the production-source seam rule is not implicated.
Cmux No Ambient Global State ✅ Passed PASS: This PR only changes TypeScript env validation/tests; the Swift-only no-ambient-global-state rule doesn’t apply, and no new ambient globals/singletons are introduced.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-client-config-env-guard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR tightens the CMUX_CLIENT_CONFIG_RATE_LIMIT_ID validation guard in web/app/env.ts so that the variable is only required when VERCEL_ENV is explicitly set to a non-preview string. Previously, VERCEL=1 without VERCEL_ENV set would trigger validation failure because undefined !== "preview" evaluates to true, breaking local Vercel-like builds.

  • web/app/env.ts: Introduces isVercelNonPreviewDeployment (gated on VERCEL=1, typeof VERCEL_ENV === \"string\", and VERCEL_ENV !== \"preview\") and uses it in requireVercelNonPreviewValue, replacing the inline condition that was too eager when VERCEL_ENV was absent.
  • web/tests/client-config-env.test.ts: New test file using spawnSync subprocess isolation to cover three distinct scenarios: local build (VERCEL=1, no VERCEL_ENV), production without the limiter id, and production with the limiter id.

Confidence Score: 5/5

Safe to merge — the production validation path is preserved and the relaxed guard only affects builds where VERCEL_ENV is absent.

The guard change is narrowly scoped: it adds an explicit string-presence check for VERCEL_ENV so that local Vercel-like builds (VERCEL=1, no VERCEL_ENV) no longer incorrectly fail. Real production deployments always have VERCEL_ENV set to production or development, so the limiter-id requirement remains intact there. The one finding is a test-helper robustness issue that does not affect production behavior.

web/tests/client-config-env.test.ts — the spawnSync helper lacks an explicit cwd, making it sensitive to the caller's working directory.

Important Files Changed

Filename Overview
web/app/env.ts Adds isVercelNonPreviewDeployment guard to correctly scope rate-limit env requirement; logic is sound and closes the undefined-VERCEL_ENV false-positive.
web/tests/client-config-env.test.ts New subprocess-based env-validation test covering three scenarios; missing explicit cwd in spawnSync makes tests sensitive to the caller's working directory.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Module load: env.ts] --> B{VERCEL === '1'?}
    B -- No --> C[isVercelNonPreviewDeployment = false\nvalidation skipped]
    B -- Yes --> D{typeof VERCEL_ENV === 'string'?}
    D -- No\n(local / Vercel CLI build) --> C
    D -- Yes --> E{VERCEL_ENV !== 'preview'?}
    E -- No\n(preview deploy) --> C
    E -- Yes\n(production / development) --> F[isVercelNonPreviewDeployment = true]
    F --> G{CMUX_CLIENT_CONFIG_RATE_LIMIT_ID set?}
    G -- Yes --> H[Validation passes]
    G -- No --> I[Zod error: required for non-preview runtimes]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Module load: env.ts] --> B{VERCEL === '1'?}
    B -- No --> C[isVercelNonPreviewDeployment = false\nvalidation skipped]
    B -- Yes --> D{typeof VERCEL_ENV === 'string'?}
    D -- No\n(local / Vercel CLI build) --> C
    D -- Yes --> E{VERCEL_ENV !== 'preview'?}
    E -- No\n(preview deploy) --> C
    E -- Yes\n(production / development) --> F[isVercelNonPreviewDeployment = true]
    F --> G{CMUX_CLIENT_CONFIG_RATE_LIMIT_ID set?}
    G -- Yes --> H[Validation passes]
    G -- No --> I[Zod error: required for non-preview runtimes]
Loading

Reviews (2): Last reviewed commit: "Fix client config env test typecheck" | Re-trigger Greptile

Comment on lines +51 to +58
const result = spawnSync(
process.execPath,
["-e", "await import('./app/env')"],
{
env: env as NodeJS.ProcessEnv,
encoding: "utf8",
},
);

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.

P2 The spawnSync call does not specify a cwd, so the subprocess resolves ./app/env relative to whatever directory the test runner was invoked from. If CI or a developer runs bun test from the repo root instead of web/, the dynamic import will fail to find the module and all three tests will produce misleading failures (exit code ≠ 0 but for the wrong reason). Pinning cwd to the directory containing the test file makes the helper robust regardless of invocation path.

Suggested change
const result = spawnSync(
process.execPath,
["-e", "await import('./app/env')"],
{
env: env as NodeJS.ProcessEnv,
encoding: "utf8",
},
);
const result = spawnSync(
process.execPath,
["-e", "await import('./app/env')"],
{
cwd: new URL("..", import.meta.url).pathname,
env: env as NodeJS.ProcessEnv,
encoding: "utf8",
},
);

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/tests/client-config-env.test.ts`:
- Around line 50-58: The importEnv helper in client-config-env.test.ts uses
spawnSync without any execution bound, so add a timeout option to the spawnSync
call to prevent the child process from hanging the test run. Update the
importEnv function to include a reasonable timeout while preserving the existing
env and encoding behavior, and ensure the test still returns exitCode and stderr
from the spawn result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 926e4b5b-c1f4-4d15-8277-fb00e6e98abb

📥 Commits

Reviewing files that changed from the base of the PR and between 3af8cfb and 0c59f4e.

📒 Files selected for processing (1)
  • web/tests/client-config-env.test.ts

Comment on lines +50 to +58
function importEnv(env: Record<string, string>): { exitCode: number; stderr: string } {
const result = spawnSync(
process.execPath,
["-e", "await import('./app/env')"],
{
env: env as NodeJS.ProcessEnv,
encoding: "utf8",
},
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add a timeout to spawnSync to prevent CI hangs.

The subprocess call has no bound; if the child ever fails to exit (e.g. an unresolved promise introduced later in env.ts), the whole test run blocks indefinitely.

🔒 Proposed fix
   const result = spawnSync(
     process.execPath,
     ["-e", "await import('./app/env')"],
     {
       env: env as NodeJS.ProcessEnv,
       encoding: "utf8",
+      timeout: 10_000,
     },
   );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function importEnv(env: Record<string, string>): { exitCode: number; stderr: string } {
const result = spawnSync(
process.execPath,
["-e", "await import('./app/env')"],
{
env: env as NodeJS.ProcessEnv,
encoding: "utf8",
},
);
function importEnv(env: Record<string, string>): { exitCode: number; stderr: string } {
const result = spawnSync(
process.execPath,
["-e", "await import('./app/env')"],
{
env: env as NodeJS.ProcessEnv,
encoding: "utf8",
timeout: 10_000,
},
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/tests/client-config-env.test.ts` around lines 50 - 58, The importEnv
helper in client-config-env.test.ts uses spawnSync without any execution bound,
so add a timeout option to the spawnSync call to prevent the child process from
hanging the test run. Update the importEnv function to include a reasonable
timeout while preserving the existing env and encoding behavior, and ensure the
test still returns exitCode and stderr from the spawn result.

@lawrencecchen
lawrencecchen merged commit 6d0c4af into main Jul 5, 2026
32 checks passed
@lawrencecchen
lawrencecchen deleted the fix-client-config-env-guard branch July 5, 2026 23:13
@lawrencecchen
lawrencecchen restored the fix-client-config-env-guard branch July 18, 2026 10:24

This branch was successfully deployed

1 active deployment
Preview – cmux — 0c59f4e9 Deployed Jul 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant