feat: add global network proxy support#1706
Conversation
Add an opt-in global proxy that routes all provider traffic through a user-configured HTTP/HTTPS/SOCKS5 endpoint. - ProxyConfiguration parses a proxy URL into a connectionProxyDictionary - ProviderHTTPClient swaps its URLSession at runtime via applyProxyConfiguration - SettingsStore persists proxyEnabled/proxyURL; ProxyConfigurator bridges them into the shared client on launch and on change - Preferences > Advanced gains a Network proxy toggle + URL field with validation - Localized strings (en, ar, fa, th, zh-Hans)
|
Codex review: needs real behavior proof before merge. Reviewed June 22, 2026, 11:36 AM ET / 15:36 UTC. Summary Reproducibility: yes. Source inspection shows current-main provider fetchers still create direct URLSessions outside ProviderHTTPClient.shared, and the PR resolves invalid enabled proxy input to nil/direct behavior. Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Land proxy support only after maintainers approve the scope, every provider network path is covered or explicitly excluded in the UI, invalid enabled input cannot silently bypass the proxy, and redacted end-to-end proof is attached. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current-main provider fetchers still create direct URLSessions outside ProviderHTTPClient.shared, and the PR resolves invalid enabled proxy input to nil/direct behavior. Is this the best way to solve the issue? No. The shared-client session swap is a useful starting point, but the safest solution must either cover every provider session or narrow the UI promise, and it must not fail open on invalid enabled proxy settings. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against ef8007fc16ce. Label changesLabel justifications:
Evidence reviewedSecurity concerns:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b75d560baa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| /// Applies the current settings to the shared HTTP client. | ||
| static func apply(from settings: SettingsStore) { | ||
| ProviderHTTPClient.shared.applyProxyConfiguration(self.resolve(from: settings)) |
There was a problem hiding this comment.
Route direct provider sessions through the proxy
This only updates ProviderHTTPClient.shared, but repo-wide URLSession call sites show provider paths that instantiate their own sessions, such as Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanUsageFetcher.swift:88 and Sources/CodexBarCore/Providers/Amp/AmpUsageFetcher.swift:157. When those providers are enabled, their network requests bypass the configured app proxy, so the advertised global proxy does not actually cover all provider traffic; route these sessions through a proxy-aware factory/client as well.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
should this be fix by provider side?
| TextField(L("proxy_url_placeholder"), text: self.$settings.proxyURL) | ||
| .textFieldStyle(.roundedBorder) | ||
| .disableAutocorrection(true) | ||
| .disabled(!self.settings.proxyEnabled) | ||
| .onSubmit { ProxyConfigurator.apply(from: self.settings) } |
There was a problem hiding this comment.
Apply proxy changes when editing finishes
With the switch already enabled, editing this field only persists settings.proxyURL; the active ProviderHTTPClient is rebuilt only if the user presses Return. In the common flow of enabling the checkbox, typing a URL, then closing preferences or tabbing/clicking away, traffic continues using the previous/direct session even though the UI shows the new enabled proxy URL.
Useful? React with 👍 / 👎.
Editing the proxy URL field then clicking/tabbing away (or closing Preferences) without pressing Return left the live ProviderHTTPClient on the old session. Apply on focus loss and on disappear too; dedupe in ProxyConfigurator so the extra calls only rebuild the session when the resolved configuration actually changes.
Summary
Adds an opt-in global proxy so all provider traffic can be routed through a user-configured proxy (corporate proxy, mitmproxy/Charles for inspection, etc.). Configured in Preferences → Advanced → Network proxy: a checkbox plus a single proxy-URL field.
Supports
http://,https://andsocks5://URLs. For anhttp(s)://proxy both the HTTP and HTTPSconnectionProxyDictionarykeys are set (nearly all provider endpoints are HTTPS).Per-provider proxying is intentionally out of scope —
URLSessionConfiguration.connectionProxyDictionaryis per-session, not per-request, so it would require a provider→session registry refactor. Proxy authentication is also out of scope (no credentials).How it works
ProxyConfiguration(CodexBarCore) parses/validates a proxy URL into aconnectionProxyDictionary.ProviderHTTPClientswaps its underlyingURLSessionat runtime viaapplyProxyConfiguration(_:)(lock-guarded; old session isfinishTasksAndInvalidated so in-flight requests complete). All ~95 call sites route through the shared client, so they pick it up automatically.SettingsStorepersistsproxyEnabled/proxyURL;ProxyConfigurator(app) resolves them and applies on launch, on toggle, when the URL field finishes editing (focus loss / submit), and on pane disappear. It dedupes so the session is only rebuilt when the resolved config actually changes.Notes / limitations
http_proxy/https_proxyenv vars.Test plan
swift build✅swift test— newProxyConfigurationTests(12 cases) ✅, existingProviderHTTPClientTests✅make check(swiftformat + swiftlint + locale check) ✅:9000, enabled the proxy in Preferences → Advanced, and confirmed provider requests were routed through the proxy (visible in the proxy log); disabling it restored direct connections. Also verified the URL applies when editing finishes without pressing Return.🤖 Generated with Claude Code