Skip to content

Restrict chat gateway target overrides#899

Merged
DanielButler1 merged 2 commits into
mainfrom
fix/chat-gateway-target-policy
Jul 5, 2026
Merged

Restrict chat gateway target overrides#899
DanielButler1 merged 2 commits into
mainfrom
fix/chat-gateway-target-policy

Conversation

@DanielButler1

@DanielButler1 DanielButler1 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Restrict chat gateway target resolution so production uses only the configured AI_STATS_GATEWAY_URL.
  • Fail closed in production when the gateway URL is missing instead of falling back to the public API.
  • Preserve local development testing by allowing the public gateway and localhost gateway targets outside production.
  • Add regression coverage for production fail-closed behavior and development-only overrides.

Validation

  • pnpm --filter @ai-stats/web test -- gatewayProxy.test.ts
  • pnpm --filter @ai-stats/web typecheck
  • pnpm --filter @ai-stats/web exec eslint "src/app/api/chat/_shared/gatewayProxy.ts" "src/app/api/chat/_shared/gatewayProxy.test.ts"

Note: full pnpm --filter @ai-stats/web lint still fails on existing repo-wide lint issues unrelated to this change.

Created with Codex

Summary by CodeRabbit

  • Bug Fixes

    • Improved gateway URL handling across environments.
    • In production, the app now uses only the configured gateway URL and no longer falls back to a public default when it isn’t set.
    • In development, local and approved public gateway targets continue to work, while unsupported external targets are ignored in favor of a safe fallback.
  • Tests

    • Added coverage for production and development gateway URL resolution behavior.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@DanielButler1, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 70769eb0-e773-4e22-9a03-45531185e782

📥 Commits

Reviewing files that changed from the base of the PR and between 63fef09 and 9b7e447.

📒 Files selected for processing (1)
  • apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts
📝 Walkthrough

Walkthrough

The gateway base URL resolution logic in gatewayProxy.ts was refactored to accept an explicit nodeEnv parameter and introduces a new exported function, resolveGatewayBaseUrlForEnvironment, which fails closed to null in production when unconfigured. New Jest tests validate this behavior.

Changes

Gateway Base URL Resolution

Layer / File(s) Summary
Environment-aware resolution logic
apps/web/src/app/api/chat/_shared/gatewayProxy.ts
isDevelopmentLocalGatewayBaseUrl now accepts an explicit nodeEnv parameter instead of reading process.env.NODE_ENV directly; new exported resolveGatewayBaseUrlForEnvironment resolves the gateway base URL per environment, returning null in production when unconfigured (no public fallback) and preferring requested/configured/public URLs in non-production; resolveGatewayBaseUrl now delegates to it.
Resolution behavior tests
apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts
Adds Jest tests covering production configured-only/fail-closed behavior and development allowance of explicit public/localhost targets versus rejection of arbitrary external targets.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client as Proxy Endpoint
  participant Resolver as resolveGatewayBaseUrlForEnvironment
  participant Env as process.env

  Client->>Env: read AI_STATS_GATEWAY_URL, NODE_ENV
  Client->>Resolver: resolve(configuredBaseUrl, requestedBaseUrl, nodeEnv)
  alt production
    Resolver-->>Client: normalized configuredBaseUrl or null
    Client->>Client: if null, return gateway_not_configured
  else development
    Resolver-->>Client: requestedBaseUrl, configuredBaseUrl, or public fallback
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: restricting chat gateway target overrides.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/chat-gateway-target-policy

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.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@DanielButler1 DanielButler1 marked this pull request as ready for review July 5, 2026 07:50

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

🧹 Nitpick comments (2)
apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts (2)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the app’s absolute import alias here.

This test is under apps/web, so prefer the @/ alias instead of a relative import.

Suggested change
-import { resolveGatewayBaseUrlForEnvironment } from "./gatewayProxy";
+import { resolveGatewayBaseUrlForEnvironment } from "`@/app/api/chat/_shared/gatewayProxy`";

As per coding guidelines, apps/web/**/*.{ts,tsx}: “Web app uses Next.js 15 App Router with TypeScript ES modules and absolute imports using @/ prefix; Tailwind for styling.”

🤖 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 `@apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts` at line 1, The import
in the gatewayProxy test should use the web app’s absolute alias instead of a
relative path. Update the import in gatewayProxy.test.ts to reference
resolveGatewayBaseUrlForEnvironment via the `@/` prefix, matching the apps/web
import convention and keeping it consistent with the gatewayProxy module
location.

Source: Coding guidelines


4-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a production assertion for arbitrary requested targets.

The production test covers public and localhost overrides, but the main abuse case is an arbitrary external target. Add one deterministic fixture to lock that down too.

Suggested addition
 		expect(
 			resolveGatewayBaseUrlForEnvironment({
 				configuredBaseUrl: "https://private-gateway.example.com",
 				requestedBaseUrl: "http://127.0.0.1:8787/v1",
 				nodeEnv: "production",
 			}),
 		).toBe("https://private-gateway.example.com/v1");
+
+		expect(
+			resolveGatewayBaseUrlForEnvironment({
+				configuredBaseUrl: "https://private-gateway.example.com",
+				requestedBaseUrl: "https://attacker.example.com/v1",
+				nodeEnv: "production",
+			}),
+		).toBe("https://private-gateway.example.com/v1");

As per coding guidelines, **/*.test.{ts,tsx}: “Jest test files should cover new logic and data validations with deterministic fixtures.”

🤖 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 `@apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts` around lines 4 - 20,
The production coverage in resolveGatewayBaseUrlForEnvironment is missing the
arbitrary external-target case, so add one deterministic assertion in
gatewayProxy.test.ts alongside the existing production checks. Reuse the same
test and verify that when nodeEnv is production and requestedBaseUrl points to
an external non-public target, the function still resolves to the
configuredBaseUrl with the requested path preserved, matching the pattern
already used for the public and localhost fixtures.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts`:
- Line 1: The import in the gatewayProxy test should use the web app’s absolute
alias instead of a relative path. Update the import in gatewayProxy.test.ts to
reference resolveGatewayBaseUrlForEnvironment via the `@/` prefix, matching the
apps/web import convention and keeping it consistent with the gatewayProxy
module location.
- Around line 4-20: The production coverage in
resolveGatewayBaseUrlForEnvironment is missing the arbitrary external-target
case, so add one deterministic assertion in gatewayProxy.test.ts alongside the
existing production checks. Reuse the same test and verify that when nodeEnv is
production and requestedBaseUrl points to an external non-public target, the
function still resolves to the configuredBaseUrl with the requested path
preserved, matching the pattern already used for the public and localhost
fixtures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ee058a1a-99cb-4506-8781-f81c3a711638

📥 Commits

Reviewing files that changed from the base of the PR and between ef84286 and 63fef09.

📒 Files selected for processing (2)
  • apps/web/src/app/api/chat/_shared/gatewayProxy.test.ts
  • apps/web/src/app/api/chat/_shared/gatewayProxy.ts

@DanielButler1 DanielButler1 merged commit 08e2fdc into main Jul 5, 2026
33 checks passed
@DanielButler1 DanielButler1 deleted the fix/chat-gateway-target-policy branch July 5, 2026 08:13
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