




















@@ -3,7 +3,6 @@ import path from "node:path";
33import { expect, test, vi } from "vitest";
44import { WebSocket } from "ws";
55import {
6-approvePendingPairingIfNeeded,
76BACKEND_GATEWAY_CLIENT,
87connectReq,
98configureTrustedProxyControlUiAuth,
@@ -136,14 +135,6 @@ export function registerControlUiAndPairingSuite(): void {
136135};
137136};
138137139-const startServerWithOperatorIdentity = async (identityPrefix = "openclaw-device-scope-") => {
140-const { server, ws, port, prevToken } = await startServerWithClient("secret", {
141-controlUiEnabled: true,
142-});
143-const { identityPath, identity, client } = await createOperatorIdentityFixture(identityPrefix);
144-return { server, ws, port, prevToken, identityPath, identity, client };
145-};
146-147138const startControlUiServerWithOperatorIdentity = async (
148139identityPrefix = "openclaw-device-scope-",
149140) => {
@@ -219,17 +210,19 @@ export function registerControlUiAndPairingSuite(): void {
219210clientMode: string;
220211displayName: string;
221212platform: string;
213+scopes?: string[];
222214}): Promise<{ identityPath: string; identity: { deviceId: string } }> => {
223215const { publicKeyRawBase64UrlFromPem } = await import("../infra/device-identity.js");
224216const { approveDevicePairing, requestDevicePairing } =
225217await import("../infra/device-pairing.js");
226218const { identityPath, identity } = await createOperatorIdentityFixture(params.identityPrefix);
219+const scopes = params.scopes ?? ["operator.read"];
227220const devicePublicKey = publicKeyRawBase64UrlFromPem(identity.publicKeyPem);
228221const seeded = await requestDevicePairing({
229222deviceId: identity.deviceId,
230223publicKey: devicePublicKey,
231224role: "operator",
232-scopes: ["operator.read"],
225+ scopes,
233226clientId: params.clientId,
234227clientMode: params.clientMode,
235228displayName: params.displayName,
@@ -491,9 +484,6 @@ export function registerControlUiAndPairingSuite(): void {
491484492485const scopedHealth = await rpcReq(scopedWs, "health");
493486expect(scopedHealth.ok).toBe(true);
494-495-const talk = await rpcReq(scopedWs, "chat.history", { sessionKey: "main", limit: 1 });
496-expect(talk.ok).toBe(true);
497487scopedWs.close();
498488});
499489} finally {
@@ -1269,36 +1259,26 @@ export function registerControlUiAndPairingSuite(): void {
1269125912701260test("allows operator.read connect when device is paired with operator.admin", async () => {
12711261const { listDevicePairing } = await import("../infra/device-pairing.js");
1272-const { server, ws, port, prevToken, identityPath, identity, client } =
1273-await startServerWithOperatorIdentity();
1274-1275-const initialNonce = await readConnectChallengeNonce(ws);
1276-const initial = await connectReq(ws, {
1277-token: "secret",
1262+const { identityPath, identity } = await seedApprovedOperatorReadPairing({
1263+identityPrefix: "openclaw-device-admin-superset-",
1264+ clientId: TEST_OPERATOR_CLIENT.id,
1265+ clientMode: TEST_OPERATOR_CLIENT.mode,
1266+ displayName: "operator-admin-superset",
1267+platform: TEST_OPERATOR_CLIENT.platform,
12781268scopes: ["operator.admin"],
1279- client,
1280-device: await buildSignedDeviceForIdentity({
1281- identityPath,
1282- client,
1283-scopes: ["operator.admin"],
1284-nonce: initialNonce,
1285-}),
12861269});
1287-if (!initial.ok) {
1288-await approvePendingPairingIfNeeded();
1289-}
129012701291-ws.close();
1271+const { server, port, prevToken } = await startControlUiServer("secret");
1292127212931273const ws2 = await openWs(port);
12941274const nonce2 = await readConnectChallengeNonce(ws2);
12951275const res = await connectReq(ws2, {
12961276token: "secret",
12971277scopes: ["operator.read"],
1298- client,
1278+client: TEST_OPERATOR_CLIENT,
12991279device: await buildSignedDeviceForIdentity({
13001280 identityPath,
1301- client,
1281+client: TEST_OPERATOR_CLIENT,
13021282scopes: ["operator.read"],
13031283nonce: nonce2,
13041284}),
@@ -1562,38 +1542,6 @@ export function registerControlUiAndPairingSuite(): void {
15621542}
15631543});
156415441565-test("allows gateway backend clients on loopback even with a remote-looking host header", async () => {
1566-const { server, port, prevToken } = await startControlUiServer("secret");
1567-const wsRemoteLike = await openWs(port, { host: "gateway.example" });
1568-try {
1569-const remoteLikeBackend = await connectReq(wsRemoteLike, {
1570-token: "secret",
1571-client: BACKEND_GATEWAY_CLIENT,
1572-});
1573-expect(remoteLikeBackend.ok).toBe(true);
1574-} finally {
1575-wsRemoteLike.close();
1576-await server.close();
1577-restoreGatewayToken(prevToken);
1578-}
1579-});
1580-1581-test("allows gateway backend clients on loopback with a private host header", async () => {
1582-const { server, port, prevToken } = await startControlUiServer("secret");
1583-const wsPrivateHost = await openWs(port, { host: "172.17.0.2:18789" });
1584-try {
1585-const remoteLikeBackend = await connectReq(wsPrivateHost, {
1586-token: "secret",
1587-client: BACKEND_GATEWAY_CLIENT,
1588-});
1589-expect(remoteLikeBackend.ok).toBe(true);
1590-} finally {
1591-wsPrivateHost.close();
1592-await server.close();
1593-restoreGatewayToken(prevToken);
1594-}
1595-});
1596-15971545test("allows CLI clients on loopback even when the host header is not private-or-loopback", async () => {
15981546const { server, port, prevToken } = await startControlUiServer("secret");
15991547const wsRemoteLike = await openWs(port, { host: "gateway.example" });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。