




















@@ -89,6 +89,7 @@ type ApprovedPairingResult = Extract<
8989>;
9090type ApprovedPairingDevice = ApprovedPairingResult["device"];
9191const INTERNAL_PAIRING_SCOPES = ["operator.write", "operator.pairing"];
92+const INTERNAL_SETUP_SCOPES = [...INTERNAL_PAIRING_SCOPES, "operator.talk.secrets"];
92939394function createApi(params?: {
9495config?: OpenClawPluginApi["config"];
@@ -286,7 +287,7 @@ describe("device-pair /pair qr", () => {
286287const result = await command.handler(
287288createCommandContext({
288289channel: "webchat",
289-gatewayClientScopes: ["operator.write", "operator.pairing"],
290+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
290291}),
291292);
292293const payload = result as { text?: string; mediaUrl?: string; sensitiveMedia?: boolean };
@@ -342,6 +343,23 @@ describe("device-pair /pair qr", () => {
342343});
343344});
344345346+it("rejects qr setup for internal callers without Talk secret scope", async () => {
347+const command = registerPairCommand();
348+const result = await command.handler(
349+createCommandContext({
350+channel: "webchat",
351+args: "qr",
352+commandBody: "/pair qr",
353+gatewayClientScopes: INTERNAL_PAIRING_SCOPES,
354+}),
355+);
356+357+expect(pluginApiMocks.issueDeviceBootstrapToken).not.toHaveBeenCalled();
358+expect(result).toEqual({
359+text: "⚠️ Setup code handoff includes Talk secrets and requires operator.talk.secrets.",
360+});
361+});
362+345363it("reissues the bootstrap token if webchat QR rendering fails before falling back", async () => {
346364pluginApiMocks.issueDeviceBootstrapToken
347365.mockResolvedValueOnce({
@@ -358,7 +376,7 @@ describe("device-pair /pair qr", () => {
358376const result = await command.handler(
359377createCommandContext({
360378channel: "webchat",
361-gatewayClientScopes: ["operator.write", "operator.pairing"],
379+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
362380}),
363381);
364382const text = requireText(result);
@@ -478,7 +496,7 @@ describe("device-pair /pair qr", () => {
478496const result = await command.handler(
479497createCommandContext({
480498 ...testCase.ctx,
481-gatewayClientScopes: INTERNAL_PAIRING_SCOPES,
499+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
482500}),
483501);
484502const text = requireText(result);
@@ -538,7 +556,7 @@ describe("device-pair /pair qr", () => {
538556createCommandContext({
539557channel: "discord",
540558senderId: "123",
541-gatewayClientScopes: INTERNAL_PAIRING_SCOPES,
559+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
542560}),
543561);
544562const text = requireText(result);
@@ -557,7 +575,7 @@ describe("device-pair /pair qr", () => {
557575createCommandContext({
558576channel: "msteams",
559577senderId: "8:orgid:123",
560-gatewayClientScopes: INTERNAL_PAIRING_SCOPES,
578+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
561579}),
562580);
563581const text = requireText(result);
@@ -678,6 +696,23 @@ describe("device-pair /pair default setup code", () => {
678696});
679697});
680698699+it("rejects setup code issuance for internal callers without Talk secret scope", async () => {
700+const command = registerPairCommand();
701+const result = await command.handler(
702+createCommandContext({
703+channel: "webchat",
704+args: "",
705+commandBody: "/pair",
706+gatewayClientScopes: INTERNAL_PAIRING_SCOPES,
707+}),
708+);
709+710+expect(pluginApiMocks.issueDeviceBootstrapToken).not.toHaveBeenCalled();
711+expect(result).toEqual({
712+text: "⚠️ Setup code handoff includes Talk secrets and requires operator.talk.secrets.",
713+});
714+});
715+681716it("fails closed for webchat setup code issuance when scopes are absent", async () => {
682717const command = registerPairCommand();
683718const result = await command.handler(
@@ -749,7 +784,7 @@ describe("device-pair /pair default setup code", () => {
749784channel: "webchat",
750785args: "",
751786commandBody: "/pair",
752-gatewayClientScopes: ["operator.write", "operator.pairing"],
787+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
753788}),
754789);
755790const text = requireText(result);
@@ -769,7 +804,7 @@ describe("device-pair /pair default setup code", () => {
769804channel: "webchat",
770805args: "",
771806commandBody: "/pair",
772-gatewayClientScopes: ["operator.write", "operator.pairing"],
807+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
773808}),
774809);
775810const text = requireText(result);
@@ -789,7 +824,7 @@ describe("device-pair /pair default setup code", () => {
789824channel: "webchat",
790825args: "",
791826commandBody: "/pair",
792-gatewayClientScopes: ["operator.write", "operator.pairing"],
827+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
793828}),
794829);
795830@@ -808,7 +843,7 @@ describe("device-pair /pair default setup code", () => {
808843channel: "webchat",
809844args: "",
810845commandBody: "/pair",
811-gatewayClientScopes: ["operator.write", "operator.pairing"],
846+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
812847}),
813848);
814849@@ -827,7 +862,7 @@ describe("device-pair /pair default setup code", () => {
827862channel: "webchat",
828863args: "",
829864commandBody: "/pair",
830-gatewayClientScopes: ["operator.write", "operator.pairing"],
865+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
831866}),
832867);
833868@@ -861,7 +896,7 @@ describe("device-pair /pair default setup code", () => {
861896channel: "webchat",
862897args: "",
863898commandBody: "/pair",
864-gatewayClientScopes: ["operator.write", "operator.pairing"],
899+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
865900}),
866901);
867902@@ -890,7 +925,7 @@ describe("device-pair /pair default setup code", () => {
890925channel: "webchat",
891926args: "",
892927commandBody: "/pair",
893-gatewayClientScopes: ["operator.write", "operator.pairing"],
928+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
894929}),
895930);
896931const text = requireText(result);
@@ -910,7 +945,7 @@ describe("device-pair /pair default setup code", () => {
910945channel: "webchat",
911946args: "",
912947commandBody: "/pair",
913-gatewayClientScopes: ["operator.write", "operator.pairing"],
948+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
914949}),
915950);
916951@@ -940,7 +975,7 @@ describe("device-pair /pair default setup code", () => {
940975channel: "webchat",
941976args: "",
942977commandBody: "/pair",
943-gatewayClientScopes: ["operator.write", "operator.pairing"],
978+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
944979}),
945980);
946981@@ -967,7 +1002,7 @@ describe("device-pair /pair default setup code", () => {
9671002channel: "webchat",
9681003args: "",
9691004commandBody: "/pair",
970-gatewayClientScopes: ["operator.write", "operator.pairing"],
1005+gatewayClientScopes: INTERNAL_SETUP_SCOPES,
9711006}),
9721007);
9731008此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。