mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 22:01:35 +00:00
refactor(cli): dedupe device role validation for token ops
This commit is contained in:
@@ -192,3 +192,64 @@ describe("devices cli clear", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("devices cli tokens", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
callGateway.mockReset();
|
||||||
|
withProgress.mockClear();
|
||||||
|
runtime.log.mockReset();
|
||||||
|
runtime.error.mockReset();
|
||||||
|
runtime.exit.mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rotates a token for a device role", async () => {
|
||||||
|
callGateway.mockResolvedValueOnce({ ok: true });
|
||||||
|
|
||||||
|
await runDevicesCommand([
|
||||||
|
"rotate",
|
||||||
|
"--device",
|
||||||
|
"device-1",
|
||||||
|
"--role",
|
||||||
|
"main",
|
||||||
|
"--scope",
|
||||||
|
"messages:send",
|
||||||
|
"--scope",
|
||||||
|
"messages:read",
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(callGateway).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
method: "device.token.rotate",
|
||||||
|
params: {
|
||||||
|
deviceId: "device-1",
|
||||||
|
role: "main",
|
||||||
|
scopes: ["messages:send", "messages:read"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("revokes a token for a device role", async () => {
|
||||||
|
callGateway.mockResolvedValueOnce({ ok: true });
|
||||||
|
|
||||||
|
await runDevicesCommand(["revoke", "--device", "device-1", "--role", "main"]);
|
||||||
|
|
||||||
|
expect(callGateway).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
method: "device.token.revoke",
|
||||||
|
params: {
|
||||||
|
deviceId: "device-1",
|
||||||
|
role: "main",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects blank device or role values", async () => {
|
||||||
|
await runDevicesCommand(["rotate", "--device", " ", "--role", "main"]);
|
||||||
|
|
||||||
|
expect(callGateway).not.toHaveBeenCalled();
|
||||||
|
expect(runtime.error).toHaveBeenCalledWith("--device and --role required");
|
||||||
|
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -110,6 +110,19 @@ function formatTokenSummary(tokens: DeviceTokenSummary[] | undefined) {
|
|||||||
return parts.join(", ");
|
return parts.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRequiredDeviceRole(
|
||||||
|
opts: DevicesRpcOpts,
|
||||||
|
): { deviceId: string; role: string } | null {
|
||||||
|
const deviceId = String(opts.device ?? "").trim();
|
||||||
|
const role = String(opts.role ?? "").trim();
|
||||||
|
if (deviceId && role) {
|
||||||
|
return { deviceId, role };
|
||||||
|
}
|
||||||
|
defaultRuntime.error("--device and --role required");
|
||||||
|
defaultRuntime.exit(1);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function registerDevicesCli(program: Command) {
|
export function registerDevicesCli(program: Command) {
|
||||||
const devices = program.command("devices").description("Device pairing and auth tokens");
|
const devices = program.command("devices").description("Device pairing and auth tokens");
|
||||||
|
|
||||||
@@ -318,16 +331,13 @@ export function registerDevicesCli(program: Command) {
|
|||||||
.requiredOption("--role <role>", "Role name")
|
.requiredOption("--role <role>", "Role name")
|
||||||
.option("--scope <scope...>", "Scopes to attach to the token (repeatable)")
|
.option("--scope <scope...>", "Scopes to attach to the token (repeatable)")
|
||||||
.action(async (opts: DevicesRpcOpts) => {
|
.action(async (opts: DevicesRpcOpts) => {
|
||||||
const deviceId = String(opts.device ?? "").trim();
|
const required = resolveRequiredDeviceRole(opts);
|
||||||
const role = String(opts.role ?? "").trim();
|
if (!required) {
|
||||||
if (!deviceId || !role) {
|
|
||||||
defaultRuntime.error("--device and --role required");
|
|
||||||
defaultRuntime.exit(1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const result = await callGatewayCli("device.token.rotate", opts, {
|
const result = await callGatewayCli("device.token.rotate", opts, {
|
||||||
deviceId,
|
deviceId: required.deviceId,
|
||||||
role,
|
role: required.role,
|
||||||
scopes: Array.isArray(opts.scope) ? opts.scope : undefined,
|
scopes: Array.isArray(opts.scope) ? opts.scope : undefined,
|
||||||
});
|
});
|
||||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||||
@@ -341,16 +351,13 @@ export function registerDevicesCli(program: Command) {
|
|||||||
.requiredOption("--device <id>", "Device id")
|
.requiredOption("--device <id>", "Device id")
|
||||||
.requiredOption("--role <role>", "Role name")
|
.requiredOption("--role <role>", "Role name")
|
||||||
.action(async (opts: DevicesRpcOpts) => {
|
.action(async (opts: DevicesRpcOpts) => {
|
||||||
const deviceId = String(opts.device ?? "").trim();
|
const required = resolveRequiredDeviceRole(opts);
|
||||||
const role = String(opts.role ?? "").trim();
|
if (!required) {
|
||||||
if (!deviceId || !role) {
|
|
||||||
defaultRuntime.error("--device and --role required");
|
|
||||||
defaultRuntime.exit(1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const result = await callGatewayCli("device.token.revoke", opts, {
|
const result = await callGatewayCli("device.token.revoke", opts, {
|
||||||
deviceId,
|
deviceId: required.deviceId,
|
||||||
role,
|
role: required.role,
|
||||||
});
|
});
|
||||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user