fix: stabilize gateway defaults

This commit is contained in:
Peter Steinberger
2026-01-20 11:00:34 +00:00
parent 9f75550702
commit 74757cd5af
5 changed files with 28 additions and 27 deletions

View File

@@ -123,7 +123,8 @@ export function registerDevicesCli(program: Command) {
const name = req.displayName || req.deviceId;
const repair = req.isRepair ? " (repair)" : "";
const ip = req.remoteIp ? ` · ${req.remoteIp}` : "";
const age = typeof req.ts === "number" ? ` · ${formatAge(Date.now() - req.ts)} ago` : "";
const age =
typeof req.ts === "number" ? ` · ${formatAge(Date.now() - req.ts)} ago` : "";
const role = req.role ? ` · role: ${req.role}` : "";
defaultRuntime.log(`- ${req.requestId}: ${name}${repair}${role}${ip}${age}`);
}
@@ -133,7 +134,9 @@ export function registerDevicesCli(program: Command) {
for (const device of list.paired) {
const name = device.displayName || device.deviceId;
const roles = device.roles?.length ? `roles: ${device.roles.join(", ")}` : "roles: -";
const scopes = device.scopes?.length ? `scopes: ${device.scopes.join(", ")}` : "scopes: -";
const scopes = device.scopes?.length
? `scopes: ${device.scopes.join(", ")}`
: "scopes: -";
const ip = device.remoteIp ? ` · ${device.remoteIp}` : "";
const tokens = formatTokenSummary(device.tokens);
defaultRuntime.log(`- ${name} · ${roles} · ${scopes} · ${tokens}${ip}`);

View File

@@ -309,7 +309,9 @@ describe("config identity defaults", () => {
expect(cfg.messages?.groupChat?.mentionPatterns).toBeUndefined();
expect(cfg.agents?.list).toBeUndefined();
expect(cfg.agents?.defaults?.maxConcurrent).toBe(DEFAULT_AGENT_MAX_CONCURRENT);
expect(cfg.agents?.defaults?.subagents?.maxConcurrent).toBe(DEFAULT_SUBAGENT_MAX_CONCURRENT);
expect(cfg.agents?.defaults?.subagents?.maxConcurrent).toBe(
DEFAULT_SUBAGENT_MAX_CONCURRENT,
);
expect(cfg.session).toBeUndefined();
});
});

View File

@@ -72,7 +72,7 @@ export function describeGatewayCloseCode(code: number): string | undefined {
export class GatewayClient {
private ws: WebSocket | null = null;
private opts: GatewayClientOptions;
private opts: GatewayClientOptions & { deviceIdentity: DeviceIdentity };
private pending = new Map<string, Pending>();
private backoffMs = 1000;
private closed = false;
@@ -161,25 +161,23 @@ export class GatewayClient {
: undefined;
const signedAtMs = Date.now();
const scopes = this.opts.scopes ?? ["operator.admin"];
const device = (() => {
if (!this.opts.deviceIdentity) return undefined;
const payload = buildDeviceAuthPayload({
deviceId: this.opts.deviceIdentity.deviceId,
clientId: this.opts.clientName ?? GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
clientMode: this.opts.mode ?? GATEWAY_CLIENT_MODES.BACKEND,
role,
scopes,
signedAtMs,
token: authToken ?? null,
});
const signature = signDevicePayload(this.opts.deviceIdentity.privateKeyPem, payload);
return {
id: this.opts.deviceIdentity.deviceId,
publicKey: publicKeyRawBase64UrlFromPem(this.opts.deviceIdentity.publicKeyPem),
signature,
signedAt: signedAtMs,
};
})();
const deviceIdentity = this.opts.deviceIdentity;
const payload = buildDeviceAuthPayload({
deviceId: deviceIdentity.deviceId,
clientId: this.opts.clientName ?? GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
clientMode: this.opts.mode ?? GATEWAY_CLIENT_MODES.BACKEND,
role,
scopes,
signedAtMs,
token: authToken ?? null,
});
const signature = signDevicePayload(deviceIdentity.privateKeyPem, payload);
const device = {
id: deviceIdentity.deviceId,
publicKey: publicKeyRawBase64UrlFromPem(deviceIdentity.publicKeyPem),
signature,
signedAt: signedAtMs,
};
const params: ConnectParams = {
minProtocol: this.opts.minProtocol ?? PROTOCOL_VERSION,
maxProtocol: this.opts.maxProtocol ?? PROTOCOL_VERSION,

View File

@@ -102,9 +102,8 @@ describe("gateway server auth/connect", () => {
test("accepts device token auth for paired device", async () => {
const { loadOrCreateDeviceIdentity } = await import("../infra/device-identity.js");
const { approveDevicePairing, getPairedDevice, listDevicePairing } = await import(
"../infra/device-pairing.js"
);
const { approveDevicePairing, getPairedDevice, listDevicePairing } =
await import("../infra/device-pairing.js");
const { server, ws, port, prevToken } = await startServerWithClient("secret");
const res = await connectReq(ws, { token: "secret" });
if (!res.ok) {

View File

@@ -10,7 +10,6 @@ import {
signDevicePayload,
} from "../infra/device-identity.js";
import { emitHeartbeatEvent } from "../infra/heartbeat-events.js";
import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import {
connectOk,