mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-23 23:22:32 +00:00
fix(gateway): gate internal command persistence mutations
This commit is contained in:
@@ -106,4 +106,92 @@ describe("phone-control plugin", () => {
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("blocks internal operator.write callers from mutating phone control", async () => {
|
||||
const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-phone-control-test-"));
|
||||
try {
|
||||
let config: Record<string, unknown> = {
|
||||
gateway: {
|
||||
nodes: {
|
||||
allowCommands: [],
|
||||
denyCommands: ["calendar.add", "contacts.add", "reminders.add", "sms.send"],
|
||||
},
|
||||
},
|
||||
};
|
||||
const writeConfigFile = vi.fn(async (next: Record<string, unknown>) => {
|
||||
config = next;
|
||||
});
|
||||
|
||||
let command: OpenClawPluginCommandDefinition | undefined;
|
||||
registerPhoneControl.register(
|
||||
createApi({
|
||||
stateDir,
|
||||
getConfig: () => config,
|
||||
writeConfig: writeConfigFile,
|
||||
registerCommand: (nextCommand) => {
|
||||
command = nextCommand;
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
if (!command) {
|
||||
throw new Error("phone-control plugin did not register its command");
|
||||
}
|
||||
|
||||
const res = await command.handler({
|
||||
...createCommandContext("arm writes 30s"),
|
||||
channel: "webchat",
|
||||
gatewayClientScopes: ["operator.write"],
|
||||
});
|
||||
|
||||
expect(String(res?.text ?? "")).toContain("requires operator.admin");
|
||||
expect(writeConfigFile).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("allows internal operator.admin callers to mutate phone control", async () => {
|
||||
const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-phone-control-test-"));
|
||||
try {
|
||||
let config: Record<string, unknown> = {
|
||||
gateway: {
|
||||
nodes: {
|
||||
allowCommands: [],
|
||||
denyCommands: ["calendar.add", "contacts.add", "reminders.add", "sms.send"],
|
||||
},
|
||||
},
|
||||
};
|
||||
const writeConfigFile = vi.fn(async (next: Record<string, unknown>) => {
|
||||
config = next;
|
||||
});
|
||||
|
||||
let command: OpenClawPluginCommandDefinition | undefined;
|
||||
registerPhoneControl.register(
|
||||
createApi({
|
||||
stateDir,
|
||||
getConfig: () => config,
|
||||
writeConfig: writeConfigFile,
|
||||
registerCommand: (nextCommand) => {
|
||||
command = nextCommand;
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
if (!command) {
|
||||
throw new Error("phone-control plugin did not register its command");
|
||||
}
|
||||
|
||||
const res = await command.handler({
|
||||
...createCommandContext("arm writes 30s"),
|
||||
channel: "webchat",
|
||||
gatewayClientScopes: ["operator.admin"],
|
||||
});
|
||||
|
||||
expect(String(res?.text ?? "")).toContain("sms.send");
|
||||
expect(writeConfigFile).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -358,6 +358,11 @@ export default definePluginEntry({
|
||||
}
|
||||
|
||||
if (action === "disarm") {
|
||||
if (ctx.channel === "webchat" && !ctx.gatewayClientScopes?.includes("operator.admin")) {
|
||||
return {
|
||||
text: "⚠️ /phone disarm requires operator.admin for internal gateway callers.",
|
||||
};
|
||||
}
|
||||
const res = await disarmNow({
|
||||
api,
|
||||
stateDir,
|
||||
@@ -375,6 +380,11 @@ export default definePluginEntry({
|
||||
}
|
||||
|
||||
if (action === "arm") {
|
||||
if (ctx.channel === "webchat" && !ctx.gatewayClientScopes?.includes("operator.admin")) {
|
||||
return {
|
||||
text: "⚠️ /phone arm requires operator.admin for internal gateway callers.",
|
||||
};
|
||||
}
|
||||
const group = parseGroup(tokens[1]);
|
||||
if (!group) {
|
||||
return { text: `Usage: /phone arm <group> [duration]\nGroups: ${formatGroupList()}` };
|
||||
|
||||
Reference in New Issue
Block a user