From f60378519ccf4089e94e98af2ddab641e2eccd56 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 26 Apr 2026 20:30:45 -0700 Subject: [PATCH] test(plugins): cover bundled dependency edge cases --- src/cli/command-path-policy.test.ts | 15 +++++ src/cli/program/register.subclis.test.ts | 13 +++- src/plugins/bundled-runtime-deps.test.ts | 75 +++++++++++++++++++++++- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/cli/command-path-policy.test.ts b/src/cli/command-path-policy.test.ts index 5c7fc1d2a87..e92ce4c55ac 100644 --- a/src/cli/command-path-policy.test.ts +++ b/src/cli/command-path-policy.test.ts @@ -97,6 +97,21 @@ describe("command-path-policy", () => { hideBanner: true, ensureCliPath: true, }); + for (const commandPath of [ + ["plugins", "install"], + ["plugins", "list"], + ["plugins", "inspect"], + ["plugins", "registry"], + ["plugins", "doctor"], + ]) { + expect(resolveCliCommandPathPolicy(commandPath)).toEqual({ + bypassConfigGuard: false, + routeConfigGuard: "never", + loadPlugins: "never", + hideBanner: false, + ensureCliPath: true, + }); + } expect(resolveCliCommandPathPolicy(["cron", "list"])).toEqual({ bypassConfigGuard: true, routeConfigGuard: "never", diff --git a/src/cli/program/register.subclis.test.ts b/src/cli/program/register.subclis.test.ts index fd3b3053947..f55ded1be1a 100644 --- a/src/cli/program/register.subclis.test.ts +++ b/src/cli/program/register.subclis.test.ts @@ -174,8 +174,17 @@ describe("registerSubCliCommands", () => { expect(acpAction).toHaveBeenCalledTimes(1); }); - it("does not preload plugin CLI registrations for builtin plugins update", async () => { - process.argv = ["node", "openclaw", "plugins", "update", "lossless-claw"]; + it.each([ + ["plugins update", ["plugins", "update", "lossless-claw"]], + ["plugins update --all", ["plugins", "update", "--all"]], + ["plugins install", ["plugins", "install", "lossless-claw"]], + ["plugins list", ["plugins", "list"]], + ["plugins inspect", ["plugins", "inspect", "lossless-claw"]], + ["plugins registry --refresh", ["plugins", "registry", "--refresh"]], + ["plugins doctor", ["plugins", "doctor"]], + ["plugins --help", ["plugins", "--help"]], + ])("does not preload plugin CLI registrations for builtin %s", async (_label, args) => { + process.argv = ["node", "openclaw", ...args]; const program = new Command().name("openclaw"); await registerSubCliByName(program, "plugins"); diff --git a/src/plugins/bundled-runtime-deps.test.ts b/src/plugins/bundled-runtime-deps.test.ts index 053399ccf3d..6ece5bd6b04 100644 --- a/src/plugins/bundled-runtime-deps.test.ts +++ b/src/plugins/bundled-runtime-deps.test.ts @@ -613,6 +613,13 @@ describe("installBundledRuntimeDeps", () => { }); describe("scanBundledPluginRuntimeDeps config policy", () => { + type RuntimeDepsConfigCase = { + name: string; + config: Parameters[0]["config"]; + includeConfiguredChannels: boolean; + expectedDeps: string[]; + }; + function setupPolicyPackageRoot(): string { const packageRoot = makeTempDir(); writeBundledPluginPackage({ @@ -630,7 +637,7 @@ describe("scanBundledPluginRuntimeDeps config policy", () => { return packageRoot; } - it.each([ + const cases: RuntimeDepsConfigCase[] = [ { name: "includes default-enabled bundled plugins", config: {}, @@ -661,6 +668,33 @@ describe("scanBundledPluginRuntimeDeps config policy", () => { includeConfiguredChannels: false, expectedDeps: [], }, + { + name: "lets plugin deny override explicit bundled channel enablement", + config: { + plugins: { deny: ["telegram"] }, + channels: { telegram: { enabled: true } }, + }, + includeConfiguredChannels: false, + expectedDeps: ["alpha-runtime@1.0.0"], + }, + { + name: "lets the plugin master toggle suppress explicit bundled channel enablement", + config: { + plugins: { enabled: false }, + channels: { telegram: { enabled: true } }, + }, + includeConfiguredChannels: false, + expectedDeps: [], + }, + { + name: "lets plugin entry disablement override explicit bundled channel enablement", + config: { + plugins: { entries: { telegram: { enabled: false } } }, + channels: { telegram: { enabled: true } }, + }, + includeConfiguredChannels: false, + expectedDeps: ["alpha-runtime@1.0.0"], + }, { name: "lets explicit bundled channel enablement bypass restrictive allowlists", config: { @@ -691,7 +725,9 @@ describe("scanBundledPluginRuntimeDeps config policy", () => { includeConfiguredChannels: true, expectedDeps: ["alpha-runtime@1.0.0"], }, - ])("$name", ({ config, includeConfiguredChannels, expectedDeps }) => { + ]; + + it.each(cases)("$name", ({ config, includeConfiguredChannels, expectedDeps }) => { const result = scanBundledPluginRuntimeDeps({ packageRoot: setupPolicyPackageRoot(), config, @@ -702,6 +738,41 @@ describe("scanBundledPluginRuntimeDeps config policy", () => { expect(result.conflicts).toEqual([]); }); + it("honors deny and disabled entries when scanning an explicit effective plugin set", () => { + const packageRoot = setupPolicyPackageRoot(); + + const denied = scanBundledPluginRuntimeDeps({ + packageRoot, + pluginIds: ["telegram"], + config: { + plugins: { deny: ["telegram"] }, + channels: { telegram: { enabled: true } }, + }, + }); + const disabled = scanBundledPluginRuntimeDeps({ + packageRoot, + pluginIds: ["telegram"], + config: { + plugins: { entries: { telegram: { enabled: false } } }, + channels: { telegram: { enabled: true } }, + }, + }); + const allowed = scanBundledPluginRuntimeDeps({ + packageRoot, + pluginIds: ["telegram"], + config: { + plugins: { entries: { telegram: { enabled: true } } }, + channels: { telegram: { enabled: true } }, + }, + }); + + expect(denied.deps).toEqual([]); + expect(disabled.deps).toEqual([]); + expect(allowed.deps.map((dep) => `${dep.name}@${dep.version}`)).toEqual([ + "telegram-runtime@2.0.0", + ]); + }); + it("reads each bundled plugin manifest once per runtime-deps scan", () => { const packageRoot = makeTempDir(); const pluginRoot = writeBundledPluginPackage({