Skip to content

add proxy support for realtime calls (websocket based) - #5788

Open
akshaydeo wants to merge 1 commit into
mainfrom
08-02-add_proxy_support_for_realtime_calls_websocket_based_
Open

add proxy support for realtime calls (websocket based)#5788
akshaydeo wants to merge 1 commit into
mainfrom
08-02-add_proxy_support_for_realtime_calls_websocket_based_

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

WebSocket connections (Realtime and Responses) were not routing through the provider-level proxy configuration. HTTP requests already respected ProxyConfig, but the WebSocket dial path bypassed it entirely, causing WebSocket traffic to go direct regardless of what proxy was configured.

Changes

  • Added ConfigureWebSocketProxy in core/providers/utils/utils.go that mirrors ConfigureProxy for *ws.Dialer, supporting HTTP, SOCKS5, env-based, and no-proxy configurations. Unlike ConfigureProxy, it returns an error directly rather than swapping in a failing dial func, since WebSocket dials are resolved fresh on every call.
  • Updated Dial, DialUpstream, Pool.Get, and Pool.dial in the WebSocket transport to accept and apply a *schemas.ProxyConfig.
  • Updated WSRealtimeHandler.runRealtimeSession and WSResponsesHandler.tryNativeWSUpstream to look up the provider's ProxyConfig and pass it through to the dial path.
  • Added unit tests for ConfigureWebSocketProxy covering literal URL, env-backed URL, empty env value (fail-fast), nil config, NoProxy, and SOCKS5 cases.
  • Added integration tests in pool_test.go with a real CONNECT-based forward proxy to verify dials actually route through the proxy (TestPoolGetDialsThroughConfiguredHTTPProxy) and that an unreachable proxy fails the dial rather than falling back silently (TestPoolGetFailsWithUnreachableProxy).
  • Added an informational UI alert on the proxy configuration form clarifying that the proxy applies to HTTP and WebSocket connections but not WebRTC-based Realtime media paths.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

# Core/Transports
go test ./core/providers/utils/...
go test ./transports/bifrost-http/websocket/...

# UI
cd ui
pnpm i
pnpm build

Configure a provider with an HTTP or SOCKS5 proxy and open a Realtime or Responses WebSocket session. Verify traffic routes through the proxy (e.g., via proxy access logs or by pointing at a local intercepting proxy). Confirm that setting an unreachable proxy URL causes the connection to fail rather than silently connecting directly.

Breaking changes

  • No

Pool.Get, Pool.dial, Dial, and DialUpstream all gained a proxyConfig *schemas.ProxyConfig parameter. Passing nil preserves the previous direct-dial behavior.

Security considerations

Proxy credentials (Username, Password) are sourced from SecretVar and embedded into the parsed proxy URL only when both are non-empty. CA certificate PEM for proxy TLS is validated at dial time and fails fast if an env-backed secret resolves to an empty value, preventing silent misconfiguration.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • WebSocket connections now support HTTP, HTTPS, SOCKS5, and environment-based proxy settings.
    • Proxy authentication, custom certificates, and bypass rules are supported for WebSocket traffic.
    • Realtime and Responses connections consistently use configured proxy settings for direct and pooled connections.
    • Invalid or unreachable proxy configurations fail clearly without silently bypassing the proxy.
  • UI
    • Added guidance clarifying which connection types use the configured proxy, while WebRTC sessions use a separate media path.

Walkthrough

WebSocket dialing now accepts provider proxy configuration for HTTP, SOCKS5, and environment-backed proxies. Realtime and Responses handlers pass proxy settings to direct and pooled connections. Tests cover proxy configuration and tunneled WebSocket flows. The provider form documents proxy coverage.

Changes

WebSocket proxy support

Layer / File(s) Summary
Proxy configuration and validation
core/providers/utils/utils.go, core/providers/utils/proxy_test.go
Added WebSocket proxy configuration for HTTP, SOCKS5, environment-backed proxies, credentials, and custom CA settings. Added validation tests.
Proxy-aware dialing and pooling
transports/bifrost-http/websocket/connection.go, transports/bifrost-http/websocket/pool.go, transports/bifrost-http/websocket/pool_test.go
Passed proxy configuration through WebSocket dialing and pool creation. Added CONNECT proxy, message exchange, and unreachable-proxy tests.
Provider proxy propagation
transports/bifrost-http/handlers/wsrealtime.go, transports/bifrost-http/handlers/wsresponses.go
Loaded provider proxy configuration for realtime and native Responses connections.
Proxy tooling and module dependencies
Makefile, core/go.mod, framework/go.mod, plugins/*/go.mod, transports/go.mod, tests/cmd/*/go.mod
Added SOCKS5 proxy installation and launch targets. Updated module dependencies.
Proxy coverage notice
ui/app/workspace/providers/fragments/proxyFormFragment.tsx
Documented HTTP and WebSocket coverage and excluded WebRTC media sessions.

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

