




























@@ -1,32 +1,28 @@
1-import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
2-3-const callGatewayMock = vi.fn();
4-const configState = vi.hoisted(() => ({
5-value: {} as Record<string, unknown>,
1+import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
2+import { callGatewayTool, resolveGatewayOptions } from "./gateway.js";
3+4+const mocks = vi.hoisted(() => ({
5+callGateway: vi.fn(),
6+configState: {
7+value: {} as Record<string, unknown>,
8+},
69}));
710vi.mock("../../config/config.js", () => ({
8-getRuntimeConfig: () => configState.value,
11+getRuntimeConfig: () => mocks.configState.value,
912resolveGatewayPort: () => 18789,
1013}));
1114vi.mock("../../gateway/call.js", () => ({
12-callGateway: (...args: unknown[]) => callGatewayMock(...args),
15+callGateway: (...args: unknown[]) => mocks.callGateway(...args),
1316}));
141715-let callGatewayTool: typeof import("./gateway.js").callGatewayTool;
16-let resolveGatewayOptions: typeof import("./gateway.js").resolveGatewayOptions;
17-1818describe("gateway tool defaults", () => {
1919const envSnapshot = {
2020openclaw: process.env.OPENCLAW_GATEWAY_TOKEN,
2121};
222223-beforeAll(async () => {
24-({ callGatewayTool, resolveGatewayOptions } = await import("./gateway.js"));
25-});
26-2723beforeEach(() => {
28-callGatewayMock.mockClear();
29-configState.value = {};
24+mocks.callGateway.mockClear();
25+mocks.configState.value = {};
3026delete process.env.OPENCLAW_GATEWAY_TOKEN;
3127});
3228@@ -44,13 +40,13 @@ describe("gateway tool defaults", () => {
4440});
45414642it("accepts allowlisted gatewayUrl overrides (SSRF hardening)", async () => {
47-callGatewayMock.mockResolvedValueOnce({ ok: true });
43+mocks.callGateway.mockResolvedValueOnce({ ok: true });
4844await callGatewayTool(
4945"health",
5046{ gatewayUrl: "ws://127.0.0.1:18789", gatewayToken: "t", timeoutMs: 5000 },
5147{},
5248);
53-expect(callGatewayMock).toHaveBeenCalledWith(
49+expect(mocks.callGateway).toHaveBeenCalledWith(
5450expect.objectContaining({
5551url: "ws://127.0.0.1:18789",
5652token: "t",
@@ -68,7 +64,7 @@ describe("gateway tool defaults", () => {
6864});
69657066it("falls back to config gateway.auth.token when env is unset for local overrides", () => {
71-configState.value = {
67+mocks.configState.value = {
7268gateway: {
7369auth: { token: "config-token" },
7470},
@@ -78,7 +74,7 @@ describe("gateway tool defaults", () => {
7874});
79758076it("uses gateway.remote.token for allowlisted remote overrides", () => {
81-configState.value = {
77+mocks.configState.value = {
8278gateway: {
8379remote: {
8480url: "wss://gateway.example",
@@ -93,7 +89,7 @@ describe("gateway tool defaults", () => {
93899490it("does not leak local env/config tokens to remote overrides", () => {
9591process.env.OPENCLAW_GATEWAY_TOKEN = "local-env-token";
96-configState.value = {
92+mocks.configState.value = {
9793gateway: {
9894auth: { token: "local-config-token" },
9995remote: {
@@ -106,7 +102,7 @@ describe("gateway tool defaults", () => {
106102});
107103108104it("ignores unresolved local token SecretRef for strict remote overrides", () => {
109-configState.value = {
105+mocks.configState.value = {
110106gateway: {
111107auth: {
112108mode: "token",
@@ -128,7 +124,7 @@ describe("gateway tool defaults", () => {
128124129125it("explicit gatewayToken overrides fallback token resolution", () => {
130126process.env.OPENCLAW_GATEWAY_TOKEN = "local-env-token";
131-configState.value = {
127+mocks.configState.value = {
132128gateway: {
133129remote: {
134130url: "wss://gateway.example",
@@ -144,9 +140,9 @@ describe("gateway tool defaults", () => {
144140});
145141146142it("uses least-privilege write scope for write methods", async () => {
147-callGatewayMock.mockResolvedValueOnce({ ok: true });
143+mocks.callGateway.mockResolvedValueOnce({ ok: true });
148144await callGatewayTool("wake", {}, { mode: "now", text: "hi" });
149-expect(callGatewayMock).toHaveBeenCalledWith(
145+expect(mocks.callGateway).toHaveBeenCalledWith(
150146expect.objectContaining({
151147method: "wake",
152148scopes: ["operator.write"],
@@ -155,9 +151,9 @@ describe("gateway tool defaults", () => {
155151});
156152157153it("uses admin scope only for admin methods", async () => {
158-callGatewayMock.mockResolvedValueOnce({ ok: true });
154+mocks.callGateway.mockResolvedValueOnce({ ok: true });
159155await callGatewayTool("cron.add", {}, { id: "job-1" });
160-expect(callGatewayMock).toHaveBeenCalledWith(
156+expect(mocks.callGateway).toHaveBeenCalledWith(
161157expect.objectContaining({
162158method: "cron.add",
163159scopes: ["operator.admin"],
@@ -166,14 +162,14 @@ describe("gateway tool defaults", () => {
166162});
167163168164it("allows explicit scope overrides for dynamic callers", async () => {
169-callGatewayMock.mockResolvedValueOnce({ ok: true });
165+mocks.callGateway.mockResolvedValueOnce({ ok: true });
170166await callGatewayTool(
171167"node.pair.approve",
172168{},
173169{ requestId: "req-1" },
174170{ scopes: ["operator.admin"] },
175171);
176-expect(callGatewayMock).toHaveBeenCalledWith(
172+expect(mocks.callGateway).toHaveBeenCalledWith(
177173expect.objectContaining({
178174method: "node.pair.approve",
179175scopes: ["operator.admin"],
@@ -182,9 +178,9 @@ describe("gateway tool defaults", () => {
182178});
183179184180it("default-denies unknown methods by sending no scopes", async () => {
185-callGatewayMock.mockResolvedValueOnce({ ok: true });
181+mocks.callGateway.mockResolvedValueOnce({ ok: true });
186182await callGatewayTool("nonexistent.method", {}, {});
187-expect(callGatewayMock).toHaveBeenCalledWith(
183+expect(mocks.callGateway).toHaveBeenCalledWith(
188184expect.objectContaining({
189185method: "nonexistent.method",
190186scopes: [],
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。