mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 02:11:23 +00:00
fix(node): default mac headless system.run to local host
Co-authored-by: aethnova <262512133+aethnova@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { formatSystemRunAllowlistMissMessage } from "./invoke-system-run.js";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { ExecHostResponse } from "../infra/exec-host.js";
|
||||
import { handleSystemRunInvoke, formatSystemRunAllowlistMissMessage } from "./invoke-system-run.js";
|
||||
|
||||
describe("formatSystemRunAllowlistMissMessage", () => {
|
||||
it("returns legacy allowlist miss message by default", () => {
|
||||
@@ -14,3 +15,102 @@ describe("formatSystemRunAllowlistMissMessage", () => {
|
||||
).toContain("Windows shell wrappers like cmd.exe /c require approval");
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleSystemRunInvoke mac app exec host routing", () => {
|
||||
async function runSystemInvoke(params: {
|
||||
preferMacAppExecHost: boolean;
|
||||
runViaResponse?: ExecHostResponse | null;
|
||||
}) {
|
||||
const runCommand = vi.fn(async () => ({
|
||||
success: true,
|
||||
stdout: "local-ok",
|
||||
stderr: "",
|
||||
timedOut: false,
|
||||
truncated: false,
|
||||
exitCode: 0,
|
||||
error: null,
|
||||
}));
|
||||
const runViaMacAppExecHost = vi.fn(async () => params.runViaResponse ?? null);
|
||||
const sendInvokeResult = vi.fn(async () => {});
|
||||
const sendExecFinishedEvent = vi.fn(async () => {});
|
||||
|
||||
await handleSystemRunInvoke({
|
||||
client: {} as never,
|
||||
params: {
|
||||
command: ["echo", "ok"],
|
||||
approved: true,
|
||||
sessionKey: "agent:main:main",
|
||||
},
|
||||
skillBins: {
|
||||
current: async () => new Set<string>(),
|
||||
},
|
||||
execHostEnforced: false,
|
||||
execHostFallbackAllowed: true,
|
||||
resolveExecSecurity: () => "full",
|
||||
resolveExecAsk: () => "off",
|
||||
isCmdExeInvocation: () => false,
|
||||
sanitizeEnv: () => undefined,
|
||||
runCommand,
|
||||
runViaMacAppExecHost,
|
||||
sendNodeEvent: async () => {},
|
||||
buildExecEventPayload: (payload) => payload,
|
||||
sendInvokeResult,
|
||||
sendExecFinishedEvent,
|
||||
preferMacAppExecHost: params.preferMacAppExecHost,
|
||||
});
|
||||
|
||||
return { runCommand, runViaMacAppExecHost, sendInvokeResult, sendExecFinishedEvent };
|
||||
}
|
||||
|
||||
it("uses local execution by default when mac app exec host preference is disabled", async () => {
|
||||
const { runCommand, runViaMacAppExecHost, sendInvokeResult } = await runSystemInvoke({
|
||||
preferMacAppExecHost: false,
|
||||
});
|
||||
|
||||
expect(runViaMacAppExecHost).not.toHaveBeenCalled();
|
||||
expect(runCommand).toHaveBeenCalledTimes(1);
|
||||
expect(sendInvokeResult).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
ok: true,
|
||||
payloadJSON: expect.stringContaining("local-ok"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("uses mac app exec host when explicitly preferred", async () => {
|
||||
const { runCommand, runViaMacAppExecHost, sendInvokeResult } = await runSystemInvoke({
|
||||
preferMacAppExecHost: true,
|
||||
runViaResponse: {
|
||||
ok: true,
|
||||
payload: {
|
||||
success: true,
|
||||
stdout: "app-ok",
|
||||
stderr: "",
|
||||
timedOut: false,
|
||||
truncated: false,
|
||||
exitCode: 0,
|
||||
error: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(runViaMacAppExecHost).toHaveBeenCalledWith({
|
||||
approvals: expect.objectContaining({
|
||||
agent: expect.objectContaining({
|
||||
security: "full",
|
||||
ask: "off",
|
||||
}),
|
||||
}),
|
||||
request: expect.objectContaining({
|
||||
command: ["echo", "ok"],
|
||||
}),
|
||||
});
|
||||
expect(runCommand).not.toHaveBeenCalled();
|
||||
expect(sendInvokeResult).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
ok: true,
|
||||
payloadJSON: expect.stringContaining("app-ok"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,6 +70,7 @@ export async function handleSystemRunInvoke(opts: {
|
||||
success?: boolean;
|
||||
};
|
||||
}) => Promise<void>;
|
||||
preferMacAppExecHost: boolean;
|
||||
}): Promise<void> {
|
||||
const command = resolveSystemRunCommand({
|
||||
command: opts.params.command,
|
||||
@@ -166,7 +167,7 @@ export async function handleSystemRunInvoke(opts: {
|
||||
? opts.isCmdExeInvocation(segments[0]?.argv ?? [])
|
||||
: opts.isCmdExeInvocation(argv);
|
||||
|
||||
const useMacAppExec = process.platform === "darwin";
|
||||
const useMacAppExec = opts.preferMacAppExecHost;
|
||||
if (useMacAppExec) {
|
||||
const execRequest: ExecHostRequest = {
|
||||
command: argv,
|
||||
|
||||
@@ -35,6 +35,7 @@ const DEFAULT_NODE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sb
|
||||
const execHostEnforced = process.env.OPENCLAW_NODE_EXEC_HOST?.trim().toLowerCase() === "app";
|
||||
const execHostFallbackAllowed =
|
||||
process.env.OPENCLAW_NODE_EXEC_FALLBACK?.trim().toLowerCase() !== "0";
|
||||
const preferMacAppExecHost = process.platform === "darwin" && execHostEnforced;
|
||||
|
||||
type SystemWhichParams = {
|
||||
bins: string[];
|
||||
@@ -457,6 +458,7 @@ export async function handleInvoke(
|
||||
sendExecFinishedEvent: async ({ sessionKey, runId, cmdText, result }) => {
|
||||
await sendExecFinishedEvent({ client, sessionKey, runId, cmdText, result });
|
||||
},
|
||||
preferMacAppExecHost,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user