Sequence Diagram(s)

sequenceDiagram
  participant Handler
  participant WebSocketPool
  participant ConfigureWebSocketProxy
  participant Upstream
  Handler->>WebSocketPool: pass provider ProxyConfig
  WebSocketPool->>ConfigureWebSocketProxy: configure new dialer
  ConfigureWebSocketProxy-->>WebSocketPool: configured dialer
  WebSocketPool->>Upstream: establish WebSocket connection
  Upstream-->>Handler: return pooled connection
Loading

Possibly related PRs

  • maximhq/bifrost#5731: Both changes update the same seed module files and core dependency versions.
  • maximhq/bifrost#5756: Both changes update overlapping dependency declarations across multiple go.mod files.

Suggested reviewers: danpiths, pratham-mishra04

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: proxy support for WebSocket-based Realtime calls.
Description check ✅ Passed The description directly explains the WebSocket proxy bug, implementation, tests, UI update, and affected areas.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 08-02-add_proxy_support_for_realtime_calls_websocket_based_

Warning

Tools execution failed with the following error:

Failed to run tools: Ping-pong health check failed


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

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@akshaydeo
akshaydeo marked this pull request as ready for review August 3, 2026 06:34

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

Actionable comments posted: 2

🤖 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 `@core/providers/utils/utils.go`:
- Around line 661-665: Update the custom CA handling in the proxy configuration
flow around createTLSConfigWithCA: when TLS configuration creation fails, return
or propagate the configuration error instead of only logging it and continuing
with an unset dialer.TLSClientConfig; retain the successful path that assigns
tlsConfig to the dialer.
- Around line 635-638: The explicit HTTPProxy or Socks5Proxy path must fail
closed when proxyConfig.URL.GetValue() is empty instead of returning the direct
dialer. Update the proxy setup logic in core/providers/utils/utils.go:635-638 to
return a clear invalid-proxy-configuration error, and update the corresponding
expectations in core/providers/utils/proxy_test.go:156-170 to assert that error
rather than direct-dial behavior.
🪄 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: CHILL

Plan: Pro Plus

Run ID: f24be127-653b-4f67-963e-58cd44eb336c

📥 Commits

Reviewing files that changed from the base of the PR and between 2daaea6 and 3cacee3.

📒 Files selected for processing (8)
  • core/providers/utils/proxy_test.go
  • core/providers/utils/utils.go
  • transports/bifrost-http/handlers/wsrealtime.go
  • transports/bifrost-http/handlers/wsresponses.go
  • transports/bifrost-http/websocket/connection.go
  • transports/bifrost-http/websocket/pool.go
  • transports/bifrost-http/websocket/pool_test.go
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx

Comment thread core/providers/utils/utils.go
Comment thread core/providers/utils/utils.go
@akshaydeo
akshaydeo force-pushed the 08-02-add_proxy_support_for_realtime_calls_websocket_based_ branch from 3cacee3 to 8ff1080 Compare August 3, 2026 07:27
@akshaydeo
akshaydeo requested a review from a team as a code owner August 3, 2026 07:27
@akshaydeo
akshaydeo force-pushed the 08-02-add_proxy_support_for_realtime_calls_websocket_based_ branch from 8ff1080 to 661c00c Compare August 3, 2026 07:35

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

♻️ Duplicate comments (1)
core/providers/utils/utils.go (1)

632-639: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed instead of silently dialing direct when an explicit proxy has no URL.

For HTTPProxy and Socks5Proxy, if proxyURLValue is empty, the code logs a warning and returns dialer, nil at Line 638, leaving dialer.Proxy unset. The caller then dials directly, bypassing the configured proxy.

This is the same pattern flagged in a previous review round on these lines, which was reported as "Addressed in commit 8ff1080" with the fix of returning an error instead of falling back to direct dialing. The code shown here still contains the pre-fix behavior, so either the fix did not land on this branch or was reverted. Confirm whether the intended fix is present in this branch, and if not, reapply it.

🔒 Proposed fix
 		proxyURLValue := proxyConfig.URL.GetValue()
 		if proxyURLValue == "" {
-			getLogger().Warn("Warning: proxy URL is required for setting up WebSocket proxy")
-			return dialer, nil
+			return nil, fmt.Errorf("invalid proxy configuration: proxy URL is required for WebSocket proxy")
 		}
🤖 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 `@core/providers/utils/utils.go` around lines 632 - 639, Update the empty proxy
URL handling in the HTTPProxy and Socks5Proxy setup paths around proxyURLValue
so an explicitly configured proxy fails closed: return a descriptive error
instead of logging a warning and returning dialer with no Proxy. Preserve the
existing secret-reference validation and normal proxy setup behavior for
non-empty URLs.
🧹 Nitpick comments (1)
core/providers/utils/utils.go (1)

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

