From 784fac53b821864c4378c2ed9458cf4a6002aca2 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 14 Aug 2026 18:51:45 -0700 Subject: [PATCH] fix(gateway): include build identity in status JSON (#123917) * fix(gateway): preserve build id in status probes * chore: leave release notes to release automation --- src/cli/daemon-cli/status.gather.test.ts | 30 +++++++++++++++++++--- src/cli/daemon-cli/status.gather.ts | 1 + src/commands/gateway-status/output.test.ts | 6 +++++ src/commands/gateway-status/output.ts | 1 + src/gateway/probe.test.ts | 2 ++ src/gateway/probe.ts | 4 +++ 6 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/cli/daemon-cli/status.gather.test.ts b/src/cli/daemon-cli/status.gather.test.ts index ab412d9953d8..0deb2375cb0d 100644 --- a/src/cli/daemon-cli/status.gather.test.ts +++ b/src/cli/daemon-cli/status.gather.test.ts @@ -23,14 +23,14 @@ const callGatewayStatusProbe = vi.fn< ok: boolean; url?: string; error?: string | null; - server?: { version?: string | null; connId?: string | null }; + server?: { version?: string | null; buildId?: string | null; connId?: string | null }; version?: string | null; }> >(async (_opts?: unknown) => ({ ok: true, url: "ws://127.0.0.1:19001", error: null, - server: { version: "2026.5.6", connId: "conn-1" }, + server: { version: "2026.5.6", buildId: "build-2026.5.6", connId: "conn-1" }, })); const isDefaultInstallIdentity = vi.fn((_env?: NodeJS.ProcessEnv) => true); const isGatewayExternallySupervised = vi.fn((_env?: NodeJS.ProcessEnv) => false); @@ -473,7 +473,11 @@ describe("gatherDaemonStatus", () => { expect(status.gateway?.version).toBe("2026.5.6"); expect(status.rpc?.url).toBe("wss://127.0.0.1:19001"); expect(status.rpc?.ok).toBe(true); - expect(status.rpc?.server).toEqual({ version: "2026.5.6", connId: "conn-1" }); + expect(status.rpc?.server).toEqual({ + version: "2026.5.6", + buildId: "build-2026.5.6", + connId: "conn-1", + }); expect(status.cli?.version).toBe(VERSION); if (process.argv[1]) { expect(status.cli?.entrypoint).toBe(process.argv[1]); @@ -482,6 +486,26 @@ describe("gatherDaemonStatus", () => { expect(inspectWindowsGatewayFirewall).not.toHaveBeenCalled(); }); + it("preserves probe build identity in deep JSON output", async () => { + const status = await gatherStatus({ deep: true }); + const writeJson = vi.spyOn(defaultRuntime, "writeJson").mockImplementation(() => {}); + try { + printDaemonStatus(status, { json: true, deep: true }); + expect(writeJson).toHaveBeenCalledOnce(); + expect(writeJson.mock.calls[0]?.[0]).toMatchObject({ + rpc: { + server: { + version: "2026.5.6", + buildId: "build-2026.5.6", + connId: "conn-1", + }, + }, + }); + } finally { + writeJson.mockRestore(); + } + }); + it("batches daemon and CLI port status inspection when ports differ", async () => { await gatherStatus(); diff --git a/src/cli/daemon-cli/status.gather.ts b/src/cli/daemon-cli/status.gather.ts index c5990480ce4e..a4c496647ce2 100644 --- a/src/cli/daemon-cli/status.gather.ts +++ b/src/cli/daemon-cli/status.gather.ts @@ -342,6 +342,7 @@ export type DaemonStatus = { }; server?: { version?: string | null; + buildId?: string | null; connId?: string | null; }; version?: string | null; diff --git a/src/commands/gateway-status/output.test.ts b/src/commands/gateway-status/output.test.ts index c720dd2cf0de..74a88bde2f96 100644 --- a/src/commands/gateway-status/output.test.ts +++ b/src/commands/gateway-status/output.test.ts @@ -65,6 +65,7 @@ function createProbe( }, server: { version: "2026.4.24", + buildId: "build-test", connId: "conn-test", }, health: null, @@ -449,6 +450,11 @@ describe("gateway status output", () => { scopes: ["operator.read"], capability: "read_only", }, + server: { + version: "2026.4.24", + buildId: "build-test", + connId: "conn-test", + }, self: null, config: null, health: null, diff --git a/src/commands/gateway-status/output.ts b/src/commands/gateway-status/output.ts index 6c3e10ad01d5..05221e1803e4 100644 --- a/src/commands/gateway-status/output.ts +++ b/src/commands/gateway-status/output.ts @@ -190,6 +190,7 @@ export function writeGatewayStatusJson(params: { close: entry.probe.close, }, auth: entry.probe.auth, + server: entry.probe.server, self: entry.self, config: entry.configSummary, health: entry.probe.health, diff --git a/src/gateway/probe.test.ts b/src/gateway/probe.test.ts index 2a8e6dec7ac8..1d61aec19102 100644 --- a/src/gateway/probe.test.ts +++ b/src/gateway/probe.test.ts @@ -16,6 +16,7 @@ const gatewayClientState = vi.hoisted(() => ({ } as { role?: string; scopes?: string[] } | undefined, helloServer: { version: "2026.4.24", + buildId: "build-test", connId: "conn-test", }, connectError: "scope upgrade pending approval (requestId: req-123)", @@ -414,6 +415,7 @@ describe("probeGateway", () => { }); expect(result.server).toEqual({ version: "2026.4.24", + buildId: "build-test", connId: "conn-test", }); }); diff --git a/src/gateway/probe.ts b/src/gateway/probe.ts index 0e303f992686..6ea1b89a42ea 100644 --- a/src/gateway/probe.ts +++ b/src/gateway/probe.ts @@ -47,6 +47,7 @@ export type GatewayProbeAuthSummary = { export type GatewayProbeServerSummary = { version: string | null; + buildId?: string; connId: string | null; }; @@ -440,6 +441,9 @@ export async function probeGateway(opts: { authMetadataPresent = typeof hello?.auth === "object" && hello.auth !== null; server = { version: typeof hello?.server?.version === "string" ? hello.server.version : null, + ...(typeof hello?.server?.buildId === "string" + ? { buildId: hello.server.buildId } + : {}), connId: typeof hello?.server?.connId === "string" ? hello.server.connId : null, }; auth = resolveProbeAuthSummary({