Gateway: install global proxy dispatcher before channels start#33990
Gateway: install global proxy dispatcher before channels start#33990gallexy-liu wants to merge 7 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e83f3d5d33
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| for (const acct of Object.values(telegramAccounts)) { | ||
| const p = (acct as { proxy?: string })?.proxy?.trim(); | ||
| if (p) { | ||
| return p; |
There was a problem hiding this comment.
Skip disabled accounts when picking the global proxy
Proxy selection currently takes the first account proxy regardless of whether that account is disabled, so a stale proxy on channels.telegram.accounts.<id>.proxy or channels.discord.accounts.<id>.proxy can hijack the process-wide dispatcher even when the active account uses a different proxy (or none). In multi-account setups this can break all global fetch traffic based on config order rather than enabled runtime accounts.
Useful? React with 👍 / 👎.
| }), | ||
| ); | ||
| applied = true; | ||
| log.info(`global proxy dispatcher set: ${proxyUrl}${isWsl2 ? " (wsl2 ipv4-only)" : ""}`); |
There was a problem hiding this comment.
Redact proxy credentials from startup logs
This info log prints the full proxy URL, which commonly includes inline credentials (for example http://user:pass@proxy:port). As written, authenticated proxy secrets are emitted to console/file logs whenever startup succeeds, creating avoidable credential exposure in environments where logs are shared or persisted.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR fixes a proxy routing bug where third-party libraries (e.g., Implementation is sound:
Security concern:
Confidence Score: 4/5
Last reviewed commit: e83f3d5 |
| }), | ||
| ); | ||
| applied = true; | ||
| log.info(`global proxy dispatcher set: ${proxyUrl}${isWsl2 ? " (wsl2 ipv4-only)" : ""}`); |
There was a problem hiding this comment.
Proxy credentials exposed in logs
proxyUrl is logged verbatim at line 117. Proxy URLs can include credentials in their userinfo component, which would be written in plaintext to log files and aggregators.
Consider stripping the userinfo before logging. You can parse the URL with new URL(proxyUrl), clear username and password, then stringify and log the sanitized result:
const url = new URL(proxyUrl);
url.username = "";
url.password = "";
log.info(`global proxy dispatcher set: ${url.toString()}${isWsl2 ? " (wsl2 ipv4-only)" : ""}`);Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-global-proxy.ts
Line: 117
Comment:
Proxy credentials exposed in logs
`proxyUrl` is logged verbatim at line 117. Proxy URLs can include credentials in their userinfo component, which would be written in plaintext to log files and aggregators.
Consider stripping the userinfo before logging. You can parse the URL with `new URL(proxyUrl)`, clear `username` and `password`, then stringify and log the sanitized result:
```typescript
const url = new URL(proxyUrl);
url.username = "";
url.password = "";
log.info(`global proxy dispatcher set: ${url.toString()}${isWsl2 ? " (wsl2 ipv4-only)" : ""}`);
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f6f46e914a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const telegramProxy = cfg.channels?.telegram?.proxy?.trim(); | ||
| if (telegramProxy) { | ||
| return telegramProxy; |
There was a problem hiding this comment.
Skip disabled channels when selecting global proxy
resolveFirstChannelProxy returns channel-level proxy URLs without checking whether that channel is enabled, so applyGlobalProxyDispatcher can install a proxy from channels.telegram.proxy (and similarly channels.discord.proxy) even when channels.<name>.enabled is false. In that configuration, all process-wide globalThis.fetch traffic gets forced through a proxy for a channel that is intentionally off, which can break unrelated outbound requests if that proxy is stale or unreachable.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 41cde4521d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // Third-party libs (e.g. @buape/carbon) use globalThis.fetch which does not | ||
| // honor HTTP_PROXY env vars; this ensures all outbound fetch() calls route | ||
| // through the proxy configured in any channel (e.g. Telegram, Discord). | ||
| applyGlobalProxyDispatcher(params.cfg); |
There was a problem hiding this comment.
Skip global proxy install when channels are disabled
applyGlobalProxyDispatcher(params.cfg) now runs even when OPENCLAW_SKIP_CHANNELS=1/OPENCLAW_SKIP_PROVIDERS=1, so provider-only/test runs that intentionally skip channels still inherit a channel proxy from channels.telegram.proxy/channels.discord.proxy. In that mode, all process-wide fetch traffic can be forced through a stale or unreachable channel proxy, causing unrelated startup/network failures despite channels being explicitly disabled.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3fa41fe1ee
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (telegramAccounts) { | ||
| for (const acct of Object.values(telegramAccounts)) { | ||
| const account = acct as { enabled?: boolean; proxy?: string }; | ||
| if (account.enabled !== false) { |
There was a problem hiding this comment.
Exclude tokenless accounts from global proxy selection
This selector only checks enabled, so an account with a proxy but no credentials can still become the process-wide dispatcher. In practice, tokenless Telegram/Discord accounts are not runnable (for example src/telegram/monitor.ts throws when token is empty), so a stale proxy on an unconfigured account can hijack all globalThis.fetch traffic before channels start and break outbound calls for the actually configured accounts.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e2780c61e7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // Skip disabled channels (enabled defaults to true when not set) | ||
| if (telegram && telegram.enabled !== false) { | ||
| // Top-level telegram config has credentials → use its proxy | ||
| if (hasTelegramToken(telegram)) { |
There was a problem hiding this comment.
Resolve credentials via token resolvers before proxy selection
resolveFirstChannelProxy gates top-level proxy use on hasTelegramToken/hasDiscordToken, which only inspects raw config fields and ignores supported env-token paths (TELEGRAM_BOT_TOKEN, DISCORD_BOT_TOKEN). In configs that rely on env credentials but set channels.telegram.proxy or channels.discord.proxy, this function returns no proxy and applyGlobalProxyDispatcher is skipped, so globalThis.fetch still bypasses the proxy and the connectivity failure this change targets remains reproducible.
Useful? React with 👍 / 👎.
| tokenFile?: string; | ||
| }; | ||
| if (account.enabled !== false && hasTelegramToken(account)) { | ||
| const p = account.proxy?.trim(); |
There was a problem hiding this comment.
Fall back to channel-level proxy for credentialed accounts
The account loops only consider account.proxy, but runtime account config is merged as {...channelBase, ...account} in src/telegram/accounts.ts and src/discord/accounts.ts, so a common setup (channels.<name>.proxy at top level, token on accounts.<id>) is valid at runtime yet invisible here. In that case resolveFirstChannelProxy returns undefined, preventing global dispatcher installation and leaving third-party fetch traffic unproxied.
Useful? React with 👍 / 👎.
|
The three failing CI jobs are unrelated to the changes in this PR: checks-windows / macos: src/plugin-sdk/root-alias.test.ts times out. This file was introduced by upstream commit 5c4ab99 ("Plugins/zalouser: migrate to scoped plugin-sdk imports") which is not yet in my fork's base. The timeout appears to be a pre-existing flaky test on the upstream main branch. |
|
This pull request has been automatically marked as stale due to inactivity. |
|
Closing due to inactivity. |
Summary
channels.discord.proxy/channels.telegram.proxy), third-party libraries like@buape/carbonuseglobalThis.fetchwhich ignoresHTTP_PROXYenv vars and the per-channel proxy config, causingTypeError: fetch failedon restricted networks (e.g. WSL2 + GFW).src/gateway/server-global-proxy.tswhich installs aProxyAgentas the global undici dispatcher before channels start, so allglobalThis.fetchcalls in the gateway process route through the configured proxy. Updatedsrc/telegram/fetch.tsto skip overwriting the dispatcher if a proxy dispatcher is already installed.HttpsProxyAgent, REST proxy via per-channelProxyAgent.Change Type
Scope