Skip to content

feat: add global network proxy support#1706

Open
tctony wants to merge 2 commits into
steipete:mainfrom
tctony:feat_global_proxy_support
Open

feat: add global network proxy support#1706
tctony wants to merge 2 commits into
steipete:mainfrom
tctony:feat_global_proxy_support

Conversation

@tctony

@tctony tctony commented Jun 22, 2026

Copy link
Copy Markdown

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:// and socks5:// URLs. For an http(s):// proxy both the HTTP and HTTPS connectionProxyDictionary keys are set (nearly all provider endpoints are HTTPS).

Per-provider proxying is intentionally out of scopeURLSessionConfiguration.connectionProxyDictionary is 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 a connectionProxyDictionary.
  • ProviderHTTPClient swaps its underlying URLSession at runtime via applyProxyConfiguration(_:) (lock-guarded; old session is finishTasksAndInvalidated so in-flight requests complete). All ~95 call sites route through the shared client, so they pick it up automatically.
  • SettingsStore persists proxyEnabled / 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.
  • Preferences → Advanced gains the toggle + URL field with inline validation.
  • Localized: en, ar, fa, th, zh-Hans (other locales fall back to English per the existing locale-check policy).

Notes / limitations

  • macOS app feature; the Linux/CLI build continues to honor http_proxy/https_proxy env vars.

Test plan

  • swift build
  • swift test — new ProxyConfigurationTests (12 cases) ✅, existing ProviderHTTPClientTests
  • make check (swiftformat + swiftlint + locale check) ✅
  • Manual (verified by me on macOS): ran a local proxy on :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

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)
@clawsweeper

clawsweeper Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed June 22, 2026, 11:36 AM ET / 15:36 UTC.

Summary
The PR adds an Advanced network proxy preference, persisted proxy settings, proxy URL parsing, localized strings, tests, and runtime swapping of ProviderHTTPClient.shared's URLSession.

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.

  • Files changed: 3 added, 11 modified, 0 removed. The feature spans UI, settings persistence, localization, core HTTP transport, and tests, so review is broader than a parser-only change.
  • Persisted settings added: 2 UserDefaults keys. The new saved proxy state affects launch and upgrade behavior even though the setting is opt-in.
  • Direct session bypass surface: At least 7 constructors across 5 provider files. Current provider URLSession paths outside ProviderHTTPClient.shared are enough to contradict a global all-provider proxy claim.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted terminal output, proxy logs, or a recording showing real provider traffic routed through the proxy and disabled mode restoring direct traffic.
  • Route direct provider URLSession paths through the same proxy-aware transport or narrow the UI promise to only the covered shared-client flows.
  • [P1] Make invalid enabled proxy input fail closed or preserve the last valid proxy instead of applying direct/default networking.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body reports manual proxy testing, but it includes no inspectable terminal output, proxy logs, screenshot, recording, or linked artifact; add redacted proof and update the PR body to trigger re-review.

Risk before merge

  • [P1] Users can enable the proxy believing all provider traffic is routed while direct provider sessions can still connect outside it.
  • [P1] Invalid saved proxy input can leave the toggle enabled while applying direct/default networking.
  • [P1] The PR body reports manual testing but provides no inspectable terminal output, proxy logs, screenshot, recording, or linked artifact for the proxy boundary.
  • [P1] Prior proxy discussion asked for authentication and credential-storage scope plus end-to-end proof; this PR intentionally excludes authentication and still needs maintainer scope approval.

Maintainer options:

  1. Require proxy boundary fixes before merge (recommended)
    Route direct provider URLSession paths through a proxy-aware factory or shared transport, and make invalid enabled input fail closed or retain the last valid proxy.
  2. Narrow the exposed proxy scope
    If maintainers only want shared-client traffic covered, change the UI, tests, and PR description to name that narrower scope and remove all-provider language.
  3. Pause for proxy product scope
    Pause or close this PR if proxy authentication and credential storage are prerequisites before CodexBar exposes a global network proxy control.

Next step before merge

  • [P1] This needs contributor proof and maintainer decisions on coverage, fail-open behavior, and authentication scope before automated repair is safe.

