fix: skip tailscale dns probe when off
This commit is contained in:
@@ -21,7 +21,6 @@ Docs: https://docs.clawd.bot
|
|||||||
- BlueBubbles: keep part-index GUIDs in reply tags when short IDs are missing.
|
- BlueBubbles: keep part-index GUIDs in reply tags when short IDs are missing.
|
||||||
- Web UI: hide internal `message_id` hints in chat bubbles.
|
- Web UI: hide internal `message_id` hints in chat bubbles.
|
||||||
- Web UI: show Stop button during active runs, swap back to New session when idle. (#1664) Thanks @ndbroadbent.
|
- Web UI: show Stop button during active runs, swap back to New session when idle. (#1664) Thanks @ndbroadbent.
|
||||||
- Web UI: keep raw config edits from toggling channel save state; enable save/apply on raw changes only. (#1673) Thanks @Glucksberg.
|
|
||||||
- Heartbeat: normalize target identifiers for consistent routing.
|
- Heartbeat: normalize target identifiers for consistent routing.
|
||||||
- TUI: reload history after gateway reconnect to restore session state. (#1663)
|
- TUI: reload history after gateway reconnect to restore session state. (#1663)
|
||||||
- Telegram: use wrapped fetch for long-polling on Node to normalize AbortSignal handling. (#1639)
|
- Telegram: use wrapped fetch for long-polling on Node to normalize AbortSignal handling. (#1639)
|
||||||
@@ -29,7 +28,7 @@ Docs: https://docs.clawd.bot
|
|||||||
- Agents: auto-compact on context overflow prompt errors before failing. (#1627) Thanks @rodrigouroz.
|
- Agents: auto-compact on context overflow prompt errors before failing. (#1627) Thanks @rodrigouroz.
|
||||||
- Agents: use the active auth profile for auto-compaction recovery.
|
- Agents: use the active auth profile for auto-compaction recovery.
|
||||||
- Models: default missing custom provider fields so minimal configs are accepted.
|
- Models: default missing custom provider fields so minimal configs are accepted.
|
||||||
- Gateway: honor trusted proxy client IPs for local pairing + HTTP checks. (#1654) Thanks @ndbroadbent.
|
- Gateway: skip Tailscale DNS probing when tailscale.mode is off. (#1671)
|
||||||
- Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b.
|
- Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b.
|
||||||
- macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman.
|
- macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman.
|
||||||
- Voice Call: return stream TwiML for outbound conversation calls on initial Twilio webhook. (#1634)
|
- Voice Call: return stream TwiML for outbound conversation calls on initial Twilio webhook. (#1634)
|
||||||
|
|||||||
@@ -48,29 +48,19 @@ describe("models-config", () => {
|
|||||||
const previous = process.env.COPILOT_GITHUB_TOKEN;
|
const previous = process.env.COPILOT_GITHUB_TOKEN;
|
||||||
const previousGh = process.env.GH_TOKEN;
|
const previousGh = process.env.GH_TOKEN;
|
||||||
const previousGithub = process.env.GITHUB_TOKEN;
|
const previousGithub = process.env.GITHUB_TOKEN;
|
||||||
const previousVenice = process.env.VENICE_API_KEY;
|
|
||||||
const previousKimiCode = process.env.KIMICODE_API_KEY;
|
const previousKimiCode = process.env.KIMICODE_API_KEY;
|
||||||
const previousKimiCodeAlt = process.env.KIMI_CODE_API_KEY;
|
|
||||||
const previousMinimax = process.env.MINIMAX_API_KEY;
|
const previousMinimax = process.env.MINIMAX_API_KEY;
|
||||||
const previousMoonshot = process.env.MOONSHOT_API_KEY;
|
const previousMoonshot = process.env.MOONSHOT_API_KEY;
|
||||||
const previousSynthetic = process.env.SYNTHETIC_API_KEY;
|
const previousSynthetic = process.env.SYNTHETIC_API_KEY;
|
||||||
const previousAwsAccessKey = process.env.AWS_ACCESS_KEY_ID;
|
const previousVenice = process.env.VENICE_API_KEY;
|
||||||
const previousAwsSecretKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
||||||
const previousAwsProfile = process.env.AWS_PROFILE;
|
|
||||||
const previousAwsBearer = process.env.AWS_BEARER_TOKEN;
|
|
||||||
delete process.env.COPILOT_GITHUB_TOKEN;
|
delete process.env.COPILOT_GITHUB_TOKEN;
|
||||||
delete process.env.GH_TOKEN;
|
delete process.env.GH_TOKEN;
|
||||||
delete process.env.GITHUB_TOKEN;
|
delete process.env.GITHUB_TOKEN;
|
||||||
delete process.env.VENICE_API_KEY;
|
|
||||||
delete process.env.KIMICODE_API_KEY;
|
delete process.env.KIMICODE_API_KEY;
|
||||||
delete process.env.KIMI_CODE_API_KEY;
|
|
||||||
delete process.env.MINIMAX_API_KEY;
|
delete process.env.MINIMAX_API_KEY;
|
||||||
delete process.env.MOONSHOT_API_KEY;
|
delete process.env.MOONSHOT_API_KEY;
|
||||||
delete process.env.SYNTHETIC_API_KEY;
|
delete process.env.SYNTHETIC_API_KEY;
|
||||||
delete process.env.AWS_ACCESS_KEY_ID;
|
delete process.env.VENICE_API_KEY;
|
||||||
delete process.env.AWS_SECRET_ACCESS_KEY;
|
|
||||||
delete process.env.AWS_PROFILE;
|
|
||||||
delete process.env.AWS_BEARER_TOKEN;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
@@ -93,26 +83,16 @@ describe("models-config", () => {
|
|||||||
else process.env.GH_TOKEN = previousGh;
|
else process.env.GH_TOKEN = previousGh;
|
||||||
if (previousGithub === undefined) delete process.env.GITHUB_TOKEN;
|
if (previousGithub === undefined) delete process.env.GITHUB_TOKEN;
|
||||||
else process.env.GITHUB_TOKEN = previousGithub;
|
else process.env.GITHUB_TOKEN = previousGithub;
|
||||||
if (previousVenice === undefined) delete process.env.VENICE_API_KEY;
|
|
||||||
else process.env.VENICE_API_KEY = previousVenice;
|
|
||||||
if (previousKimiCode === undefined) delete process.env.KIMICODE_API_KEY;
|
if (previousKimiCode === undefined) delete process.env.KIMICODE_API_KEY;
|
||||||
else process.env.KIMICODE_API_KEY = previousKimiCode;
|
else process.env.KIMICODE_API_KEY = previousKimiCode;
|
||||||
if (previousKimiCodeAlt === undefined) delete process.env.KIMI_CODE_API_KEY;
|
|
||||||
else process.env.KIMI_CODE_API_KEY = previousKimiCodeAlt;
|
|
||||||
if (previousMinimax === undefined) delete process.env.MINIMAX_API_KEY;
|
if (previousMinimax === undefined) delete process.env.MINIMAX_API_KEY;
|
||||||
else process.env.MINIMAX_API_KEY = previousMinimax;
|
else process.env.MINIMAX_API_KEY = previousMinimax;
|
||||||
if (previousMoonshot === undefined) delete process.env.MOONSHOT_API_KEY;
|
if (previousMoonshot === undefined) delete process.env.MOONSHOT_API_KEY;
|
||||||
else process.env.MOONSHOT_API_KEY = previousMoonshot;
|
else process.env.MOONSHOT_API_KEY = previousMoonshot;
|
||||||
if (previousSynthetic === undefined) delete process.env.SYNTHETIC_API_KEY;
|
if (previousSynthetic === undefined) delete process.env.SYNTHETIC_API_KEY;
|
||||||
else process.env.SYNTHETIC_API_KEY = previousSynthetic;
|
else process.env.SYNTHETIC_API_KEY = previousSynthetic;
|
||||||
if (previousAwsAccessKey === undefined) delete process.env.AWS_ACCESS_KEY_ID;
|
if (previousVenice === undefined) delete process.env.VENICE_API_KEY;
|
||||||
else process.env.AWS_ACCESS_KEY_ID = previousAwsAccessKey;
|
else process.env.VENICE_API_KEY = previousVenice;
|
||||||
if (previousAwsSecretKey === undefined) delete process.env.AWS_SECRET_ACCESS_KEY;
|
|
||||||
else process.env.AWS_SECRET_ACCESS_KEY = previousAwsSecretKey;
|
|
||||||
if (previousAwsProfile === undefined) delete process.env.AWS_PROFILE;
|
|
||||||
else process.env.AWS_PROFILE = previousAwsProfile;
|
|
||||||
if (previousAwsBearer === undefined) delete process.env.AWS_BEARER_TOKEN;
|
|
||||||
else process.env.AWS_BEARER_TOKEN = previousAwsBearer;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export async function startGatewayDiscovery(params: {
|
|||||||
gatewayTls?: { enabled: boolean; fingerprintSha256?: string };
|
gatewayTls?: { enabled: boolean; fingerprintSha256?: string };
|
||||||
canvasPort?: number;
|
canvasPort?: number;
|
||||||
wideAreaDiscoveryEnabled: boolean;
|
wideAreaDiscoveryEnabled: boolean;
|
||||||
|
tailscaleMode: "off" | "serve" | "funnel";
|
||||||
logDiscovery: { info: (msg: string) => void; warn: (msg: string) => void };
|
logDiscovery: { info: (msg: string) => void; warn: (msg: string) => void };
|
||||||
}) {
|
}) {
|
||||||
let bonjourStop: (() => Promise<void>) | null = null;
|
let bonjourStop: (() => Promise<void>) | null = null;
|
||||||
@@ -20,8 +21,11 @@ export async function startGatewayDiscovery(params: {
|
|||||||
process.env.CLAWDBOT_DISABLE_BONJOUR !== "1" &&
|
process.env.CLAWDBOT_DISABLE_BONJOUR !== "1" &&
|
||||||
process.env.NODE_ENV !== "test" &&
|
process.env.NODE_ENV !== "test" &&
|
||||||
!process.env.VITEST;
|
!process.env.VITEST;
|
||||||
|
const tailscaleEnabled = params.tailscaleMode !== "off";
|
||||||
const needsTailnetDns = bonjourEnabled || params.wideAreaDiscoveryEnabled;
|
const needsTailnetDns = bonjourEnabled || params.wideAreaDiscoveryEnabled;
|
||||||
const tailnetDns = needsTailnetDns ? await resolveTailnetDnsHint() : undefined;
|
const tailnetDns = needsTailnetDns
|
||||||
|
? await resolveTailnetDnsHint({ enabled: tailscaleEnabled })
|
||||||
|
: undefined;
|
||||||
const sshPortEnv = process.env.CLAWDBOT_SSH_PORT?.trim();
|
const sshPortEnv = process.env.CLAWDBOT_SSH_PORT?.trim();
|
||||||
const sshPortParsed = sshPortEnv ? Number.parseInt(sshPortEnv, 10) : NaN;
|
const sshPortParsed = sshPortEnv ? Number.parseInt(sshPortEnv, 10) : NaN;
|
||||||
const sshPort = Number.isFinite(sshPortParsed) && sshPortParsed > 0 ? sshPortParsed : undefined;
|
const sshPort = Number.isFinite(sshPortParsed) && sshPortParsed > 0 ? sshPortParsed : undefined;
|
||||||
|
|||||||
45
src/gateway/server-discovery.test.ts
Normal file
45
src/gateway/server-discovery.test.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
const getTailnetHostname = vi.hoisted(() => vi.fn());
|
||||||
|
|
||||||
|
vi.mock("../infra/tailscale.js", () => ({ getTailnetHostname }));
|
||||||
|
|
||||||
|
import { resolveTailnetDnsHint } from "./server-discovery.js";
|
||||||
|
|
||||||
|
describe("resolveTailnetDnsHint", () => {
|
||||||
|
const prevTailnetDns = { value: undefined as string | undefined };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
prevTailnetDns.value = process.env.CLAWDBOT_TAILNET_DNS;
|
||||||
|
delete process.env.CLAWDBOT_TAILNET_DNS;
|
||||||
|
getTailnetHostname.mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (prevTailnetDns.value === undefined) {
|
||||||
|
delete process.env.CLAWDBOT_TAILNET_DNS;
|
||||||
|
} else {
|
||||||
|
process.env.CLAWDBOT_TAILNET_DNS = prevTailnetDns.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns env hint when disabled", async () => {
|
||||||
|
process.env.CLAWDBOT_TAILNET_DNS = "studio.tailnet.ts.net.";
|
||||||
|
const value = await resolveTailnetDnsHint({ enabled: false });
|
||||||
|
expect(value).toBe("studio.tailnet.ts.net");
|
||||||
|
expect(getTailnetHostname).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("skips tailscale lookup when disabled", async () => {
|
||||||
|
const value = await resolveTailnetDnsHint({ enabled: false });
|
||||||
|
expect(value).toBeUndefined();
|
||||||
|
expect(getTailnetHostname).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("uses tailscale lookup when enabled", async () => {
|
||||||
|
getTailnetHostname.mockResolvedValue("host.tailnet.ts.net");
|
||||||
|
const value = await resolveTailnetDnsHint({ enabled: true });
|
||||||
|
expect(value).toBe("host.tailnet.ts.net");
|
||||||
|
expect(getTailnetHostname).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -55,11 +55,13 @@ export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}):
|
|||||||
export async function resolveTailnetDnsHint(opts?: {
|
export async function resolveTailnetDnsHint(opts?: {
|
||||||
env?: NodeJS.ProcessEnv;
|
env?: NodeJS.ProcessEnv;
|
||||||
exec?: typeof runExec;
|
exec?: typeof runExec;
|
||||||
|
enabled?: boolean;
|
||||||
}): Promise<string | undefined> {
|
}): Promise<string | undefined> {
|
||||||
const env = opts?.env ?? process.env;
|
const env = opts?.env ?? process.env;
|
||||||
const envRaw = env.CLAWDBOT_TAILNET_DNS?.trim();
|
const envRaw = env.CLAWDBOT_TAILNET_DNS?.trim();
|
||||||
const envValue = envRaw && envRaw.length > 0 ? envRaw.replace(/\.$/, "") : "";
|
const envValue = envRaw && envRaw.length > 0 ? envRaw.replace(/\.$/, "") : "";
|
||||||
if (envValue) return envValue;
|
if (envValue) return envValue;
|
||||||
|
if (opts?.enabled === false) return undefined;
|
||||||
|
|
||||||
const exec =
|
const exec =
|
||||||
opts?.exec ??
|
opts?.exec ??
|
||||||
|
|||||||
@@ -339,6 +339,7 @@ export async function startGatewayServer(
|
|||||||
? { enabled: true, fingerprintSha256: gatewayTls.fingerprintSha256 }
|
? { enabled: true, fingerprintSha256: gatewayTls.fingerprintSha256 }
|
||||||
: undefined,
|
: undefined,
|
||||||
wideAreaDiscoveryEnabled: cfgAtStart.discovery?.wideArea?.enabled === true,
|
wideAreaDiscoveryEnabled: cfgAtStart.discovery?.wideArea?.enabled === true,
|
||||||
|
tailscaleMode,
|
||||||
logDiscovery,
|
logDiscovery,
|
||||||
});
|
});
|
||||||
bonjourStop = discovery.bonjourStop;
|
bonjourStop = discovery.bonjourStop;
|
||||||
|
|||||||
Reference in New Issue
Block a user