fix(gmail): keep tailscale serve path at root
The default Gmail hook path configured by `clawdbot hooks gmail setup` is `/gmail-pubsub`. Tailscale strips the mount path before proxying, so the request lands on `/` and the hook 404s under the default configuration. When Tailscale is enabled, always listen on `/` internally and keep the public URL on the configured path (defaulting to `/gmail-pubsub`). This makes default and custom paths work reliably. Alternative (not implemented here): call tailscale with a full target URL so the backend keeps the path, e.g. `tailscale funnel --set-path /gmail-pubsub http://127.0.0.1:8788/gmail-pubsub`. We did not take this path because it requires changing the CLI invocation to pass URLs (not ports) plus extra validation, which is a larger behavior change.
This commit is contained in:
committed by
Peter Steinberger
parent
0de3bb36d5
commit
26ce65995f
@@ -134,6 +134,11 @@ export async function runGmailSetup(opts: GmailSetupOptions) {
|
|||||||
const serveBind = opts.bind ?? DEFAULT_GMAIL_SERVE_BIND;
|
const serveBind = opts.bind ?? DEFAULT_GMAIL_SERVE_BIND;
|
||||||
const servePort = opts.port ?? DEFAULT_GMAIL_SERVE_PORT;
|
const servePort = opts.port ?? DEFAULT_GMAIL_SERVE_PORT;
|
||||||
const configuredServePath = opts.path ?? baseConfig.hooks?.gmail?.serve?.path;
|
const configuredServePath = opts.path ?? baseConfig.hooks?.gmail?.serve?.path;
|
||||||
|
const normalizedServePath =
|
||||||
|
typeof configuredServePath === "string" &&
|
||||||
|
configuredServePath.trim().length > 0
|
||||||
|
? normalizeServePath(configuredServePath)
|
||||||
|
: DEFAULT_GMAIL_SERVE_PATH;
|
||||||
|
|
||||||
const includeBody = opts.includeBody ?? true;
|
const includeBody = opts.includeBody ?? true;
|
||||||
const maxBytes = opts.maxBytes ?? DEFAULT_GMAIL_MAX_BYTES;
|
const maxBytes = opts.maxBytes ?? DEFAULT_GMAIL_MAX_BYTES;
|
||||||
@@ -142,18 +147,14 @@ export async function runGmailSetup(opts: GmailSetupOptions) {
|
|||||||
|
|
||||||
const tailscaleMode = opts.tailscale ?? "funnel";
|
const tailscaleMode = opts.tailscale ?? "funnel";
|
||||||
// Tailscale strips the path before proxying; keep a public path while gog
|
// Tailscale strips the path before proxying; keep a public path while gog
|
||||||
// listens on "/" unless the user explicitly configured a serve path.
|
// listens on "/" whenever Tailscale is enabled.
|
||||||
const servePath = normalizeServePath(
|
const servePath = normalizeServePath(
|
||||||
tailscaleMode !== "off" && !configuredServePath
|
tailscaleMode !== "off" ? "/" : normalizedServePath,
|
||||||
? "/"
|
|
||||||
: (configuredServePath ?? DEFAULT_GMAIL_SERVE_PATH),
|
|
||||||
);
|
);
|
||||||
const tailscalePath = normalizeServePath(
|
const tailscalePath = normalizeServePath(
|
||||||
opts.tailscalePath ??
|
opts.tailscalePath ??
|
||||||
baseConfig.hooks?.gmail?.tailscale?.path ??
|
baseConfig.hooks?.gmail?.tailscale?.path ??
|
||||||
(tailscaleMode !== "off"
|
(tailscaleMode !== "off" ? normalizedServePath : servePath),
|
||||||
? (configuredServePath ?? DEFAULT_GMAIL_SERVE_PATH)
|
|
||||||
: servePath),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await runGcloud(["config", "set", "project", projectId, "--quiet"]);
|
await runGcloud(["config", "set", "project", projectId, "--quiet"]);
|
||||||
|
|||||||
@@ -85,7 +85,30 @@ describe("gmail hook config", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps explicit serve path for tailscale when set", () => {
|
it("keeps the default public path when serve path is explicit", () => {
|
||||||
|
const result = resolveGmailHookRuntimeConfig(
|
||||||
|
{
|
||||||
|
hooks: {
|
||||||
|
token: "hook-token",
|
||||||
|
gmail: {
|
||||||
|
account: "clawdbot@gmail.com",
|
||||||
|
topic: "projects/demo/topics/gog-gmail-watch",
|
||||||
|
pushToken: "push-token",
|
||||||
|
serve: { path: "/gmail-pubsub" },
|
||||||
|
tailscale: { mode: "funnel" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
expect(result.ok).toBe(true);
|
||||||
|
if (result.ok) {
|
||||||
|
expect(result.value.serve.path).toBe("/");
|
||||||
|
expect(result.value.tailscale.path).toBe("/gmail-pubsub");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps custom public path when serve path is set", () => {
|
||||||
const result = resolveGmailHookRuntimeConfig(
|
const result = resolveGmailHookRuntimeConfig(
|
||||||
{
|
{
|
||||||
hooks: {
|
hooks: {
|
||||||
@@ -103,7 +126,7 @@ describe("gmail hook config", () => {
|
|||||||
);
|
);
|
||||||
expect(result.ok).toBe(true);
|
expect(result.ok).toBe(true);
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
expect(result.value.serve.path).toBe("/custom");
|
expect(result.value.serve.path).toBe("/");
|
||||||
expect(result.value.tailscale.path).toBe("/custom");
|
expect(result.value.tailscale.path).toBe("/custom");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -160,23 +160,22 @@ export function resolveGmailHookRuntimeConfig(
|
|||||||
? Math.floor(servePortRaw)
|
? Math.floor(servePortRaw)
|
||||||
: DEFAULT_GMAIL_SERVE_PORT;
|
: DEFAULT_GMAIL_SERVE_PORT;
|
||||||
const servePathRaw = overrides.servePath ?? gmail?.serve?.path;
|
const servePathRaw = overrides.servePath ?? gmail?.serve?.path;
|
||||||
const hasExplicitServePath =
|
const normalizedServePathRaw =
|
||||||
typeof servePathRaw === "string" && servePathRaw.trim().length > 0;
|
typeof servePathRaw === "string" && servePathRaw.trim().length > 0
|
||||||
|
? normalizeServePath(servePathRaw)
|
||||||
|
: DEFAULT_GMAIL_SERVE_PATH;
|
||||||
|
|
||||||
const tailscaleMode =
|
const tailscaleMode =
|
||||||
overrides.tailscaleMode ?? gmail?.tailscale?.mode ?? "off";
|
overrides.tailscaleMode ?? gmail?.tailscale?.mode ?? "off";
|
||||||
// When exposing the push endpoint via Tailscale, the public path is stripped
|
// Tailscale strips the public path before proxying, so listen on "/" when on.
|
||||||
// before proxying; use "/" internally unless the user set a path explicitly.
|
|
||||||
const servePath = normalizeServePath(
|
const servePath = normalizeServePath(
|
||||||
tailscaleMode !== "off" && !hasExplicitServePath ? "/" : servePathRaw,
|
tailscaleMode !== "off" ? "/" : normalizedServePathRaw,
|
||||||
);
|
);
|
||||||
|
|
||||||
const tailscalePathRaw = overrides.tailscalePath ?? gmail?.tailscale?.path;
|
const tailscalePathRaw = overrides.tailscalePath ?? gmail?.tailscale?.path;
|
||||||
const tailscalePath = normalizeServePath(
|
const tailscalePath = normalizeServePath(
|
||||||
tailscaleMode !== "off" && !tailscalePathRaw
|
tailscaleMode !== "off"
|
||||||
? hasExplicitServePath
|
? (tailscalePathRaw ?? normalizedServePathRaw)
|
||||||
? servePathRaw
|
|
||||||
: DEFAULT_GMAIL_SERVE_PATH
|
|
||||||
: (tailscalePathRaw ?? servePath),
|
: (tailscalePathRaw ?? servePath),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user