Security
Needs attention: The diff introduces a proxy boundary control that can be bypassed by direct provider sessions and invalid enabled proxy input.

Review findings

  • [P1] Route every provider session through the proxy — Sources/CodexBar/ProxyConfigurator.swift:27
  • [P1] Avoid failing open on invalid proxy URLs — Sources/CodexBar/ProxyConfigurator.swift:15
Review details

Best 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:

  • [P1] Route every provider session through the proxy — Sources/CodexBar/ProxyConfigurator.swift:27
    ProxyConfigurator only applies the setting to ProviderHTTPClient.shared, but current provider code still constructs direct URLSession instances in paths such as Alibaba Token Plan, Amp, OpenCodeGo, Ollama, and Antigravity. Those requests can bypass the new setting while the UI says all provider requests are routed through the proxy.
    Confidence: 0.91
  • [P1] Avoid failing open on invalid proxy URLs — Sources/CodexBar/ProxyConfigurator.swift:15
    When proxying is enabled and the saved URL is non-empty but invalid, resolve returns nil and apply rebuilds the client as a default/direct session. A mistyped proxy should not silently send provider traffic outside the user's configured network boundary.
    Confidence: 0.89

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against ef8007fc16ce.

Label changes

Label justifications:

  • P2: This is a normal-priority feature PR with limited default blast radius, but it affects provider-network behavior when users opt in.
  • merge-risk: 🚨 security-boundary: The proxy preference is a network boundary control, and the current diff can bypass it through direct provider sessions and invalid enabled input.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body reports manual proxy testing, but it includes no inspectable terminal output, proxy logs, screenshot, recording, or linked artifact; add redacted proof and update the PR body to trigger re-review.
Evidence reviewed

Security concerns:

  • [medium] Provider traffic can bypass the proxy control — Sources/CodexBar/ProxyConfigurator.swift:27
    Only the shared ProviderHTTPClient receives the proxy configuration, while existing provider-specific URLSession instances remain outside that setting.
    Confidence: 0.91
  • [medium] Invalid enabled proxy can fail open — Sources/CodexBar/ProxyConfigurator.swift:15
    Invalid non-empty proxy input is treated as nil and applied as direct/default networking, so provider requests can bypass the proxy while the feature remains enabled.
    Confidence: 0.89

What I checked:

Likely related people:

  • steipete: Provided prior proxy-scope guidance, merged/refactored the shared ProviderHTTPClient seam, and authored recent provider networking fixes in adjacent Amp, Ollama, and Antigravity areas. (role: recent reviewer and area contributor; confidence: high; commits: 2aecbfe3dfb6, f380287041b8, ae159ec81f18; files: Sources/CodexBarCore/ProviderHTTPClient.swift, Sources/CodexBar/PreferencesAdvancedPane.swift, Sources/CodexBarCore/Providers/Amp/AmpUsageFetcher.swift)
  • serezha93: Introduced the shared provider HTTP client seam and authored earlier proxy-support branches that shaped the current proxy design discussion. (role: feature-history contributor; confidence: high; commits: a1467f533568, 62b55e96e675, a9eeef83cc61; files: Sources/CodexBarCore/ProviderHTTPClient.swift, Sources/CodexBarCore/Config/NetworkProxyConfiguration.swift)
  • YanxinXue: Introduced and revised Alibaba Token Plan, one of the current direct-URLSession provider paths the global proxy would need to cover or exclude. (role: adjacent provider owner; confidence: medium; commits: dbc28ab99554, 54b8d8324e4a; files: Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanUsageFetcher.swift)
  • duailibe: Introduced the Amp provider path, which still contains direct URLSession construction relevant to the proxy coverage gap. (role: adjacent provider owner; confidence: medium; commits: 7c1d0a2bc987, e680a09ff848; files: Sources/CodexBarCore/Providers/Amp/AmpUsageFetcher.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

should this be fix by provider side?

Comment on lines +37 to +41
TextField(L("proxy_url_placeholder"), text: self.$settings.proxyURL)
.textFieldStyle(.roundedBorder)
.disableAutocorrection(true)
.disabled(!self.settings.proxyEnabled)
.onSubmit { ProxyConfigurator.apply(from: self.settings) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed in commit 10c153e

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Jun 22, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant