Skip to content

feat(proxy): global and per-account outbound proxy support - #155

Open
caigee-cmd wants to merge 1 commit into
mainfrom
feat/outbound-proxy
Open

caigee-cmd wants to merge 1 commit into
mainfrom
feat/outbound-proxy

Conversation

@caigee-cmd

Copy link
Copy Markdown
Owner

Summary

Adds outbound proxy support across every account family: one global setting with a per-account override.

  • Global setting — stored in app_secrets as proxy_url, bootstrapped from QODER_PROXY_URL, editable on the System page. Validated http(s)-only (proxy.ValidateHTTPOnly) because Qoder child workers inherit it. direct / none explicitly bypass.
  • Per-account override — new SQLite migration 019_account_proxy.sql adds accounts.proxy_url. Override wins over global. Qoder account-level proxies are http(s)-only; WorkBuddy / Trae also accept socks5. Credentials are redacted in console responses, and redacted re-submits resolve back to the stored value (proxy.Preserve).
  • Qoder workersExecStarter pushes the effective proxy as HTTP(S)_PROXY + QODER_PROXY_URL; worker/src/daemon.mjs installs an undici ProxyAgent (or plain Agent for direct/none) as the global dispatcher and overrides fetch. Worker pins undici 6.21.2; deploy/Dockerfile runs npm ci.
  • WorkBuddy / Trae — in-process adapters select a Go transport from a per-client proxy.TransportCache (bounded LRU, 32 entries, evicts with CloseIdleConnections) so CONNECT tunnels are reused.
  • Reload semanticsManager.ReloadProxyURL restarts only enabled child-process accounts that inherit the global proxy; a failed reload stays pending so an identical PATCH retries. Editing an account proxy restarts that account.

New package

internal/proxy: Parse, ValidateHTTPOnly, Redact, Preserve, Effective, NewTransport/NewClient, and TransportCache.

Docs

README.md / README_EN.md / deploy/README.md document QODER_PROXY_URL. Console static assets rebuilt to match frontend/dist.

Testing

  • go build ./..., go vet ./... clean.
  • go test ./... green (new tests in internal/proxy, internal/accounts, internal/api, internal/providers/{trae,workbuddy}).

Not merging now — opening for review.

Add outbound proxy routing across every account family.

Global setting
- New internal/proxy package: Parse/ValidateHTTPOnly, Redact, Preserve,
  Effective resolution, and a bounded LRU TransportCache (32 entries,
  evicts with CloseIdleConnections).
- Global proxy stored in app_secrets as proxy_url, bootstrapped from
  QODER_PROXY_URL, editable on the System page.
- proxy.ValidateHTTPOnly keeps the global value http(s)-only because
  Qoder child workers inherit it. direct / none explicitly bypass.

Account override
- New SQLite migration 019_account_proxy.sql adds accounts.proxy_url.
- Account override wins over the global value; Qoder account-level
  proxies are http(s)-only, WorkBuddy / Trae also accept socks5.
- Proxy credentials are redacted in console responses; redacted
  re-submits are resolved back to the stored value via proxy.Preserve.

Runtime wiring
- Qoder workers: ExecStarter pushes the effective proxy as HTTP(S)_PROXY
  and QODER_PROXY_URL; worker/src/daemon.mjs installs an undici
  ProxyAgent (or a plain Agent for direct/none) as the global dispatcher.
  Worker deps pin undici 6.21.2 and deploy/Dockerfile runs npm ci.
- WorkBuddy / Trae in-process adapters pick a Go transport from a
  per-client proxy.TransportCache so CONNECT tunnels are reused.
- Manager.ReloadProxyURL restarts only enabled child-process accounts
  that inherit the global proxy; a failed reload stays pending so an
  identical PATCH retries. Account proxy edits restart that account.
- Console System page edits the global value; account create/edit forms
  edit the override.

Docs: README / README_EN / deploy/README describe QODER_PROXY_URL.
Console static assets rebuilt to match frontend/dist.
@caigee-cmd

Copy link
Copy Markdown
Owner Author

Heads-up for review: this branch is CONFLICTING against main.

  • Only conflicting file: internal/providers/workbuddy/client_test.go.
  • Underlying cause is semantic, not just textual. main (fix(workbuddy): expose deepseek-v4.1-flash via catalog alias #153) removed the WorkBuddy CLI-agent filter from Models() (so every non-disabled catalog model is exposed) and updated the test to expect 2 models. This branch instead re-adds the CLI-agent filter (and adds upstreamModelID() alias→native chat mapping), expecting 1 model.
  • Note: at the branch's base (4f530a1) the workbuddy suite was already red — fix(workbuddy): expose deepseek-v4.1-flash via catalog alias #153 removed the filter but left the ...AcceptsGlobalCLIAgentNames... test expecting 1 model. The two sides fixed that inconsistency in opposite directions.

Resolution requires picking the WorkBuddy model-exposure direction (follow main, or keep this branch's CLI-agent filter). Left unresolved deliberately — not merging anything yet.

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