From 3e6d27ac4e9148bbbab287541c7805401ebcd40e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 11 Jan 2026 01:46:37 +0100 Subject: [PATCH] fix(status): show gateway auth when reachable --- src/commands/status-all.ts | 6 +++++- src/commands/status-all/format.ts | 14 ++++++++++++++ src/commands/status.test.ts | 25 +++++++++++++++++++++++++ src/commands/status.ts | 7 ++++++- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/commands/status-all.ts b/src/commands/status-all.ts index 9bb227373..1a2da354e 100644 --- a/src/commands/status-all.ts +++ b/src/commands/status-all.ts @@ -31,6 +31,7 @@ import { getAgentLocalStatuses } from "./status-all/agents.js"; import { formatAge, formatDuration, + formatGatewayAuthUsed, redactSecrets, } from "./status-all/format.js"; import { @@ -282,6 +283,9 @@ export async function statusAllCommand( : gatewayProbe?.error ? `unreachable (${gatewayProbe.error})` : "unreachable"; + const gatewayAuth = gatewayReachable + ? ` · auth ${formatGatewayAuthUsed(remoteUrlMissing ? localFallbackAuth : remoteAuth)}` + : ""; const gatewaySelfLine = gatewaySelf?.host || gatewaySelf?.ip || @@ -319,7 +323,7 @@ export async function statusAllCommand( { Item: "Update", Value: updateLine }, { Item: "Gateway", - Value: `${gatewayMode}${remoteUrlMissing ? " (remote.url missing)" : ""} · ${gatewayTarget} (${connection.urlSource}) · ${gatewayStatus}`, + Value: `${gatewayMode}${remoteUrlMissing ? " (remote.url missing)" : ""} · ${gatewayTarget} (${connection.urlSource}) · ${gatewayStatus}${gatewayAuth}`, }, gatewaySelfLine ? { Item: "Gateway self", Value: gatewaySelfLine } diff --git a/src/commands/status-all/format.ts b/src/commands/status-all/format.ts index 0380d487d..ad636d14e 100644 --- a/src/commands/status-all/format.ts +++ b/src/commands/status-all/format.ts @@ -15,6 +15,20 @@ export const formatDuration = (ms: number | null | undefined) => { return `${(ms / 1000).toFixed(1)}s`; }; +export function formatGatewayAuthUsed( + auth: { + token?: string; + password?: string; + } | null, +): "token" | "password" | "token+password" | "none" { + const hasToken = Boolean(auth?.token?.trim()); + const hasPassword = Boolean(auth?.password?.trim()); + if (hasToken && hasPassword) return "token+password"; + if (hasToken) return "token"; + if (hasPassword) return "password"; + return "none"; +} + export function redactSecrets(text: string): string { if (!text) return text; let out = text; diff --git a/src/commands/status.test.ts b/src/commands/status.test.ts index 8d21b03e3..241278602 100644 --- a/src/commands/status.test.ts +++ b/src/commands/status.test.ts @@ -150,4 +150,29 @@ describe("statusCommand", () => { expect(logs.some((l) => l.includes("FAQ:"))).toBe(true); expect(logs.some((l) => l.includes("Troubleshooting:"))).toBe(true); }); + + it("shows gateway auth when reachable", async () => { + const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; + process.env.CLAWDBOT_GATEWAY_TOKEN = "abcd1234"; + try { + mocks.probeGateway.mockResolvedValueOnce({ + ok: true, + url: "ws://127.0.0.1:18789", + connectLatencyMs: 123, + error: null, + close: null, + health: {}, + status: {}, + presence: [], + configSnapshot: null, + }); + (runtime.log as vi.Mock).mockClear(); + await statusCommand({}, runtime as never); + const logs = (runtime.log as vi.Mock).mock.calls.map((c) => String(c[0])); + expect(logs.some((l) => l.includes("auth token"))).toBe(true); + } finally { + if (prevToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; + else process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + } + }); }); diff --git a/src/commands/status.ts b/src/commands/status.ts index 3a5a81281..bc8d9df0e 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -44,6 +44,7 @@ import { resolveHeartbeatSeconds } from "../web/reconnect.js"; import { getWebAuthAgeMs, webAuthExists } from "../web/session.js"; import type { HealthSummary } from "./health.js"; import { resolveControlUiLinks } from "./onboard-helpers.js"; +import { formatGatewayAuthUsed } from "./status-all/format.js"; import { buildProvidersTable } from "./status-all/providers.js"; import { statusAllCommand } from "./status-all.js"; @@ -714,6 +715,10 @@ export async function statusCommand( ? `unreachable (${gatewayProbe.error})` : "unreachable", ); + const auth = + gatewayReachable && !remoteUrlMissing + ? ` · auth ${formatGatewayAuthUsed(resolveGatewayProbeAuth(cfg))}` + : ""; const self = gatewaySelf?.host || gatewaySelf?.version || gatewaySelf?.platform ? [ @@ -726,7 +731,7 @@ export async function statusCommand( .join(" ") : null; const suffix = self ? ` · ${self}` : ""; - return `${gatewayMode} · ${target} · ${reach}${suffix}`; + return `${gatewayMode} · ${target} · ${reach}${auth}${suffix}`; })(); const agentsValue = (() => {