fix(infra): redact APNs proxy URL params

This commit is contained in:
jesse-merhi
2026-05-04 02:30:40 +10:00
committed by clawsweeper
parent 6252e7b270
commit 24c08b9cd9
3 changed files with 30 additions and 4 deletions

View File

@@ -278,7 +278,7 @@ Docs: https://docs.openclaw.ai
- Slack: collapse routine Socket Mode pong-timeout reconnects into one OpenClaw reconnect line and suppress the duplicate Slack SDK pong warning.
- Gateway/diagnostics: abort-drain embedded runs after an extended no-progress stall so a single dead session no longer leaves queued Discord/channel turns blocked behind repeated `recovery=none` liveness warnings.
- Plugins/ClawHub: accept the live artifact resolver `kind`/`sha256` field names alongside the typed `artifactKind`/`artifactSha256` form so `clawhub:` installs of npm-pack and legacy ZIP packages no longer miss downloadable artifacts. Thanks @romneyda.
- Direct APNs: route direct HTTP/2 delivery through the active managed proxy so push requests honor configured egress controls, and let `openclaw proxy validate --apns-reachable` prove APNs is reachable through the proxy before deployment. (#74905) Thanks @jesse-merhi.
- Direct APNs: route direct HTTP/2 delivery through the active managed proxy with redacted proxy diagnostics, so push requests honor configured egress controls and `openclaw proxy validate --apns-reachable` can prove APNs is reachable through the proxy before deployment. (#74905) Thanks @jesse-merhi.
- Control UI/Sessions: avoid full `sessions.list` reloads for chat-turn `sessions.changed` payloads, so large session stores no longer add multi-second delays while chat responses are being delivered. (#76676) Thanks @VACInc.
- Gateway/watch: run `doctor --fix --non-interactive` once and retry when the dev Gateway child exits during startup, so stale local plugin install/config state does not leave the tmux watch session disappearing without a repair attempt.
- Doctor/Telegram: warn when selected Telegram quote replies can suppress `streaming.preview.toolProgress`, and document the `replyToMode` trade-off without changing runtime delivery. Fixes #73487. Thanks @GodsBoy.

View File

@@ -184,6 +184,34 @@ describe("openHttpConnectTunnel", () => {
expect(proxySocket.destroyed).toBe(true);
});
it("redacts proxy URL query and fragment values when CONNECT fails", async () => {
const proxySocket = new FakeSocket("HTTP/1.1 407 Proxy Authentication Required\r\n\r\n");
setNextNetSocket(proxySocket);
const { openHttpConnectTunnel } = await import("./http-connect-tunnel.js");
let caught: unknown;
try {
await openHttpConnectTunnel({
proxyUrl: "http://user:secret@proxy.example:8080/?token=hidden#fragment",
targetHost: "api.push.apple.com",
targetPort: 443,
});
} catch (err) {
caught = err;
}
expect(caught).toBeInstanceOf(Error);
if (!(caught instanceof Error)) {
throw new Error("expected CONNECT failure");
}
expect(caught.message).toBe(
"Proxy CONNECT failed via http://proxy.example:8080: HTTP/1.1 407 Proxy Authentication Required",
);
expect(caught.message).not.toContain("secret");
expect(caught.message).not.toContain("hidden");
expect(caught.message).not.toContain("fragment");
});
it("rejects malformed proxy credentials through the normal cleanup path", async () => {
const proxySocket = new FakeSocket();
setNextNetSocket(proxySocket);

View File

@@ -13,9 +13,7 @@ const MAX_CONNECT_RESPONSE_HEADER_BYTES = 16 * 1024;
function redactProxyUrl(proxyUrl: string): string {
try {
const parsed = new URL(proxyUrl);
parsed.username = "";
parsed.password = "";
return parsed.toString().replace(/\/$/, "");
return parsed.origin;
} catch {
return "<invalid proxy URL>";
}