Consider sharing URL/credential-resolution logic with ConfigureProxy.

ConfigureWebSocketProxy duplicates the secret-resolution check, URL parsing, and username/password merging already present in ConfigureProxy (lines 530-553, 556-580). The doc comment at Line 614 correctly explains why the two functions differ in failure behavior (fail-fast dial func vs. direct error return), but the URL/credential-resolution portion itself does not need to differ.

Extracting a small shared helper, e.g. resolveProxyURL(proxyConfig, fieldName) (*url.URL, error), that performs the secret check, GetValue(), url.Parse, and UserPassword merge, would let both callers apply the same validation. This also reduces the risk of the two code paths drifting apart, which is part of why the fail-open regression above only affects the WebSocket path and not ConfigureProxy.

🤖 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 `@core/providers/utils/utils.go` around lines 623 - 670, Extract the duplicated
proxy URL and credential resolution from ConfigureProxy and
ConfigureWebSocketProxy into a shared helper such as resolveProxyURL, including
secret-reference validation, value retrieval, URL parsing, and username/password
merging. Update both callers to use the helper while preserving their existing
distinct error-handling behavior and the WebSocket-specific empty URL handling.
🤖 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.

Duplicate comments:
In `@core/providers/utils/utils.go`:
- Around line 632-639: Update the empty proxy URL handling in the HTTPProxy and
Socks5Proxy setup paths around proxyURLValue so an explicitly configured proxy
fails closed: return a descriptive error instead of logging a warning and
returning dialer with no Proxy. Preserve the existing secret-reference
validation and normal proxy setup behavior for non-empty URLs.

---

Nitpick comments:
In `@core/providers/utils/utils.go`:
- Around line 623-670: Extract the duplicated proxy URL and credential
resolution from ConfigureProxy and ConfigureWebSocketProxy into a shared helper
such as resolveProxyURL, including secret-reference validation, value retrieval,
URL parsing, and username/password merging. Update both callers to use the
helper while preserving their existing distinct error-handling behavior and the
WebSocket-specific empty URL handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 224caeec-5f93-4c58-a248-aa43708e01fd

📥 Commits

Reviewing files that changed from the base of the PR and between 8ff1080 and 661c00c.

⛔ Files ignored due to path filters (14)
  • core/go.sum is excluded by !**/*.sum
  • framework/go.sum is excluded by !**/*.sum
  • plugins/compat/go.sum is excluded by !**/*.sum
  • plugins/governance/go.sum is excluded by !**/*.sum
  • plugins/jsonparser/go.sum is excluded by !**/*.sum
  • plugins/logging/go.sum is excluded by !**/*.sum
  • plugins/maxim/go.sum is excluded by !**/*.sum
  • plugins/mocker/go.sum is excluded by !**/*.sum
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
  • plugins/otel/go.sum is excluded by !**/*.sum
  • plugins/prompts/go.sum is excluded by !**/*.sum
  • plugins/semanticcache/go.sum is excluded by !**/*.sum
  • plugins/telemetry/go.sum is excluded by !**/*.sum
  • transports/go.sum is excluded by !**/*.sum
📒 Files selected for processing (26)
  • Makefile
  • core/go.mod
  • core/providers/utils/proxy_test.go
  • core/providers/utils/utils.go
  • framework/go.mod
  • plugins/compat/go.mod
  • plugins/governance/go.mod
  • plugins/jsonparser/go.mod
  • plugins/logging/go.mod
  • plugins/maxim/go.mod
  • plugins/mocker/go.mod
  • plugins/modelcatalogresolver/go.mod
  • plugins/otel/go.mod
  • plugins/prompts/go.mod
  • plugins/semanticcache/go.mod
  • plugins/telemetry/go.mod
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
  • transports/bifrost-http/handlers/wsrealtime.go
  • transports/bifrost-http/handlers/wsresponses.go
  • transports/bifrost-http/websocket/connection.go
  • transports/bifrost-http/websocket/pool.go
  • transports/bifrost-http/websocket/pool_test.go
  • transports/go.mod
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
  • tests/cmd/seed/go.mod
  • transports/bifrost-http/handlers/wsrealtime.go
  • tests/cmd/seedvks/go.mod
  • transports/bifrost-http/websocket/pool.go
  • transports/bifrost-http/handlers/wsresponses.go
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • tests/cmd/e2eseed/go.mod
  • Makefile
  • transports/bifrost-http/websocket/connection.go
  • transports/bifrost-http/websocket/pool_test.go
  • core/providers/utils/proxy_test.go

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