Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  read-only.test.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import fs from "node:fs";
import path from "node:path";
import { afterAll, afterEach, describe, expect, it } from "vitest";
import {
  cleanupPluginLoaderFixturesForTest,
  EMPTY_PLUGIN_SCHEMA,
  makeTempDir,
  resetPluginLoaderTestStateForTest,
  useNoBundledPlugins,
} from "../../plugins/loader.test-fixtures.js";
import { listReadOnlyChannelPluginsForConfig } from "./read-only.js";

function writeExternalSetupChannelPlugin(
  options: {
    setupEntry?: boolean;
    pluginDir?: string;
    pluginId?: string;
    channelId?: string;
    manifestChannelIds?: string[];
    manifestChannelConfig?: boolean;
    manifestChannelDescription?: string;
    manifestChannelLabel?: string;
    setupRequiresRuntime?: boolean;
    setupChannelId?: string;
  } = {},
) {
  useNoBundledPlugins();
  const pluginDir = options.pluginDir ?? makeTempDir();
  const pluginId = options.pluginId ?? "external-chat";
  const channelId = options.channelId ?? "external-chat";
  const manifestChannelIds = options.manifestChannelIds ?? [channelId];
  const setupChannelId = options.setupChannelId ?? channelId;
  const fullMarker = path.join(pluginDir, "full-loaded.txt");
  const setupMarker = path.join(pluginDir, "setup-loaded.txt");
  const setupEntry = options.setupEntry !== false;

  fs.writeFileSync(
    path.join(pluginDir, "package.json"),
    JSON.stringify(
      {
        name: `@example/openclaw-${pluginId}`,
        version: "1.0.0",
        openclaw: {
          extensions: ["./index.cjs"],
          ...(setupEntry ? { setupEntry: "./setup-entry.cjs" } : {}),
        },
      },
      null,
      2,
    ),
    "utf-8",
  );
  fs.writeFileSync(
    path.join(pluginDir, "openclaw.plugin.json"),
    JSON.stringify(
      {
        id: pluginId,
        configSchema: EMPTY_PLUGIN_SCHEMA,
        channels: manifestChannelIds,
        channelEnvVars: {
          [channelId]: ["EXTERNAL_CHAT_TOKEN"],
        },
        ...(typeof options.setupRequiresRuntime === "boolean"
          ? { setup: { requiresRuntime: options.setupRequiresRuntime } }
          : {}),
        ...(options.manifestChannelConfig
          ? {
              channelConfigs: Object.fromEntries(
                manifestChannelIds.map((id) => [
                  id,
                  {
                    schema: {
                      type: "object",
                      additionalProperties: false,
                      properties: {
                        token: { type: "string" },
                      },
                    },
                    uiHints: {
                      token: {
                        label: "Token",
                        sensitive: true,
                      },
                    },
                    label: options.manifestChannelLabel ?? "External Chat Manifest",
                    description: options.manifestChannelDescription ?? "manifest config",
                    preferOver: ["legacy-external-chat"],
                  },
                ]),
              ),
            }
          : {}),
      },
      null,
      2,
    ),
    "utf-8",
  );
  fs.writeFileSync(
    path.join(pluginDir, "index.cjs"),
    `require("node:fs").writeFileSync(${JSON.stringify(fullMarker)}, "loaded", "utf-8");
module.exports = {
  id: ${JSON.stringify(pluginId)},
  register(api) {
    api.registerChannel({
      plugin: {
        id: ${JSON.stringify(channelId)},
        meta: {
          id: ${JSON.stringify(channelId)},
          label: "External Chat",
          selectionLabel: "External Chat",
          docsPath: ${JSON.stringify(`/channels/${channelId}`)},
          blurb: "full entry",
        },
        capabilities: { chatTypes: ["direct"] },
        config: {
          listAccountIds: () => ["default"],
          resolveAccount: (cfg) => ({
            accountId: "default",
            token: cfg.channels?.[${JSON.stringify(channelId)}]?.token ?? "configured",
          }),
        },
        outbound: { deliveryMode: "direct" },
        secrets: {
          secretTargetRegistryEntries: [
            {
              id: ${JSON.stringify(`channels.${channelId}.token`)},
              targetType: "channel",
              configFile: "openclaw.json",
              pathPattern: ${JSON.stringify(`channels.${channelId}.token`)},
              secretShape: "secret_input",
              expectedResolvedValue: "string",
              includeInPlan: true,
              includeInConfigure: true,
              includeInAudit: true,
            },
          ],
        },
      },
    });
  },
};`,
    "utf-8",
  );
  if (setupEntry) {
    fs.writeFileSync(
      path.join(pluginDir, "setup-entry.cjs"),
      `require("node:fs").writeFileSync(${JSON.stringify(setupMarker)}, "loaded", "utf-8");
module.exports = {
  plugin: {
    id: ${JSON.stringify(setupChannelId)},
    meta: {
      id: ${JSON.stringify(setupChannelId)},
      label: "External Chat",
      selectionLabel: "External Chat",
      docsPath: ${JSON.stringify(`/channels/${setupChannelId}`)},
      blurb: "setup entry",
    },
    capabilities: { chatTypes: ["direct"] },
    config: {
      listAccountIds: () => ["default"],
      resolveAccount: (cfg) => ({
        accountId: "default",
        token: cfg.channels?.[${JSON.stringify(setupChannelId)}]?.token ?? "configured",
      }),
    },
    outbound: { deliveryMode: "direct" },
    secrets: {
      secretTargetRegistryEntries: [
            {
              id: ${JSON.stringify(`channels.${setupChannelId}.token`)},
              targetType: "channel",
              configFile: "openclaw.json",
              pathPattern: ${JSON.stringify(`channels.${setupChannelId}.token`)},
          secretShape: "secret_input",
          expectedResolvedValue: "string",
          includeInPlan: true,
          includeInConfigure: true,
          includeInAudit: true,
        },
      ],
    },
  },
};`,
      "utf-8",
    );
  }

  return { pluginDir, fullMarker, setupMarker };
}

