




















@@ -108,7 +108,7 @@ function expectResolvedBundledDirFromRoot(params: {
108108expectResolvedBundledDir({
109109cwd: params.cwd ?? params.repoRoot,
110110expectedDir: path.join(params.repoRoot, params.expectedRelativeDir),
111-...(params.argv1 ? { argv1: params.argv1 } : {}),
111+argv1: params.argv1 ?? path.join(params.repoRoot, "openclaw.mjs"),
112112 ...(params.bundledDirOverride ? { bundledDirOverride: params.bundledDirOverride } : {}),
113113 ...(params.vitest !== undefined ? { vitest: params.vitest } : {}),
114114 ...(params.execArgv ? { execArgv: params.execArgv } : {}),
@@ -202,15 +202,15 @@ describe("resolveBundledPluginsDir", () => {
202202},
203203],
204204[
205-"prefers source extensions under vitest to avoid stale staged plugins",
205+"does not prefer source extensions from VITEST alone",
206206{
207207prefix: "openclaw-bundled-dir-vitest-",
208208hasExtensions: true,
209209hasDistRuntimeExtensions: true,
210210hasDistExtensions: true,
211211},
212212{
213-expectedRelativeDir: "extensions",
213+expectedRelativeDir: path.join("dist-runtime", "extensions"),
214214vitest: "true",
215215},
216216],
@@ -248,6 +248,8 @@ describe("resolveBundledPluginsDir", () => {
248248seedBundledPluginTree(repoRoot, path.join("dist-runtime", "extensions"));
249249} else if (expectation.expectedRelativeDir === path.join("dist", "extensions")) {
250250seedBundledPluginTree(repoRoot, path.join("dist", "extensions"));
251+} else if (expectation.expectedRelativeDir === "extensions") {
252+seedBundledPluginTree(repoRoot, "extensions");
251253}
252254expectResolvedBundledDirFromRoot({
253255 repoRoot,
@@ -270,6 +272,7 @@ describe("resolveBundledPluginsDir", () => {
270272fs.mkdirSync(path.join(repoRoot, "dist-runtime", "extensions", "discord"), {
271273recursive: true,
272274});
275+seedBundledPluginTree(repoRoot, "extensions");
273276274277expectResolvedBundledDirFromRoot({
275278 repoRoot,
@@ -296,6 +299,140 @@ describe("resolveBundledPluginsDir", () => {
296299expect(fs.readdirSync(bundledDir ?? "")).toEqual([]);
297300});
298301302+it("ignores an existing override under an argv1-derived fake package root", () => {
303+const installedRoot = createOpenClawRoot({
304+prefix: "openclaw-bundled-dir-argv-override-reject-",
305+hasDistExtensions: true,
306+});
307+seedBundledPluginTree(installedRoot, path.join("dist", "extensions"));
308+309+vi.spyOn(process, "cwd").mockReturnValue(installedRoot);
310+process.argv[1] = path.join(installedRoot, "openclaw.mjs");
311+process.execArgv.length = 0;
312+delete process.env.VITEST;
313+process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = path.join(installedRoot, "dist", "extensions");
314+delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
315+316+const bundledDir = resolveBundledPluginsDir();
317+318+expect(bundledDir).toBeDefined();
319+expect(fs.realpathSync(bundledDir!)).not.toBe(
320+fs.realpathSync(path.join(installedRoot, "dist", "extensions")),
321+);
322+});
323+324+it("does not let VITEST relax existing override trust checks", () => {
325+const overrideRoot = makeRepoRoot("openclaw-bundled-dir-vitest-override-reject-");
326+seedBundledPluginTree(overrideRoot, "extensions", "memory-core");
327+328+vi.spyOn(process, "cwd").mockReturnValue(overrideRoot);
329+process.argv[1] = "/usr/bin/env";
330+process.execArgv.length = 0;
331+process.env.VITEST = "true";
332+process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = path.join(overrideRoot, "extensions");
333+delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
334+335+const bundledDir = resolveBundledPluginsDir();
336+337+expect(bundledDir).toBeDefined();
338+expect(fs.realpathSync(bundledDir!)).not.toBe(
339+fs.realpathSync(path.join(overrideRoot, "extensions")),
340+);
341+});
342+343+it("does not let VITEST add cwd to bundled plugin resolution candidates", () => {
344+const cwdRepoRoot = createOpenClawRoot({
345+prefix: "openclaw-bundled-dir-vitest-cwd-",
346+hasExtensions: true,
347+hasSrc: true,
348+hasGitCheckout: true,
349+});
350+seedBundledPluginTree(cwdRepoRoot, "extensions", "memory-core");
351+352+vi.spyOn(process, "cwd").mockReturnValue(cwdRepoRoot);
353+process.argv[1] = "/usr/bin/env";
354+process.execArgv.length = 0;
355+process.env.VITEST = "true";
356+delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
357+delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
358+359+const bundledDir = resolveBundledPluginsDir();
360+361+expect(bundledDir).toBeDefined();
362+expect(fs.realpathSync(bundledDir!)).not.toBe(
363+fs.realpathSync(path.join(cwdRepoRoot, "extensions")),
364+);
365+});
366+367+it("falls back from a missing override instead of returning an untrusted future path", () => {
368+vi.spyOn(process, "cwd").mockReturnValue(makeRepoRoot("openclaw-bundled-dir-missing-cwd-"));
369+process.argv[1] = "/usr/bin/env";
370+process.execArgv.length = 0;
371+delete process.env.VITEST;
372+const missingOverride = path.join(
373+makeRepoRoot("openclaw-bundled-dir-missing-override-"),
374+"extensions",
375+);
376+process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = missingOverride;
377+delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
378+379+const bundledDir = resolveBundledPluginsDir();
380+381+expect(bundledDir).toBeDefined();
382+expect(path.resolve(bundledDir!)).not.toBe(path.resolve(missingOverride));
383+});
384+385+it("falls back to argv root when an existing rejected override is unrelated", () => {
386+const installedRoot = createOpenClawRoot({
387+prefix: "openclaw-bundled-dir-rejected-override-argv-",
388+hasDistExtensions: true,
389+});
390+seedBundledPluginTree(installedRoot, path.join("dist", "extensions"));
391+const overrideRoot = makeRepoRoot("openclaw-bundled-dir-rejected-override-");
392+seedBundledPluginTree(overrideRoot, "extensions", "memory-core");
393+394+vi.spyOn(process, "cwd").mockReturnValue(makeRepoRoot("openclaw-bundled-dir-rejected-cwd-"));
395+process.argv[1] = path.join(installedRoot, "openclaw.mjs");
396+process.execArgv.length = 0;
397+delete process.env.VITEST;
398+process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = path.join(overrideRoot, "extensions");
399+delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
400+401+const bundledDir = resolveBundledPluginsDir();
402+403+expect(fs.realpathSync(bundledDir ?? "")).toBe(
404+fs.realpathSync(path.join(installedRoot, "dist", "extensions")),
405+);
406+});
407+408+it("does not resolve bundled plugins from cwd when argv1 is not a package root", () => {
409+const cwdRepoRoot = createOpenClawRoot({
410+prefix: "openclaw-bundled-dir-untrusted-cwd-",
411+hasExtensions: true,
412+hasSrc: true,
413+hasGitCheckout: true,
414+});
415+fs.mkdirSync(path.join(cwdRepoRoot, "extensions", "memory-core"), { recursive: true });
416+fs.writeFileSync(
417+path.join(cwdRepoRoot, "extensions", "memory-core", "runtime-api.js"),
418+"export const marker = 'untrusted-cwd';\n",
419+"utf8",
420+);
421+vi.spyOn(process, "cwd").mockReturnValue(cwdRepoRoot);
422+process.argv[1] = "/usr/bin/env";
423+process.execArgv.length = 0;
424+delete process.env.VITEST;
425+delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
426+delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
427+428+const bundledDir = resolveBundledPluginsDir();
429+430+expect(bundledDir).toBeDefined();
431+expect(fs.realpathSync(bundledDir!)).not.toBe(
432+fs.realpathSync(path.join(cwdRepoRoot, "extensions")),
433+);
434+});
435+299436it.each([
300437{
301438name: "prefers the running CLI package root over an unrelated cwd checkout",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。