From be9aa5494a1f19b466e2f2c8138e77f5bd4667df Mon Sep 17 00:00:00 2001 From: Ivan Pereira Date: Fri, 16 Jan 2026 13:19:55 +0000 Subject: [PATCH 1/2] fix(security): resolve local auth for gateway probe --- src/security/audit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/security/audit.ts b/src/security/audit.ts index 88a594b87..6e8897980 100644 --- a/src/security/audit.ts +++ b/src/security/audit.ts @@ -538,7 +538,7 @@ async function maybeProbeGateway(params: { return { token, password }; }; - const auth = remoteUrlMissing ? resolveAuth("local") : resolveAuth("remote"); + const auth = !isRemoteMode || remoteUrlMissing ? resolveAuth("local") : resolveAuth("remote"); const res = await params.probe({ url, auth, timeoutMs: params.timeoutMs }).catch((err) => ({ ok: false, url, From 544ca062a3e5941ea330c60c285dae33d19d5be4 Mon Sep 17 00:00:00 2001 From: Ivan Pereira Date: Fri, 16 Jan 2026 13:31:01 +0000 Subject: [PATCH 2/2] test(security): add coverage for gateway probe auth selection --- src/security/audit.test.ts | 144 +++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/src/security/audit.test.ts b/src/security/audit.test.ts index fd02f208f..60dd00a5f 100644 --- a/src/security/audit.test.ts +++ b/src/security/audit.test.ts @@ -401,4 +401,148 @@ describe("security audit", () => { ]), ); }); + + describe("maybeProbeGateway auth selection", () => { + it("uses local auth when gateway.mode is local", async () => { + let capturedAuth: { token?: string; password?: string } | undefined; + const cfg: ClawdbotConfig = { + gateway: { + mode: "local", + auth: { token: "local-token-abc123" }, + }, + }; + + await runSecurityAudit({ + config: cfg, + deep: true, + deepTimeoutMs: 50, + includeFilesystem: false, + includeChannelSecurity: false, + probeGatewayFn: async (opts) => { + capturedAuth = opts.auth; + return { + ok: true, + url: opts.url, + connectLatencyMs: 10, + error: null, + close: null, + health: null, + status: null, + presence: null, + configSnapshot: null, + }; + }, + }); + + expect(capturedAuth?.token).toBe("local-token-abc123"); + }); + + it("uses local auth when gateway.mode is undefined (default)", async () => { + let capturedAuth: { token?: string; password?: string } | undefined; + const cfg: ClawdbotConfig = { + gateway: { + auth: { token: "default-local-token" }, + }, + }; + + await runSecurityAudit({ + config: cfg, + deep: true, + deepTimeoutMs: 50, + includeFilesystem: false, + includeChannelSecurity: false, + probeGatewayFn: async (opts) => { + capturedAuth = opts.auth; + return { + ok: true, + url: opts.url, + connectLatencyMs: 10, + error: null, + close: null, + health: null, + status: null, + presence: null, + configSnapshot: null, + }; + }, + }); + + expect(capturedAuth?.token).toBe("default-local-token"); + }); + + it("uses remote auth when gateway.mode is remote with URL", async () => { + let capturedAuth: { token?: string; password?: string } | undefined; + const cfg: ClawdbotConfig = { + gateway: { + mode: "remote", + auth: { token: "local-token-should-not-use" }, + remote: { + url: "ws://remote.example.com:18789", + token: "remote-token-xyz789", + }, + }, + }; + + await runSecurityAudit({ + config: cfg, + deep: true, + deepTimeoutMs: 50, + includeFilesystem: false, + includeChannelSecurity: false, + probeGatewayFn: async (opts) => { + capturedAuth = opts.auth; + return { + ok: true, + url: opts.url, + connectLatencyMs: 10, + error: null, + close: null, + health: null, + status: null, + presence: null, + configSnapshot: null, + }; + }, + }); + + expect(capturedAuth?.token).toBe("remote-token-xyz789"); + }); + + it("falls back to local auth when gateway.mode is remote but URL is missing", async () => { + let capturedAuth: { token?: string; password?: string } | undefined; + const cfg: ClawdbotConfig = { + gateway: { + mode: "remote", + auth: { token: "fallback-local-token" }, + remote: { + token: "remote-token-should-not-use", + }, + }, + }; + + await runSecurityAudit({ + config: cfg, + deep: true, + deepTimeoutMs: 50, + includeFilesystem: false, + includeChannelSecurity: false, + probeGatewayFn: async (opts) => { + capturedAuth = opts.auth; + return { + ok: true, + url: opts.url, + connectLatencyMs: 10, + error: null, + close: null, + health: null, + status: null, + presence: null, + configSnapshot: null, + }; + }, + }); + + expect(capturedAuth?.token).toBe("fallback-local-token"); + }); + }); });