mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
fix: honor Slack Socket Mode env proxies (#62878) (thanks @mjamiv)
This commit is contained in:
@@ -4,6 +4,10 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Fixes
|
||||
|
||||
- Slack: honor ambient HTTP(S) proxy settings for Socket Mode WebSocket connections, including NO_PROXY exclusions, so proxy-only deployments can connect without a monkey patch. (#62878) Thanks @mjamiv.
|
||||
|
||||
## 2026.4.7-1
|
||||
|
||||
### Fixes
|
||||
|
||||
@@ -85,7 +85,14 @@ describe("slack web client config", () => {
|
||||
describe("slack proxy agent", () => {
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
const PROXY_KEYS = ["HTTPS_PROXY", "HTTP_PROXY", "https_proxy", "http_proxy", "NO_PROXY", "no_proxy"];
|
||||
const PROXY_KEYS = [
|
||||
"HTTPS_PROXY",
|
||||
"HTTP_PROXY",
|
||||
"https_proxy",
|
||||
"http_proxy",
|
||||
"NO_PROXY",
|
||||
"no_proxy",
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
for (const key of PROXY_KEYS) {
|
||||
@@ -139,7 +146,17 @@ describe("slack proxy agent", () => {
|
||||
|
||||
expect(options.agent).toBeDefined();
|
||||
// HttpsProxyAgent stores the proxy URL — verify it picked the lower-case one
|
||||
expect((options.agent as { proxy: { href: string } }).proxy.href).toContain("lower.example.com");
|
||||
expect((options.agent as unknown as { proxy: { href: string } }).proxy.href).toContain(
|
||||
"lower.example.com",
|
||||
);
|
||||
});
|
||||
|
||||
it("treats empty lowercase https_proxy as authoritative over uppercase", () => {
|
||||
process.env.https_proxy = "";
|
||||
process.env.HTTPS_PROXY = "http://upper.example.com:3128";
|
||||
const options = resolveSlackWebClientOptions();
|
||||
|
||||
expect(options.agent).toBeUndefined();
|
||||
});
|
||||
|
||||
it("also applies proxy agent to write client options", () => {
|
||||
@@ -166,6 +183,14 @@ describe("slack proxy agent", () => {
|
||||
expect(options.agent).toBeUndefined();
|
||||
});
|
||||
|
||||
it("respects space-separated no_proxy entries", () => {
|
||||
process.env.HTTPS_PROXY = "http://proxy.example.com:3128";
|
||||
process.env.no_proxy = "localhost *.slack.com";
|
||||
const options = resolveSlackWebClientOptions();
|
||||
|
||||
expect(options.agent).toBeUndefined();
|
||||
});
|
||||
|
||||
it("respects NO_PROXY wildcard", () => {
|
||||
process.env.HTTPS_PROXY = "http://proxy.example.com:3128";
|
||||
process.env.NO_PROXY = "*";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type RetryOptions, type WebClientOptions, WebClient } from "@slack/web-api";
|
||||
import { HttpsProxyAgent } from "https-proxy-agent";
|
||||
import { resolveEnvHttpProxyUrl } from "openclaw/plugin-sdk/infra-runtime";
|
||||
|
||||
export const SLACK_DEFAULT_RETRY_OPTIONS: RetryOptions = {
|
||||
retries: 2,
|
||||
@@ -17,23 +18,27 @@ export const SLACK_WRITE_RETRY_OPTIONS: RetryOptions = {
|
||||
* Check whether a hostname is excluded from proxying by `NO_PROXY` / `no_proxy`.
|
||||
* Supports comma-separated entries with optional leading dots (e.g. `.slack.com`).
|
||||
*/
|
||||
function isHostExcludedByNoProxy(
|
||||
hostname: string,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
function isHostExcludedByNoProxy(hostname: string, env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
const raw = env.no_proxy ?? env.NO_PROXY;
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
const entries = raw.split(",").map((e) => e.trim().toLowerCase()).filter(Boolean);
|
||||
const entries = raw
|
||||
.split(/[,\s]+/)
|
||||
.map((e) => e.trim().toLowerCase())
|
||||
.filter(Boolean);
|
||||
const lower = hostname.toLowerCase();
|
||||
for (const entry of entries) {
|
||||
if (entry === "*") {
|
||||
return true;
|
||||
}
|
||||
// Strip optional leading dot for comparison so `.slack.com` matches both
|
||||
// `slack.com` (apex) and `wss-primary.slack.com` (subdomain).
|
||||
const bare = entry.startsWith(".") ? entry.slice(1) : entry;
|
||||
// Strip optional wildcard/leading dot so `*.slack.com` and `.slack.com`
|
||||
// match both `slack.com` (apex) and Slack subdomains.
|
||||
const bare = entry.startsWith("*.")
|
||||
? entry.slice(2)
|
||||
: entry.startsWith(".")
|
||||
? entry.slice(1)
|
||||
: entry;
|
||||
if (lower === bare || lower.endsWith(`.${bare}`)) {
|
||||
return true;
|
||||
}
|
||||
@@ -41,21 +46,6 @@ function isHostExcludedByNoProxy(
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the proxy URL from env vars following undici EnvHttpProxyAgent
|
||||
* semantics: lower-case takes precedence, HTTPS prefers https_proxy then
|
||||
* falls back to http_proxy. Returns `undefined` when no proxy is configured.
|
||||
*/
|
||||
function resolveProxyUrlFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
|
||||
return (
|
||||
env.https_proxy?.trim() ||
|
||||
env.HTTPS_PROXY?.trim() ||
|
||||
env.http_proxy?.trim() ||
|
||||
env.HTTP_PROXY?.trim() ||
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an HTTPS proxy agent from env vars (HTTPS_PROXY, HTTP_PROXY, etc.)
|
||||
* for use as the `agent` option in Slack WebClient and Socket Mode connections.
|
||||
@@ -72,7 +62,7 @@ function resolveProxyUrlFromEnv(env: NodeJS.ProcessEnv = process.env): string |
|
||||
* are excluded by `NO_PROXY`.
|
||||
*/
|
||||
function resolveSlackProxyAgent(): HttpsProxyAgent<string> | undefined {
|
||||
const proxyUrl = resolveProxyUrlFromEnv();
|
||||
const proxyUrl = resolveEnvHttpProxyUrl("https");
|
||||
if (!proxyUrl) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -81,7 +71,7 @@ function resolveSlackProxyAgent(): HttpsProxyAgent<string> | undefined {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return new HttpsProxyAgent<string>(proxyUrl);
|
||||
return new HttpsProxyAgent(proxyUrl);
|
||||
} catch {
|
||||
// Malformed proxy URL — degrade gracefully to direct connection.
|
||||
return undefined;
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -941,6 +941,9 @@ importers:
|
||||
'@slack/web-api':
|
||||
specifier: ^7.15.0
|
||||
version: 7.15.0
|
||||
https-proxy-agent:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
devDependencies:
|
||||
'@openclaw/plugin-sdk':
|
||||
specifier: workspace:*
|
||||
|
||||
Reference in New Issue
Block a user