





















@@ -27,9 +27,11 @@ import * as openClawPluginTools from "./openclaw-plugin-tools.js";
2727import { createOpenClawTools } from "./openclaw-tools.js";
2828import { expectReadWriteEditTools } from "./test-helpers/agent-tools-fs-helpers.js";
2929import { createAgentToolsSandboxContext } from "./test-helpers/agent-tools-sandbox-context.js";
30+import { stubTool } from "./test-helpers/fast-tool-stubs.js";
3031import { createHostSandboxFsBridge } from "./test-helpers/host-sandbox-fs-bridge.js";
3132import { buildEmptyExplicitToolAllowlistError } from "./tool-allowlist-guard.js";
3233import { DEFAULT_PLUGIN_TOOLS_ALLOWLIST_ENTRY, normalizeToolName } from "./tool-policy.js";
34+import { replaceWithEffectiveCronCreatorToolAllowlist } from "./tools/cron-tool.js";
33353436const tinyPngBuffer = Buffer.from(
3537"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO2f7z8AAAAASUVORK5CYII=",
@@ -154,6 +156,12 @@ function expectListIncludes(
154156}
155157}
156158159+function cronCreatorToolNames(
160+list: OpenClawToolsOptions["cronCreatorToolAllowlist"] | undefined,
161+): string[] | undefined {
162+return list?.map((entry) => (typeof entry === "string" ? entry : entry.name));
163+}
164+157165describe("createOpenClawCodingTools", () => {
158166const testConfig: OpenClawConfig = {};
159167@@ -739,6 +747,88 @@ describe("createOpenClawCodingTools", () => {
739747expect(inheritedAllow?.includes("process")).toBe(false);
740748});
741749750+it("passes group-restricted tool surface to cron-created agent turns", () => {
751+const createOpenClawToolsMock = vi.mocked(createOpenClawTools);
752+createOpenClawToolsMock.mockClear();
753+754+createOpenClawCodingTools({
755+sessionKey: "agent:main:whatsapp:group:restricted-room",
756+config: {
757+tools: { allow: ["read", "exec", "process", "cron"] },
758+channels: {
759+whatsapp: {
760+groups: {
761+"restricted-room": {
762+tools: { allow: ["read", "cron"] },
763+},
764+},
765+},
766+},
767+},
768+});
769+770+expect(createOpenClawToolsMock).toHaveBeenCalledTimes(1);
771+const cronAllow = latestCreateOpenClawToolsOptions().cronCreatorToolAllowlist;
772+const cronAllowNames = cronCreatorToolNames(cronAllow);
773+expectListIncludes(cronAllowNames, ["read", "cron"]);
774+expect(cronAllowNames?.includes("exec")).toBe(false);
775+expect(cronAllowNames?.includes("process")).toBe(false);
776+});
777+778+it("lets embedded attempts refresh a caller-owned cron creator tool surface", () => {
779+const createOpenClawToolsMock = vi.mocked(createOpenClawTools);
780+createOpenClawToolsMock.mockClear();
781+const cronCreatorToolAllowlistRef: NonNullable<
782+OpenClawToolsOptions["cronCreatorToolAllowlist"]
783+> = [];
784+785+createOpenClawCodingTools({
786+config: { tools: { allow: ["read", "cron"] } },
787+ cronCreatorToolAllowlistRef,
788+});
789+790+expect(createOpenClawToolsMock).toHaveBeenCalledTimes(1);
791+const cronAllow = latestCreateOpenClawToolsOptions().cronCreatorToolAllowlist;
792+expect(cronAllow).toBe(cronCreatorToolAllowlistRef);
793+expect(cronCreatorToolNames(cronAllow)).toEqual(["read", "cron"]);
794+795+replaceWithEffectiveCronCreatorToolAllowlist(cronCreatorToolAllowlistRef, [
796+stubTool("read"),
797+stubTool("cron"),
798+stubTool("bundle_mcp_search"),
799+]);
800+801+expect(cronCreatorToolNames(cronAllow)).toEqual(["read", "cron", "bundle_mcp_search"]);
802+});
803+804+it("passes deny-restricted tool surface to cron-created agent turns", () => {
805+const createOpenClawToolsMock = vi.mocked(createOpenClawTools);
806+createOpenClawToolsMock.mockClear();
807+808+createOpenClawCodingTools({
809+sessionKey: "agent:main:whatsapp:group:restricted-room",
810+config: {
811+tools: { allow: ["read", "exec", "process", "cron"] },
812+channels: {
813+whatsapp: {
814+groups: {
815+"restricted-room": {
816+tools: { deny: ["exec", "process"] },
817+},
818+},
819+},
820+},
821+},
822+});
823+824+expect(createOpenClawToolsMock).toHaveBeenCalledTimes(1);
825+const cronAllow = latestCreateOpenClawToolsOptions().cronCreatorToolAllowlist;
826+const cronAllowNames = cronCreatorToolNames(cronAllow);
827+expectListIncludes(cronAllowNames, ["read", "cron"]);
828+expect(cronAllowNames?.includes("exec")).toBe(false);
829+expect(cronAllowNames?.includes("process")).toBe(false);
830+});
831+742832it("records core tool-prep stages for hot-path diagnostics", () => {
743833const stages: string[] = [];
744834此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。