test: refine gateway auth helper coverage

This commit is contained in:
Peter Steinberger 2026-03-13 17:58:28 +00:00
parent 91f1894372
commit e25fa446e8
2 changed files with 104 additions and 64 deletions

View File

@ -1,29 +1,69 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { buildDeviceAuthPayloadV3, normalizeDeviceMetadataForAuth } from "./device-auth.js"; import {
buildDeviceAuthPayload,
buildDeviceAuthPayloadV3,
normalizeDeviceMetadataForAuth,
} from "./device-auth.js";
describe("device-auth payload vectors", () => { describe("device-auth payload vectors", () => {
it("builds canonical v3 payload", () => { it.each([
const payload = buildDeviceAuthPayloadV3({ {
deviceId: "dev-1", name: "builds canonical v2 payloads",
clientId: "openclaw-macos", build: () =>
clientMode: "ui", buildDeviceAuthPayload({
role: "operator", deviceId: "dev-1",
scopes: ["operator.admin", "operator.read"], clientId: "openclaw-macos",
signedAtMs: 1_700_000_000_000, clientMode: "ui",
token: "tok-123", role: "operator",
nonce: "nonce-abc", scopes: ["operator.admin", "operator.read"],
platform: " IOS ", signedAtMs: 1_700_000_000_000,
deviceFamily: " iPhone ", token: null,
}); nonce: "nonce-abc",
}),
expect(payload).toBe( expected:
"v3|dev-1|openclaw-macos|ui|operator|operator.admin,operator.read|1700000000000|tok-123|nonce-abc|ios|iphone", "v2|dev-1|openclaw-macos|ui|operator|operator.admin,operator.read|1700000000000||nonce-abc",
); },
{
name: "builds canonical v3 payloads",
build: () =>
buildDeviceAuthPayloadV3({
deviceId: "dev-1",
clientId: "openclaw-macos",
clientMode: "ui",
role: "operator",
scopes: ["operator.admin", "operator.read"],
signedAtMs: 1_700_000_000_000,
token: "tok-123",
nonce: "nonce-abc",
platform: " IOS ",
deviceFamily: " iPhone ",
}),
expected:
"v3|dev-1|openclaw-macos|ui|operator|operator.admin,operator.read|1700000000000|tok-123|nonce-abc|ios|iphone",
},
{
name: "keeps empty metadata slots in v3 payloads",
build: () =>
buildDeviceAuthPayloadV3({
deviceId: "dev-2",
clientId: "openclaw-ios",
clientMode: "ui",
role: "operator",
scopes: ["operator.read"],
signedAtMs: 1_700_000_000_001,
nonce: "nonce-def",
}),
expected: "v3|dev-2|openclaw-ios|ui|operator|operator.read|1700000000001||nonce-def||",
},
])("$name", ({ build, expected }) => {
expect(build()).toBe(expected);
}); });
it("normalizes metadata with ASCII-only lowercase", () => { it.each([
expect(normalizeDeviceMetadataForAuth(" İOS ")).toBe("İos"); { input: " İOS ", expected: "İos" },
expect(normalizeDeviceMetadataForAuth(" MAC ")).toBe("mac"); { input: " MAC ", expected: "mac" },
expect(normalizeDeviceMetadataForAuth(undefined)).toBe(""); { input: undefined, expected: "" },
])("normalizes metadata %j", ({ input, expected }) => {
expect(normalizeDeviceMetadataForAuth(input)).toBe(expected);
}); });
}); });

View File

@ -6,8 +6,9 @@ import {
} from "./probe-auth.js"; } from "./probe-auth.js";
describe("resolveGatewayProbeAuthSafe", () => { describe("resolveGatewayProbeAuthSafe", () => {
it("returns probe auth credentials when available", () => { it.each([
const result = resolveGatewayProbeAuthSafe({ {
name: "returns probe auth credentials when available",
cfg: { cfg: {
gateway: { gateway: {
auth: { auth: {
@ -15,20 +16,17 @@ describe("resolveGatewayProbeAuthSafe", () => {
}, },
}, },
} as OpenClawConfig, } as OpenClawConfig,
mode: "local", mode: "local" as const,
env: {} as NodeJS.ProcessEnv, env: {} as NodeJS.ProcessEnv,
}); expected: {
auth: {
expect(result).toEqual({ token: "token-value",
auth: { password: undefined,
token: "token-value", },
password: undefined,
}, },
}); },
}); {
name: "returns warning and empty auth when a local token SecretRef is unresolved",
it("returns warning and empty auth when token SecretRef is unresolved", () => {
const result = resolveGatewayProbeAuthSafe({
cfg: { cfg: {
gateway: { gateway: {
auth: { auth: {
@ -42,17 +40,15 @@ describe("resolveGatewayProbeAuthSafe", () => {
}, },
}, },
} as OpenClawConfig, } as OpenClawConfig,
mode: "local", mode: "local" as const,
env: {} as NodeJS.ProcessEnv, env: {} as NodeJS.ProcessEnv,
}); expected: {
auth: {},
expect(result.auth).toEqual({}); warningIncludes: ["gateway.auth.token", "unresolved"],
expect(result.warning).toContain("gateway.auth.token"); },
expect(result.warning).toContain("unresolved"); },
}); {
name: "does not fall through to remote token when the local SecretRef is unresolved",
it("does not fall through to remote token when local token SecretRef is unresolved", () => {
const result = resolveGatewayProbeAuthSafe({
cfg: { cfg: {
gateway: { gateway: {
mode: "local", mode: "local",
@ -70,17 +66,15 @@ describe("resolveGatewayProbeAuthSafe", () => {
}, },
}, },
} as OpenClawConfig, } as OpenClawConfig,
mode: "local", mode: "local" as const,
env: {} as NodeJS.ProcessEnv, env: {} as NodeJS.ProcessEnv,
}); expected: {
auth: {},
expect(result.auth).toEqual({}); warningIncludes: ["gateway.auth.token", "unresolved"],
expect(result.warning).toContain("gateway.auth.token"); },
expect(result.warning).toContain("unresolved"); },
}); {
name: "ignores unresolved local token SecretRefs in remote mode",
it("ignores unresolved local token SecretRef in remote mode when remote-only auth is requested", () => {
const result = resolveGatewayProbeAuthSafe({
cfg: { cfg: {
gateway: { gateway: {
mode: "remote", mode: "remote",
@ -98,16 +92,22 @@ describe("resolveGatewayProbeAuthSafe", () => {
}, },
}, },
} as OpenClawConfig, } as OpenClawConfig,
mode: "remote", mode: "remote" as const,
env: {} as NodeJS.ProcessEnv, env: {} as NodeJS.ProcessEnv,
}); expected: {
auth: {
expect(result).toEqual({ token: undefined,
auth: { password: undefined,
token: undefined, },
password: undefined,
}, },
}); },
])("$name", ({ cfg, mode, env, expected }) => {
const result = resolveGatewayProbeAuthSafe({ cfg, mode, env });
expect(result.auth).toEqual(expected.auth);
for (const fragment of expected.warningIncludes ?? []) {
expect(result.warning).toContain(fragment);
}
}); });
}); });