


























@@ -8,6 +8,7 @@ import {
88normalizeDeclaredNodeCommands,
99resolveNodeCommandAllowlist,
1010} from "./node-command-policy.js";
11+import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "./protocol/client-info.js";
11121213describe("gateway/node-command-policy", () => {
1314afterEach(() => {
@@ -102,6 +103,140 @@ describe("gateway/node-command-policy", () => {
102103expect(allowlist.has("canvas.present")).toBe(true);
103104});
104105106+it("does not grant host command defaults for platform prefix aliases", () => {
107+const cfg = {} as OpenClawConfig;
108+const cases = [
109+{ platform: "darwin", deviceFamily: "iPhone" },
110+{ platform: "darwin", deviceFamily: "Mac" },
111+{ platform: "macos" },
112+{ platform: "macos", deviceFamily: "Mac" },
113+{ platform: "macos", deviceFamily: "iPhone" },
114+{ platform: "macOS 26.3.1", deviceFamily: "iPhone" },
115+{ platform: "macOS 26.3.1", deviceFamily: "Mac" },
116+{ platform: "windows" },
117+{ platform: "windows", deviceFamily: "Windows" },
118+{ platform: "windows", deviceFamily: "iPhone" },
119+{ platform: "linux" },
120+{ platform: "linux", deviceFamily: "Linux" },
121+{ platform: "linux", deviceFamily: "iPhone" },
122+{ platform: "Darwin-x64" },
123+{ platform: "macintosh" },
124+{ platform: "win32" },
125+{ platform: "linux-gnu" },
126+{
127+platform: "macos",
128+deviceFamily: "Mac",
129+clientId: GATEWAY_CLIENT_IDS.NODE_HOST,
130+clientMode: GATEWAY_CLIENT_MODES.NODE,
131+},
132+];
133+134+for (const node of cases) {
135+const allowlist = resolveNodeCommandAllowlist(cfg, node);
136+expect(allowlist.has("system.run")).toBe(false);
137+expect(allowlist.has("system.run.prepare")).toBe(false);
138+expect(allowlist.has("system.which")).toBe(false);
139+expect(allowlist.has("browser.proxy")).toBe(false);
140+expect(allowlist.has("screen.snapshot")).toBe(false);
141+expect(allowlist.has("system.notify")).toBe(true);
142+}
143+});
144+145+it("keeps defaults for first-party native platform labels with matching families", () => {
146+const cfg = {} as OpenClawConfig;
147+148+const iosAllowlist = resolveNodeCommandAllowlist(cfg, {
149+platform: "iOS 18.4.0",
150+deviceFamily: "iPhone",
151+});
152+expect(iosAllowlist.has("device.info")).toBe(true);
153+expect(iosAllowlist.has("photos.latest")).toBe(true);
154+expect(iosAllowlist.has("system.run")).toBe(false);
155+156+const ipadAllowlist = resolveNodeCommandAllowlist(cfg, {
157+platform: "iPadOS 18.4.0",
158+deviceFamily: "iPad",
159+});
160+expect(ipadAllowlist.has("device.info")).toBe(true);
161+expect(ipadAllowlist.has("motion.activity")).toBe(true);
162+expect(ipadAllowlist.has("system.run")).toBe(false);
163+164+const macAllowlist = resolveNodeCommandAllowlist(cfg, {
165+platform: "macOS 15.5.0",
166+deviceFamily: "Mac",
167+});
168+expect(macAllowlist.has("system.run")).toBe(false);
169+expect(macAllowlist.has("system.which")).toBe(false);
170+expect(macAllowlist.has("screen.snapshot")).toBe(false);
171+});
172+173+it("keeps explicitly approved host commands for desktop platforms", () => {
174+const cfg = {} as OpenClawConfig;
175+const cases = [
176+{ platform: "macos", deviceFamily: "Mac" },
177+{ platform: "windows", deviceFamily: "Windows" },
178+{ platform: "linux", deviceFamily: "Linux" },
179+];
180+181+for (const node of cases) {
182+const allowlist = resolveNodeCommandAllowlist(cfg, {
183+ ...node,
184+approvedCommands: ["system.run", "system.which"],
185+});
186+expect(allowlist.has("system.run")).toBe(true);
187+expect(allowlist.has("system.which")).toBe(true);
188+}
189+});
190+191+it("keeps approved host commands on live desktop node sessions", () => {
192+const allowlist = resolveNodeCommandAllowlist({} as OpenClawConfig, {
193+nodeId: "node-1",
194+connId: "conn-1",
195+platform: "linux",
196+deviceFamily: "Linux",
197+commands: ["browser.proxy", "system.run"],
198+});
199+200+expect(allowlist.has("browser.proxy")).toBe(true);
201+expect(allowlist.has("system.run")).toBe(true);
202+});
203+204+it("does not treat unconnected declared host commands as approved", () => {
205+const allowlist = resolveNodeCommandAllowlist({} as OpenClawConfig, {
206+platform: "linux",
207+deviceFamily: "Linux",
208+commands: ["browser.proxy", "system.run"],
209+});
210+211+expect(allowlist.has("browser.proxy")).toBe(false);
212+expect(allowlist.has("system.run")).toBe(false);
213+});
214+215+it("does not grandfather approved non-default commands after config removal", () => {
216+const staleApproval = resolveNodeCommandAllowlist({} as OpenClawConfig, {
217+platform: "macos",
218+deviceFamily: "Mac",
219+approvedCommands: ["screen.record"],
220+});
221+expect(staleApproval.has("screen.record")).toBe(false);
222+223+const currentConfigApproval = resolveNodeCommandAllowlist(
224+{
225+gateway: {
226+nodes: {
227+allowCommands: ["screen.record"],
228+},
229+},
230+} as OpenClawConfig,
231+{
232+platform: "macos",
233+deviceFamily: "Mac",
234+approvedCommands: ["screen.record"],
235+},
236+);
237+expect(currentConfigApproval.has("screen.record")).toBe(true);
238+});
239+105240it("reads foreground restriction metadata from plugin node policies", () => {
106241expect(isForegroundRestrictedPluginNodeCommand("canvas.snapshot")).toBe(false);
107242此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。