function writeBundledSetupChannelPlugin(
  options: {
    pluginId?: string;
    channelId?: string;
    envVar?: string;
  } = {},
) {
  const bundledRoot = makeTempDir();
  process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledRoot;
  const pluginId = options.pluginId ?? "bundled-chat";
  const channelId = options.channelId ?? pluginId;
  const envVar = options.envVar ?? "BUNDLED_CHAT_TOKEN";
  const pluginDir = path.join(bundledRoot, pluginId);
  fs.mkdirSync(pluginDir, { recursive: true });
  const fullMarker = path.join(pluginDir, "full-loaded.txt");
  const setupMarker = path.join(pluginDir, "setup-loaded.txt");

  fs.writeFileSync(
    path.join(pluginDir, "package.json"),
    JSON.stringify(
      {
        name: `@openclaw/${pluginId}`,
        version: "1.0.0",
        type: "commonjs",
        openclaw: {
          extensions: ["./index.cjs"],
          setupEntry: "./setup-entry.cjs",
          channel: {
            id: channelId,
            label: "Bundled Chat",
            selectionLabel: "Bundled Chat",
            docsPath: `/channels/${channelId}`,
            blurb: "bundled setup entry",
          },
        },
      },
      null,
      2,
    ),
    "utf-8",
  );
  fs.writeFileSync(
    path.join(pluginDir, "openclaw.plugin.json"),
    JSON.stringify(
      {
        id: pluginId,
        configSchema: EMPTY_PLUGIN_SCHEMA,
        channels: [channelId],
        channelEnvVars: {
          [channelId]: [envVar],
        },
      },
      null,
      2,
    ),
    "utf-8",
  );
  fs.writeFileSync(
    path.join(pluginDir, "index.cjs"),
    `require("node:fs").writeFileSync(${JSON.stringify(fullMarker)}, "loaded", "utf-8");
module.exports = {
  kind: "bundled-channel-entry",
  id: ${JSON.stringify(pluginId)},
  name: "Bundled Chat",
  description: "full entry",
  register() {},
  loadChannelPlugin() {
    return {
      id: ${JSON.stringify(channelId)},
      meta: { id: ${JSON.stringify(channelId)}, label: "Bundled Chat" },
      capabilities: { chatTypes: ["direct"] },
      config: {
        listAccountIds: () => ["default"],
        resolveAccount: () => ({ accountId: "default", token: "configured" }),
      },
      outbound: { deliveryMode: "direct" },
    };
  },
};`,
    "utf-8",
  );
  fs.writeFileSync(
    path.join(pluginDir, "setup-entry.cjs"),
    `module.exports = {
  kind: "bundled-channel-setup-entry",
  loadSetupPlugin() {
    require("node:fs").writeFileSync(${JSON.stringify(setupMarker)}, "loaded", "utf-8");
    return {
      id: ${JSON.stringify(channelId)},
      meta: {
        id: ${JSON.stringify(channelId)},
        label: "Bundled Chat",
        selectionLabel: "Bundled Chat",
        docsPath: ${JSON.stringify(`/channels/${channelId}`)},
        blurb: "bundled setup entry",
      },
      capabilities: { chatTypes: ["direct"] },
      config: {
        listAccountIds: () => ["default"],
        resolveAccount: () => ({ accountId: "default", token: "configured" }),
      },
      outbound: { deliveryMode: "direct" },
    };
  },
};`,
    "utf-8",
  );

  return { bundledRoot, pluginDir, fullMarker, setupMarker, pluginId, channelId, envVar };
}

