























@@ -888,6 +888,116 @@ describe("deviceHandlers", () => {
888888);
889889});
890890891+it("allows non-device operator sessions to approve operator roles within caller scopes", async () => {
892+getPendingDevicePairingMock.mockResolvedValue({
893+requestId: "req-1",
894+deviceId: "device-2",
895+publicKey: "pk-2",
896+role: "operator",
897+roles: ["operator"],
898+scopes: ["operator.pairing"],
899+ts: 100,
900+});
901+approveDevicePairingMock.mockResolvedValue({
902+status: "approved",
903+requestId: "req-1",
904+device: {
905+deviceId: "device-2",
906+publicKey: "pk-2",
907+role: "operator",
908+roles: ["operator"],
909+approvedScopes: ["operator.pairing"],
910+approvedAtMs: 100,
911+createdAtMs: 50,
912+},
913+});
914+const opts = createOptions(
915+"device.pair.approve",
916+{ requestId: "req-1" },
917+{ client: createClient(["operator.pairing"]) },
918+);
919+920+await deviceHandlers["device.pair.approve"](opts);
921+922+expect(getPendingDevicePairingMock).toHaveBeenCalledWith("req-1");
923+expect(approveDevicePairingMock).toHaveBeenCalledWith("req-1", {
924+callerScopes: ["operator.pairing"],
925+});
926+expect(opts.respond).toHaveBeenCalledWith(
927+true,
928+{
929+requestId: "req-1",
930+device: {
931+deviceId: "device-2",
932+publicKey: "pk-2",
933+role: "operator",
934+roles: ["operator"],
935+approvedAtMs: 100,
936+createdAtMs: 50,
937+tokens: undefined,
938+},
939+},
940+undefined,
941+);
942+});
943+944+it("rejects approving node roles from non-admin shared-auth sessions", async () => {
945+getPendingDevicePairingMock.mockResolvedValue({
946+requestId: "req-1",
947+deviceId: "device-2",
948+publicKey: "pk-2",
949+role: "node",
950+roles: ["node"],
951+ts: 100,
952+});
953+const opts = createOptions(
954+"device.pair.approve",
955+{ requestId: "req-1" },
956+{ client: createClient(["operator.pairing"]) },
957+);
958+959+await deviceHandlers["device.pair.approve"](opts);
960+961+expect(approveDevicePairingMock).not.toHaveBeenCalled();
962+expectRespondedErrorMessage(opts, "device pairing approval denied");
963+});
964+965+it("rejects approving mixed operator and node roles from non-admin sessions", async () => {
966+getPendingDevicePairingMock.mockResolvedValue({
967+requestId: "req-1",
968+deviceId: "device-2",
969+publicKey: "pk-2",
970+role: "operator",
971+roles: [" operator ", " node "],
972+scopes: ["operator.pairing"],
973+ts: 100,
974+});
975+const opts = createOptions(
976+"device.pair.approve",
977+{ requestId: "req-1" },
978+{ client: createClient(["operator.pairing"]) },
979+);
980+981+await deviceHandlers["device.pair.approve"](opts);
982+983+expect(approveDevicePairingMock).not.toHaveBeenCalled();
984+expectRespondedErrorMessage(opts, "device pairing approval denied");
985+});
986+987+it("denies unknown approvals from non-admin non-device sessions", async () => {
988+getPendingDevicePairingMock.mockResolvedValue(null);
989+const opts = createOptions(
990+"device.pair.approve",
991+{ requestId: "missing" },
992+{ client: createClient(["operator.pairing"]) },
993+);
994+995+await deviceHandlers["device.pair.approve"](opts);
996+997+expect(approveDevicePairingMock).not.toHaveBeenCalled();
998+expectRespondedErrorMessage(opts, "device pairing approval denied");
999+});
1000+8911001it("rejects approving node roles for the caller device without admin scope", async () => {
8921002getPendingDevicePairingMock.mockResolvedValue({
8931003requestId: "req-1",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。