Skip to content

fix(slack): honor HTTPS_PROXY for Socket Mode WebSocket connections#62878

Merged
steipete merged 4 commits intoopenclaw:mainfrom
mjamiv:fix/slack-socket-mode-proxy-support
Apr 8, 2026
Merged

fix(slack): honor HTTPS_PROXY for Socket Mode WebSocket connections#62878
steipete merged 4 commits intoopenclaw:mainfrom
mjamiv:fix/slack-socket-mode-proxy-support

Conversation

@mjamiv
Copy link
Copy Markdown
Contributor

@mjamiv mjamiv commented Apr 8, 2026

Summary

Slack Socket Mode ignores HTTPS_PROXY/HTTP_PROXY env vars — the ws library opens a direct WebSocket connection to wss-primary.slack.com, bypassing any configured proxy. This breaks Socket Mode in proxy-only environments (sandboxed containers, corporate networks, NVIDIA OpenShell).

This PR creates an HttpsProxyAgent from proxy env vars and passes it as the agent option through @slack/bolt@slack/socket-modeSlackWebSocketws, so the WebSocket upgrade request is tunneled through the HTTP CONNECT proxy.

Changes

  • extensions/slack/src/client.ts: resolveSlackWebClientOptions() and resolveSlackWriteClientOptions() now set agent to an HttpsProxyAgent when HTTPS_PROXY/HTTP_PROXY env vars are present. Follows undici EnvHttpProxyAgent semantics (lower-case takes precedence).
  • extensions/slack/package.json: Added https-proxy-agent dependency (same version as Discord extension).
  • extensions/slack/src/client.test.ts: Tests for proxy agent creation, env var precedence, explicit agent override, and no-op when no proxy is configured.

How it works

The agent flows through:

  1. resolveSlackWebClientOptions(){ agent: HttpsProxyAgent }
  2. new App({ clientOptions }) (Bolt)
  3. new SocketModeReceiver({ clientOptions })new SocketModeClient({ clientOptions })
  4. SlackWebSocket({ httpAgent: clientOptions.agent })
  5. new ws.WebSocket(url, { agent: httpAgent }) — tunneled through proxy ✅

Prior art

Mirrors the existing Discord gateway proxy support in extensions/discord/src/monitor/gateway-plugin.ts, which uses the same https-proxy-agent library.

Production validation

We've been running an equivalent monkey-patch (openclaw-ws-proxy-patch.js) across 4 OpenClaw agents on NVIDIA OpenShell sandboxes since March 2026, routing all Slack Socket Mode traffic through an HTTP CONNECT proxy at 10.200.0.1:3128. This PR replaces that workaround with a proper fix.

Fixes #57405

Test plan

  • HTTPS_PROXY set → Socket Mode connects through proxy
  • No proxy env vars → Socket Mode connects directly (no behavior change)
  • Explicit clientOptions.agent → not overridden by proxy detection
  • HTTP_PROXY fallback when HTTPS_PROXY not set
  • Lower-case https_proxy takes precedence over upper-case HTTPS_PROXY
  • Unit tests pass: extensions/slack/src/client.test.ts

@openclaw-barnacle openclaw-barnacle Bot added channel: slack Channel integration: slack size: S labels Apr 8, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR fixes Slack Socket Mode ignoring proxy env vars by creating an HttpsProxyAgent from HTTPS_PROXY/HTTP_PROXY and passing it as the agent option through Bolt → @slack/socket-modews. The change is well-scoped, correctly uses ?? to preserve any explicit agent override, and mirrors the existing Discord gateway proxy pattern.

Confidence Score: 5/5

Safe to merge; the only finding is a P2 gap where NO_PROXY exclusions are not honored, which doesn't affect the primary use case.

All findings are P2. The proxy detection and agent wiring are correct for the stated goal (proxy-only environments). The NO_PROXY gap is a completeness concern, not a present breakage for the target users.

extensions/slack/src/client.ts — resolveSlackProxyAgent does not check NO_PROXY/no_proxy.

Vulnerabilities

No security concerns identified. Proxy URL is read from standard env vars, not user input, and HttpsProxyAgent does its own URL parsing without eval or command injection risk.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/slack/src/client.ts
Line: 27-40

Comment:
**`NO_PROXY` not honored**

`HttpsProxyAgent` does not respect the `NO_PROXY` / `no_proxy` exclusion list, so any host matched by `NO_PROXY` would still be tunneled through the proxy. The PR description claims undici `EnvHttpProxyAgent` semantics, but `EnvHttpProxyAgent` is the component that handles `NO_PROXY` exclusions — `HttpsProxyAgent` alone does not.