function expectExternalChatSetupOnlyPluginLoaded(params: {
  plugins: ReturnType<typeof listReadOnlyChannelPluginsForConfig>;
  setupMarker: string;
  fullMarker: string;
}) {
  const plugin = params.plugins.find((entry) => entry.id === "external-chat");
  expect(plugin?.meta.blurb).toBe("setup entry");
  expect(
    plugin?.secrets?.secretTargetRegistryEntries?.some(
      (entry) => entry.id === "channels.external-chat.token",
    ),
  ).toBe(true);
  expect(fs.existsSync(params.setupMarker)).toBe(true);
  expect(fs.existsSync(params.fullMarker)).toBe(false);
}

afterEach(() => {
  resetPluginLoaderTestStateForTest();
});

afterAll(() => {
  cleanupPluginLoaderFixturesForTest();
});

describe("listReadOnlyChannelPluginsForConfig", () => {
  it("loads configured external channel setup metadata without importing full runtime", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin();
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    expectExternalChatSetupOnlyPluginLoaded({ plugins, setupMarker, fullMarker });
  });

  it("matches setup-only plugins by manifest-owned channel ids when plugin id differs", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      setupChannelId: "external-chat-plugin",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin?.meta.id).toBe("external-chat");
    expect(plugin?.meta.blurb).toBe("setup entry");
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("clones setup-only plugins for every configured owned channel when setup id matches one channel", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "alpha-chat",
      manifestChannelIds: ["alpha-chat", "beta-chat"],
      setupChannelId: "alpha-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "alpha-chat": { token: "configured" },
          "beta-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const alphaPlugin = plugins.find((entry) => entry.id === "alpha-chat");
    const betaPlugin = plugins.find((entry) => entry.id === "beta-chat");
    expect(alphaPlugin?.meta.id).toBe("alpha-chat");
    expect(betaPlugin?.meta.id).toBe("beta-chat");
    expect(alphaPlugin?.meta.blurb).toBe("setup entry");
    expect(betaPlugin?.meta.blurb).toBe("setup entry");
    expect(
      betaPlugin?.secrets?.secretTargetRegistryEntries?.some(
        (entry) => entry.id === "channels.beta-chat.token",
      ),
    ).toBe(true);
    expect(
      betaPlugin?.config.resolveAccount({
        channels: {
          "alpha-chat": { token: "alpha-token" },
          "beta-chat": { token: "beta-token" },
        },
      } as never),
    ).toMatchObject({ token: "beta-token" });
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("clones setup-only plugins when only another owned channel is configured", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "alpha-chat",
      manifestChannelIds: ["alpha-chat", "beta-chat"],
      setupChannelId: "alpha-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "beta-chat": { token: "beta-token" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    expect(plugins.some((entry) => entry.id === "alpha-chat")).toBe(false);
    const betaPlugin = plugins.find((entry) => entry.id === "beta-chat");
    expect(betaPlugin?.meta.id).toBe("beta-chat");
    expect(
      betaPlugin?.secrets?.secretTargetRegistryEntries?.some(
        (entry) => entry.id === "channels.beta-chat.token",
      ),
    ).toBe(true);
    expect(
      betaPlugin?.config.resolveAccount({
        channels: {
          "beta-chat": { token: "beta-token" },
        },
      } as never),
    ).toMatchObject({ token: "beta-token" });
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("keeps configured external channels visible when no setup entry exists", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      setupEntry: false,
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin).toBeUndefined();
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("uses manifest channel configs when no setup entry exists", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      setupEntry: false,
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      manifestChannelConfig: true,
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    expect(plugins.find((entry) => entry.id === "external-chat")?.meta.blurb).toBe(
      "manifest config",
    );
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("uses manifest channel configs before setup-only plugin loading", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      manifestChannelConfig: true,
      setupRequiresRuntime: false,
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin?.meta.label).toBe("External Chat Manifest");
    expect(plugin?.meta.blurb).toBe("manifest config");
    expect(plugin?.meta.preferOver).toEqual(["legacy-external-chat"]);
    expect(plugin?.configSchema?.schema).toMatchObject({
      properties: {
        token: { type: "string" },
      },
    });
    expect(plugin?.configSchema?.uiHints?.token).toMatchObject({
      label: "Token",
      sensitive: true,
    });
    expect(
      plugin?.config.listAccountIds({ channels: { "external-chat": { token: "t" } } } as never),
    ).toEqual(["default"]);
    expect(
      plugin?.config.resolveAccount({
        channels: { "external-chat": { token: "configured" } },
      } as never),
    ).toMatchObject({
      accountId: "default",
      config: { token: "configured" },
    });
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("sanitizes terminal control sequences from manifest channel metadata", () => {
    const { pluginDir } = writeExternalSetupChannelPlugin({
      setupEntry: false,
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      manifestChannelConfig: true,
      manifestChannelLabel: "External\u001b[31m Chat\u001b[0m",
      manifestChannelDescription: "manifest\u001b[2K config",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin?.meta.label).toBe("External Chat");
    expect(plugin?.meta.selectionLabel).toBe("External Chat");
    expect(plugin?.meta.blurb).toBe("manifest config");
  });

  it("ignores manifest channel configs with unsafe channel ids", () => {
    const unsafeChannelId = "__proto__";
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      setupEntry: false,
      pluginId: "external-chat-plugin",
      channelId: unsafeChannelId,
      manifestChannelIds: [unsafeChannelId],
      manifestChannelConfig: true,
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: Object.fromEntries([[unsafeChannelId, { token: "configured" }]]),
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    expect(plugins.some((entry) => entry.id === unsafeChannelId)).toBe(false);
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("uses own normalized account ids for manifest channel account config", () => {
    const { pluginDir } = writeExternalSetupChannelPlugin({
      setupEntry: false,
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      manifestChannelConfig: true,
    });
    const inheritedAccounts = Object.create({
      inherited: { token: "prototype-token" },
    }) as Record<string, unknown>;
    inheritedAccounts.default = { token: "default-token" };
    inheritedAccounts.named = { token: "named-token" };
    const cfg = {
      channels: {
        "external-chat": {
          accounts: inheritedAccounts,
        },
      },
      plugins: {
        load: { paths: [pluginDir] },
        allow: ["external-chat-plugin"],
      },
    } as never;
    const plugin = listReadOnlyChannelPluginsForConfig(cfg, {
      env: { ...process.env },
      includePersistedAuthState: false,
    }).find((entry) => entry.id === "external-chat");

    expect(plugin?.config.listAccountIds(cfg)).toEqual(["default", "named"]);
    expect(plugin?.config.resolveAccount(cfg, "__proto__")).toMatchObject({
      accountId: "default",
      config: { token: "default-token" },
    });
    expect(plugin?.config.resolveAccount(cfg, "inherited")).not.toMatchObject({
      config: { token: "prototype-token" },
    });
  });

  it("keeps setup-entry precedence when channel config descriptors are not runtime cutoffs", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      manifestChannelConfig: true,
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin?.meta.blurb).toBe("setup entry");
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("uses external channel env vars as read-only configuration triggers", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env, EXTERNAL_CHAT_TOKEN: "configured" },
        includePersistedAuthState: false,
      },
    );

    expectExternalChatSetupOnlyPluginLoaded({ plugins, setupMarker, fullMarker });
  });

  it("does not promote disabled external channels from manifest env", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { enabled: false },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env, EXTERNAL_CHAT_TOKEN: "configured" },
        includePersistedAuthState: false,
      },
    );

    expect(plugins.some((entry) => entry.id === "external-chat")).toBe(false);
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("does not promote disabled bundled channels from ambient env", () => {
    const { channelId, envVar, fullMarker, setupMarker } = writeBundledSetupChannelPlugin();
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        plugins: {
          allow: ["memory-core"],
        },
      } as never,
      {
        env: { ...process.env, [envVar]: "configured" },
        includePersistedAuthState: false,
      },
    );

    expect(plugins.some((entry) => entry.id === channelId)).toBe(false);
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("does not promote explicitly disabled bundled channels from ambient env", () => {
    const { channelId, envVar, fullMarker, pluginId, setupMarker } =
      writeBundledSetupChannelPlugin();
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          [channelId]: { enabled: false },
        },
        plugins: {
          entries: {
            [pluginId]: { enabled: true },
          },
        },
      } as never,
      {
        env: { ...process.env, [envVar]: "configured" },
        includePersistedAuthState: false,
      },
    );

    expect(plugins.some((entry) => entry.id === channelId)).toBe(false);
    expect(fs.existsSync(setupMarker)).toBe(false);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("keeps explicitly enabled bundled channels visible from env configuration", () => {
    const { channelId, envVar, fullMarker, pluginId, setupMarker } =
      writeBundledSetupChannelPlugin();
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        plugins: {
          allow: [pluginId],
          entries: {
            [pluginId]: { enabled: true },
          },
        },
      } as never,
      {
        env: { ...process.env, [envVar]: "configured" },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === channelId);
    expect(plugin?.meta.blurb).toBe("bundled setup entry");
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("accepts option-like env keys through the explicit env option", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: {
          ...process.env,
          cache: "true",
          env: "prod",
          EXTERNAL_CHAT_TOKEN: "configured",
          workspaceDir: "workspace-env-value",
        },
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin?.meta.blurb).toBe("setup entry");
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("discovers trusted external channel plugins from the default agent workspace", () => {
    const workspaceDir = makeTempDir();
    const pluginDir = path.join(workspaceDir, ".openclaw", "extensions", "external-chat-plugin");
    fs.mkdirSync(pluginDir, { recursive: true });
    const { fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginDir,
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        agents: {
          defaults: {
            workspace: workspaceDir,
          },
        },
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
        includePersistedAuthState: false,
      },
    );

    const plugin = plugins.find((entry) => entry.id === "external-chat");
    expect(plugin?.meta.blurb).toBe("setup entry");
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });

  it("ignores external setup plugins that export an unrequested channel id", () => {
    const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin({
      pluginId: "external-chat-plugin",
      channelId: "external-chat",
      manifestChannelIds: ["external-chat"],
      setupChannelId: "spoofed-chat",
    });
    const plugins = listReadOnlyChannelPluginsForConfig(
      {
        channels: {
          "external-chat": { token: "configured" },
        },
        plugins: {
          load: { paths: [pluginDir] },
          allow: ["external-chat-plugin"],
        },
      } as never,
      {
        env: { ...process.env },
      },
    );

    expect(plugins.some((entry) => entry.id === "spoofed-chat")).toBe(false);
    expect(plugins.some((entry) => entry.id === "external-chat")).toBe(false);
    expect(fs.existsSync(setupMarker)).toBe(true);
    expect(fs.existsSync(fullMarker)).toBe(false);
  });
});

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge