test: skip throwaway control ui auth clients

This commit is contained in:
Gustavo Madeira Santana
2026-04-17 19:25:19 -04:00
parent 5d8dceb37f
commit e2351b5fdc
3 changed files with 47 additions and 41 deletions

View File

@@ -21,6 +21,7 @@ import {
rpcReq,
startRateLimitedTokenServerWithPairedDeviceToken,
startGatewayServer,
startServer,
startServerWithClient,
TEST_OPERATOR_CLIENT,
testState,
@@ -142,6 +143,14 @@ export function registerControlUiAndPairingSuite(): void {
return { server, ws, port, prevToken, identityPath, identity, client };
};
const startControlUiServerWithOperatorIdentity = async (
identityPrefix = "openclaw-device-scope-",
) => {
const { server, port, prevToken } = await startControlUiServer("secret");
const { identityPath, identity, client } = await createOperatorIdentityFixture(identityPrefix);
return { server, port, prevToken, identityPath, identity, client };
};
const withControlUiGatewayServer = async <T>(
fn: (ctx: {
port: number;
@@ -163,6 +172,13 @@ export function registerControlUiAndPairingSuite(): void {
});
};
const startControlUiServer = async (token?: string, opts?: Parameters<typeof startServer>[1]) => {
return await startServer(token, {
...opts,
controlUiEnabled: true,
});
};
const getRequiredPairedMetadata = (
paired: Record<string, Record<string, unknown>>,
deviceId: string,
@@ -631,9 +647,8 @@ export function registerControlUiAndPairingSuite(): void {
test("auto-approves local-direct operator pairing despite a remote-looking host header", async () => {
const { getPairedDevice, listDevicePairing } = await import("../infra/device-pairing.js");
const { server, ws, port, prevToken, identityPath, identity, client } =
await startServerWithOperatorIdentity();
ws.close();
const { server, port, prevToken, identityPath, identity, client } =
await startControlUiServerWithOperatorIdentity();
const wsRemoteRead = await openWs(port, { host: "gateway.example" });
const initialNonce = await readConnectChallengeNonce(wsRemoteRead);
@@ -686,7 +701,7 @@ export function registerControlUiAndPairingSuite(): void {
test("requires approval for loopback scope upgrades for control ui clients", async () => {
const { getPairedDevice, listDevicePairing } = await import("../infra/device-pairing.js");
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
const { server, port, prevToken } = await startControlUiServer("secret");
const { identity, identityPath } = await seedApprovedOperatorReadPairing({
identityPrefix: "openclaw-device-token-scope-",
clientId: CONTROL_UI_CLIENT.id,
@@ -695,8 +710,6 @@ export function registerControlUiAndPairingSuite(): void {
platform: CONTROL_UI_CLIENT.platform,
});
ws.close();
const ws2 = await openWs(port, { origin: originForPort(port) });
const nonce2 = await readConnectChallengeNonce(ws2);
const upgraded = await connectReq(ws2, {
@@ -730,8 +743,7 @@ export function registerControlUiAndPairingSuite(): void {
const { publicKeyRawBase64UrlFromPem } = await import("../infra/device-identity.js");
const { getPairedDevice, listDevicePairing, verifyDeviceToken } =
await import("../infra/device-pairing.js");
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const { identityPath, identity } = await createOperatorIdentityFixture(
"openclaw-bootstrap-node-",
@@ -901,8 +913,7 @@ export function registerControlUiAndPairingSuite(): void {
const reconcileSpy = vi
.spyOn(reconcileModule, "reconcileNodePairingOnConnect")
.mockRejectedValueOnce(new Error("boom"));
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const { identityPath, client } = await createOperatorIdentityFixture(
"openclaw-bootstrap-reconcile-fail-",
@@ -960,8 +971,7 @@ export function registerControlUiAndPairingSuite(): void {
const { approveDevicePairing, getPairedDevice, listDevicePairing, requestDevicePairing } =
await import("../infra/device-pairing.js");
const { publicKeyRawBase64UrlFromPem } = await import("../infra/device-identity.js");
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const { identityPath, identity } = await createOperatorIdentityFixture(
"openclaw-bootstrap-role-upgrade-",
@@ -1031,8 +1041,7 @@ export function registerControlUiAndPairingSuite(): void {
test("requires approval for bootstrap-auth operator pairing outside the qr baseline profile", async () => {
const { issueDeviceBootstrapToken } = await import("../infra/device-bootstrap.js");
const { getPairedDevice, listDevicePairing } = await import("../infra/device-pairing.js");
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const { identityPath, identity, client } = await createOperatorIdentityFixture(
"openclaw-bootstrap-operator-",
@@ -1076,8 +1085,7 @@ export function registerControlUiAndPairingSuite(): void {
test("auto-approves local-direct node pairing, then queues operator scope approval", async () => {
const { getPairedDevice, listDevicePairing } = await import("../infra/device-pairing.js");
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const { identityPath, identity, client } =
await createOperatorIdentityFixture("openclaw-device-scope-");
const connectWithNonce = async (role: "operator" | "node", scopes: string[]) => {
@@ -1209,11 +1217,9 @@ export function registerControlUiAndPairingSuite(): void {
await stripPairedMetadataRolesAndScopes(deviceId);
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
const { server, port, prevToken } = await startControlUiServer("secret");
let ws2: WebSocket | undefined;
try {
ws.close();
const wsReconnect = await openWs(port);
ws2 = wsReconnect;
const reconnectNonce = await readConnectChallengeNonce(wsReconnect);
@@ -1239,7 +1245,6 @@ export function registerControlUiAndPairingSuite(): void {
} finally {
await server.close();
restoreGatewayToken(prevToken);
ws.close();
ws2?.close();
}
});
@@ -1256,13 +1261,11 @@ export function registerControlUiAndPairingSuite(): void {
await stripPairedMetadataRolesAndScopes(identity.deviceId);
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
const { server, port, prevToken } = await startControlUiServer("secret");
let ws2: WebSocket | undefined;
try {
const client = { ...TEST_OPERATOR_CLIENT };
ws.close();
const wsUpgrade = await openWs(port);
ws2 = wsUpgrade;
const upgradeNonce = await readConnectChallengeNonce(wsUpgrade);
@@ -1290,7 +1293,6 @@ export function registerControlUiAndPairingSuite(): void {
expect(repaired?.role).toBe("operator");
expect(repaired?.approvedScopes ?? []).toEqual(expect.arrayContaining(["operator.read"]));
} finally {
ws.close();
ws2?.close();
await server.close();
restoreGatewayToken(prevToken);
@@ -1337,8 +1339,7 @@ export function registerControlUiAndPairingSuite(): void {
test("auto-approves Docker-style CLI connects on loopback with a private host header", async () => {
const { getPairedDevice, listDevicePairing } = await import("../infra/device-pairing.js");
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const wsDockerCli = await openWs(port, { host: "172.17.0.2:18789" });
try {
const { identity, identityPath } =
@@ -1374,8 +1375,7 @@ export function registerControlUiAndPairingSuite(): void {
});
test("allows gateway backend clients on loopback even with a remote-looking host header", async () => {
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const wsRemoteLike = await openWs(port, { host: "gateway.example" });
try {
const remoteLikeBackend = await connectReq(wsRemoteLike, {
@@ -1391,8 +1391,7 @@ export function registerControlUiAndPairingSuite(): void {
});
test("allows gateway backend clients on loopback with a private host header", async () => {
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const wsPrivateHost = await openWs(port, { host: "172.17.0.2:18789" });
try {
const remoteLikeBackend = await connectReq(wsPrivateHost, {
@@ -1408,8 +1407,7 @@ export function registerControlUiAndPairingSuite(): void {
});
test("allows CLI clients on loopback even when the host header is not private-or-loopback", async () => {
const { server, ws, port, prevToken } = await startControlUiServerWithClient("secret");
ws.close();
const { server, port, prevToken } = await startControlUiServer("secret");
const wsRemoteLike = await openWs(port, { host: "gateway.example" });
try {
const remoteCli = await connectReq(wsRemoteLike, {

View File

@@ -15,6 +15,7 @@ import {
onceMessage,
rpcReq,
startGatewayServer,
startServer,
startServerWithClient,
trackConnectChallengeNonce,
testTailscaleWhois,
@@ -395,6 +396,7 @@ export {
sendRawConnectReq,
startGatewayServer,
startRateLimitedTokenServerWithPairedDeviceToken,
startServer,
startServerWithClient,
TEST_OPERATOR_CLIENT,
trackConnectChallengeNonce,

View File

@@ -712,11 +712,7 @@ export async function createGatewaySuiteHarness(opts?: {
};
}
export async function startServerWithClient(
token?: string,
opts?: GatewayServerOptions & { wsHeaders?: Record<string, string> },
) {
const { wsHeaders, ...gatewayOpts } = opts ?? {};
export async function startServer(token?: string, opts?: GatewayServerOptions) {
let port = await getFreePort();
const envSnapshot = captureEnv(["OPENCLAW_GATEWAY_TOKEN"]);
const prev = process.env.OPENCLAW_GATEWAY_TOKEN;
@@ -735,19 +731,29 @@ export async function startServerWithClient(
}
const resolvedGatewayOpts: GatewayServerOptions =
fallbackToken && !gatewayOpts.auth
fallbackToken && !opts?.auth
? {
...gatewayOpts,
...opts,
auth: { mode: "token", token: fallbackToken },
}
: gatewayOpts;
: (opts ?? {});
const started = await startGatewayServerWithRetries({ port, opts: resolvedGatewayOpts });
port = started.port;
const server = started.server;
return { server, port, prevToken: prev, envSnapshot };
}
export async function startServerWithClient(
token?: string,
opts?: GatewayServerOptions & { wsHeaders?: Record<string, string> },
) {
const { wsHeaders, ...gatewayOpts } = opts ?? {};
const started = await startServer(token, gatewayOpts);
const { server, port, prevToken, envSnapshot } = started;
const ws = await openTrackedWebSocket({ port, headers: wsHeaders });
return { server, ws, port, prevToken: prev, envSnapshot };
return { server, ws, port, prevToken, envSnapshot };
}
export async function startConnectedServerWithClient(