The core uses `EnvHttpProxyAgent` (via `resolveProxyFetchFromEnv` in `src/infra/net/proxy-fetch.ts`) precisely because it handles `NO_PROXY`. For the WebSocket `agent` slot that `ws` requires, consider checking `NO_PROXY` / `no_proxy` before constructing the agent and short-circuiting to `undefined` when the target host is excluded. Alternatively, document explicitly that `NO_PROXY` is not respected for Socket Mode connections.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(slack): honor HTTPS_PROXY for Socket..." | Re-trigger Greptile

Comment on lines +27 to +40
function resolveSlackProxyAgent(): HttpsProxyAgent<string> | undefined {
// Match undici EnvHttpProxyAgent semantics: lower-case takes precedence,
// HTTPS prefers https_proxy then falls back to http_proxy.
const proxyUrl =
process.env.https_proxy?.trim() ||
process.env.HTTPS_PROXY?.trim() ||
process.env.http_proxy?.trim() ||
process.env.HTTP_PROXY?.trim() ||
undefined;
if (!proxyUrl) {
return undefined;
}
return new HttpsProxyAgent<string>(proxyUrl);
}
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.

P2 NO_PROXY not honored

HttpsProxyAgent does not respect the NO_PROXY / no_proxy exclusion list, so any host matched by NO_PROXY would still be tunneled through the proxy. The PR description claims undici EnvHttpProxyAgent semantics, but EnvHttpProxyAgent is the component that handles NO_PROXY exclusions — HttpsProxyAgent alone does not.

The core uses EnvHttpProxyAgent (via resolveProxyFetchFromEnv in src/infra/net/proxy-fetch.ts) precisely because it handles NO_PROXY. For the WebSocket agent slot that ws requires, consider checking NO_PROXY / no_proxy before constructing the agent and short-circuiting to undefined when the target host is excluded. Alternatively, document explicitly that NO_PROXY is not respected for Socket Mode connections.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/slack/src/client.ts
Line: 27-40

Comment:
**`NO_PROXY` not honored**

`HttpsProxyAgent` does not respect the `NO_PROXY` / `no_proxy` exclusion list, so any host matched by `NO_PROXY` would still be tunneled through the proxy. The PR description claims undici `EnvHttpProxyAgent` semantics, but `EnvHttpProxyAgent` is the component that handles `NO_PROXY` exclusions — `HttpsProxyAgent` alone does not.

The core uses `EnvHttpProxyAgent` (via `resolveProxyFetchFromEnv` in `src/infra/net/proxy-fetch.ts`) precisely because it handles `NO_PROXY`. For the WebSocket `agent` slot that `ws` requires, consider checking `NO_PROXY` / `no_proxy` before constructing the agent and short-circuiting to `undefined` when the target host is excluded. Alternatively, document explicitly that `NO_PROXY` is not respected for Socket Mode connections.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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: 071c7da815

ℹ️ 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".

Comment thread extensions/slack/src/client.ts Outdated
Comment on lines +31 to +34
process.env.https_proxy?.trim() ||
process.env.HTTPS_PROXY?.trim() ||
process.env.http_proxy?.trim() ||
process.env.HTTP_PROXY?.trim() ||
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 Treat empty lowercase proxy vars as authoritative

Use lower-case proxy env vars as authoritative even when they are intentionally blank. With the current || chain, https_proxy="" (or whitespace) falls back to HTTPS_PROXY, which contradicts the repo’s documented EnvHttpProxyAgent-style precedence and can unexpectedly force Slack traffic through a proxy that operators explicitly disabled for this process.

Useful? React with 👍 / 👎.

Comment thread extensions/slack/src/client.ts Outdated
if (!proxyUrl) {
return undefined;
}
return new HttpsProxyAgent<string>(proxyUrl);
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 Guard proxy agent creation against malformed env URLs

Handle invalid proxy env values defensively before constructing the agent. new HttpsProxyAgent(proxyUrl) is called without validation or a fallback path, so a malformed HTTPS_PROXY/HTTP_PROXY value can fail option resolution during startup and prevent the Slack channel from initializing, whereas this path should degrade gracefully to direct connectivity.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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

ℹ️ 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".

Comment thread extensions/slack/src/client.ts Outdated
return true;
}
// Exact match or suffix match (with leading dot)
if (lower === entry || lower.endsWith(entry.startsWith(".") ? entry : `.${entry}`)) {
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 Honor leading-dot NO_PROXY for apex slack.com

Treating a leading-dot entry as a pure suffix check misses the apex host: with NO_PROXY=.slack.com, resolveSlackProxyAgent() checks isHostExcludedByNoProxy("slack.com"), but "slack.com".endsWith(".slack.com") is false, so the proxy agent is still applied. This breaks a common exclusion pattern and can force Slack traffic through a proxy even when operators explicitly excluded the Slack domain.

Useful? React with 👍 / 👎.

mjamiv and others added 4 commits April 8, 2026 05:34
When HTTPS_PROXY or HTTP_PROXY env vars are set, create an
HttpsProxyAgent and pass it as the `agent` option through
@slack/bolt → @slack/socket-mode → ws, so the WebSocket upgrade
request is tunneled through the proxy.

This fixes Slack Socket Mode in environments where all outbound
traffic must go through an HTTP CONNECT proxy (e.g. sandboxed
containers, corporate networks). Previously the ws library opened
a direct connection to wss-primary.slack.com, ignoring proxy env
vars entirely.

The approach mirrors the existing Discord gateway proxy support
(extensions/discord/src/monitor/gateway-plugin.ts) which uses the
same https-proxy-agent library.

Fixes openclaw#57405
- Check NO_PROXY/no_proxy before creating HttpsProxyAgent; skip proxy
  when slack.com matches an exclusion entry (exact, suffix, or wildcard).
- Wrap HttpsProxyAgent construction in try/catch so malformed proxy URLs
  degrade to direct connectivity instead of crashing Slack channel init.
- Extract resolveProxyUrlFromEnv and isHostExcludedByNoProxy as testable
  helpers.
- Add tests for NO_PROXY exclusion, wildcard, unrelated hosts, and
  malformed URL resilience.
`.slack.com` in NO_PROXY should match both `slack.com` (apex) and
`wss-primary.slack.com` (subdomain). Strip the leading dot before
comparison so the suffix check works for both cases.
@steipete steipete force-pushed the fix/slack-socket-mode-proxy-support branch from bf16be9 to fb32cf8 Compare April 8, 2026 04:38
@steipete steipete merged commit b4034b3 into openclaw:main Apr 8, 2026
9 checks passed
@steipete
Copy link
Copy Markdown
Contributor

steipete commented Apr 8, 2026

Landed via temp rebase onto main.

  • Gate: pnpm test extensions/slack/src/client.test.ts; committer pre-commit gate (pnpm check)
  • Land commit: fb32cf822b4bf9680eb216ece32eca1a093c9d89
  • Merge commit: b4034b32c365c69db0d5ad7ff649bc9920842f40

Thanks @mjamiv!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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

ℹ️ 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".

return undefined;
}
// Slack Socket Mode connects to these hosts; skip proxy if excluded.
if (isHostExcludedByNoProxy("slack.com")) {
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 Evaluate NO_PROXY against Socket Mode hostnames

resolveSlackProxyAgent() only checks NO_PROXY against the apex slack.com, but Socket Mode WebSockets connect to concrete hosts like wss-primary.slack.com / wss-backup.slack.com. When operators use targeted exclusions such as NO_PROXY=wss-primary.slack.com, this condition never matches, so we still attach HttpsProxyAgent and force the WebSocket through the proxy unexpectedly. That can break connectivity in environments that rely on host-specific bypass rules.

Useful? React with 👍 / 👎.

ericksoa pushed a commit to NVIDIA/NemoClaw that referenced this pull request Apr 22, 2026
The Discord extension's gateway plugin relies on @buape/carbon via ws,
which doesn't honour HTTPS_PROXY and opens a direct TCP socket to
gateway.discord.gg. The sandbox netns blocks direct egress, so the WSS
handshake never reaches Discord and the bot loops on close-code 1006.
DiscordAccountConfig already exposes a first-class proxy field that the
gateway plugin threads through to the ws agent option, so extending the
existing Telegram bake to Discord is enough to route the upgrade through
the OpenShell proxy. The pattern precedent for this NemoClaw-side
workaround is openclaw/openclaw#62878 (Slack Socket Mode),
openclaw/openclaw#61541 (WhatsApp), and openclaw/openclaw#41835 (Feishu)
— each a mirror of the same ignores-env-vars footgun in a different
channel's client lib. Remove once OpenClaw lands an equivalent env-var-
honouring fix for the Discord gateway.

Fixes #1738

<!-- markdownlint-disable MD041 -->
## Summary
<!-- 1-3 sentences: what this PR does and why. -->

## Related Issue
<!-- Fixes #NNN or Closes #NNN. Remove this section if none. -->

## Changes
<!-- Bullet list of key changes. -->

## Type of Change

- [X] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification
<!-- Check each item you ran and confirmed. Leave unchecked items you
skipped. -->
- [X] `npx prek run --all-files` passes
- [X] `npm test` passes
- [ ] Tests added or updated for new or changed behavior
- [ ] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

## AI Disclosure
<!-- If an AI agent authored or co-authored this PR, check the box and
name the tool. Remove this section for fully human-authored PRs. -->
- [X] AI-assisted — tool: Claude Code<!-- e.g., Claude Code, Cursor,
GitHub Copilot -->

---
<!-- DCO sign-off required by CI. Run: git config user.name && git
config user.email -->
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Discord proxy routing is now aligned with Telegram's proxy routing
configuration.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: slack Channel integration: slack size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slack Socket Mode WebSocket connections don't honor HTTPS_PROXY

2 participants