mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-30 11:00:23 +00:00
test(contracts): route bundled contract tests through sdk facades
This commit is contained in:
@@ -3,7 +3,10 @@ import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { listBundledChannelPlugins, setBundledChannelRuntime } from "../bundled.js";
|
||||
import type { ChannelPlugin } from "../types.js";
|
||||
import { channelPluginSurfaceKeys, type ChannelPluginSurface } from "./manifest.js";
|
||||
import { importBundledChannelContractArtifact } from "./runtime-artifacts.js";
|
||||
import {
|
||||
importBundledChannelContractArtifact,
|
||||
resolveBundledChannelContractArtifactUrl,
|
||||
} from "./runtime-artifacts.js";
|
||||
|
||||
type SurfaceContractEntry = {
|
||||
id: string;
|
||||
@@ -41,8 +44,8 @@ const sendMessageMatrixMock = vi.hoisted(() =>
|
||||
roomId: to.replace(/^room:/, ""),
|
||||
})),
|
||||
);
|
||||
const matrixRuntimeApiModuleId = vi.hoisted(
|
||||
() => new URL("../../../../extensions/matrix/runtime-api.js", import.meta.url).href,
|
||||
const matrixRuntimeApiModuleId = vi.hoisted(() =>
|
||||
resolveBundledChannelContractArtifactUrl("matrix", "runtime-api.js"),
|
||||
);
|
||||
|
||||
const lineContractApi = await importBundledChannelContractArtifact<{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import {
|
||||
namedAccountPromotionKeys as matrixNamedAccountPromotionKeys,
|
||||
resolveSingleAccountPromotionTarget as resolveMatrixSingleAccountPromotionTarget,
|
||||
singleAccountKeysToMove as matrixSingleAccountKeysToMove,
|
||||
} from "../../../extensions/matrix/contract-api.js";
|
||||
import { singleAccountKeysToMove as telegramSingleAccountKeysToMove } from "../../../extensions/telegram/contract-api.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
} from "../../plugin-sdk/matrix.js";
|
||||
import { singleAccountKeysToMove as telegramSingleAccountKeysToMove } from "../../plugin-sdk/telegram.js";
|
||||
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
|
||||
import {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
namedAccountPromotionKeys as matrixNamedAccountPromotionKeys,
|
||||
resolveSingleAccountPromotionTarget as resolveMatrixSingleAccountPromotionTarget,
|
||||
singleAccountKeysToMove as matrixSingleAccountKeysToMove,
|
||||
} from "../../../extensions/matrix/contract-api.js";
|
||||
import { singleAccountKeysToMove as telegramSingleAccountKeysToMove } from "../../../extensions/telegram/contract-api.js";
|
||||
import {
|
||||
resolveSetupWizardAllowFromEntries,
|
||||
resolveSetupWizardGroupAllowlist,
|
||||
} from "../../../test/helpers/plugins/setup-wizard.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import {
|
||||
namedAccountPromotionKeys as matrixNamedAccountPromotionKeys,
|
||||
resolveSingleAccountPromotionTarget as resolveMatrixSingleAccountPromotionTarget,
|
||||
singleAccountKeysToMove as matrixSingleAccountKeysToMove,
|
||||
} from "../../plugin-sdk/matrix.js";
|
||||
import { singleAccountKeysToMove as telegramSingleAccountKeysToMove } from "../../plugin-sdk/telegram.js";
|
||||
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
|
||||
import {
|
||||
|
||||
16
src/plugin-sdk/discord.ts
Normal file
16
src/plugin-sdk/discord.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// Manual facade. Keep loader boundary explicit.
|
||||
type FacadeModule = typeof import("@openclaw/discord/contract-api.js");
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "discord",
|
||||
artifactBasename: "contract-api.js",
|
||||
});
|
||||
}
|
||||
|
||||
export const collectDiscordSecurityAuditFindings: FacadeModule["collectDiscordSecurityAuditFindings"] =
|
||||
((...args) =>
|
||||
loadFacadeModule().collectDiscordSecurityAuditFindings(
|
||||
...args,
|
||||
)) as FacadeModule["collectDiscordSecurityAuditFindings"];
|
||||
@@ -2,6 +2,16 @@
|
||||
// Keep this list additive and scoped to the bundled Matrix surface.
|
||||
|
||||
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
type MatrixFacadeModule = typeof import("@openclaw/matrix/contract-api.js");
|
||||
|
||||
function loadMatrixFacadeModule(): MatrixFacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<MatrixFacadeModule>({
|
||||
dirName: "matrix",
|
||||
artifactBasename: "contract-api.js",
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
createActionGate,
|
||||
@@ -179,6 +189,18 @@ export {
|
||||
} from "./matrix-surface.js";
|
||||
export { setMatrixRuntime } from "./matrix-runtime-surface.js";
|
||||
|
||||
export const singleAccountKeysToMove: MatrixFacadeModule["singleAccountKeysToMove"] =
|
||||
loadMatrixFacadeModule().singleAccountKeysToMove;
|
||||
|
||||
export const namedAccountPromotionKeys: MatrixFacadeModule["namedAccountPromotionKeys"] =
|
||||
loadMatrixFacadeModule().namedAccountPromotionKeys;
|
||||
|
||||
export const resolveSingleAccountPromotionTarget: MatrixFacadeModule["resolveSingleAccountPromotionTarget"] =
|
||||
((...args) =>
|
||||
loadMatrixFacadeModule().resolveSingleAccountPromotionTarget(
|
||||
...args,
|
||||
)) as MatrixFacadeModule["resolveSingleAccountPromotionTarget"];
|
||||
|
||||
const matrixSetup = createOptionalChannelSetupSurface({
|
||||
channel: "matrix",
|
||||
label: "Matrix",
|
||||
|
||||
16
src/plugin-sdk/synology-chat.ts
Normal file
16
src/plugin-sdk/synology-chat.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// Manual facade. Keep loader boundary explicit.
|
||||
type FacadeModule = typeof import("@openclaw/synology-chat/contract-api.js");
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "synology-chat",
|
||||
artifactBasename: "contract-api.js",
|
||||
});
|
||||
}
|
||||
|
||||
export const collectSynologyChatSecurityAuditFindings: FacadeModule["collectSynologyChatSecurityAuditFindings"] =
|
||||
((...args) =>
|
||||
loadFacadeModule().collectSynologyChatSecurityAuditFindings(
|
||||
...args,
|
||||
)) as FacadeModule["collectSynologyChatSecurityAuditFindings"];
|
||||
@@ -15,3 +15,12 @@ export const parseTelegramTopicConversation: FacadeModule["parseTelegramTopicCon
|
||||
loadFacadeModule().parseTelegramTopicConversation(
|
||||
...args,
|
||||
)) as FacadeModule["parseTelegramTopicConversation"];
|
||||
|
||||
export const singleAccountKeysToMove: FacadeModule["singleAccountKeysToMove"] =
|
||||
loadFacadeModule().singleAccountKeysToMove;
|
||||
|
||||
export const collectTelegramSecurityAuditFindings: FacadeModule["collectTelegramSecurityAuditFindings"] =
|
||||
((...args) =>
|
||||
loadFacadeModule().collectTelegramSecurityAuditFindings(
|
||||
...args,
|
||||
)) as FacadeModule["collectTelegramSecurityAuditFindings"];
|
||||
|
||||
@@ -78,6 +78,22 @@ export { formatResolvedUnresolvedNote } from "./resolution-notes.js";
|
||||
export { buildBaseAccountStatusSnapshot } from "./status-helpers.js";
|
||||
export { chunkTextForOutbound } from "./text-chunking.js";
|
||||
|
||||
type FacadeModule = typeof import("@openclaw/zalouser/contract-api.js");
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "zalouser",
|
||||
artifactBasename: "contract-api.js",
|
||||
});
|
||||
}
|
||||
|
||||
export const collectZalouserSecurityAuditFindings: FacadeModule["collectZalouserSecurityAuditFindings"] =
|
||||
((...args) =>
|
||||
loadFacadeModule().collectZalouserSecurityAuditFindings(
|
||||
...args,
|
||||
)) as FacadeModule["collectZalouserSecurityAuditFindings"];
|
||||
|
||||
const zalouserSetup = createOptionalChannelSetupSurface({
|
||||
channel: "zalouser",
|
||||
label: "Zalo Personal",
|
||||
|
||||
@@ -12,6 +12,7 @@ const ALLOWED_BUNDLED_CAPABILITY_METADATA_CONSUMERS = new Set([
|
||||
]);
|
||||
|
||||
const ALLOWED_EXTENSION_PATH_STRING_TESTS = new Set([
|
||||
"src/plugin-sdk/browser-maintenance.test.ts",
|
||||
"src/channels/plugins/bundled.shape-guard.test.ts",
|
||||
"src/plugins/contracts/bundled-extension-config-api-guardrails.test.ts",
|
||||
"src/scripts/test-projects.test.ts",
|
||||
|
||||
@@ -41,6 +41,7 @@ const EXPECTED_SHARED_FAMILY_CONTRACTS: Record<string, ExpectedSharedFamilyContr
|
||||
google: {
|
||||
replayFamilies: ["google-gemini"],
|
||||
streamFamilies: ["google-thinking"],
|
||||
toolCompatFamilies: ["gemini"],
|
||||
},
|
||||
kilocode: {
|
||||
replayFamilies: ["passthrough-gemini"],
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { collectDiscordSecurityAuditFindings } from "../../extensions/discord/contract-api.js";
|
||||
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectDiscordSecurityAuditFindings } from "../plugin-sdk/discord.js";
|
||||
import { withChannelSecurityStateDir } from "./audit-channel-security.test-helpers.js";
|
||||
import { collectChannelSecurityFindings } from "./audit-channel.js";
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { collectDiscordSecurityAuditFindings } from "../../extensions/discord/contract-api.js";
|
||||
import type { ResolvedDiscordAccount } from "../../extensions/discord/src/accounts.js";
|
||||
import type { DiscordAccountConfig } from "../../extensions/discord/src/runtime-api.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectDiscordSecurityAuditFindings } from "../plugin-sdk/discord.js";
|
||||
import { withChannelSecurityStateDir } from "./audit-channel-security.test-helpers.js";
|
||||
|
||||
type DiscordAuditParams = Parameters<typeof collectDiscordSecurityAuditFindings>[0];
|
||||
type ResolvedDiscordAccount = DiscordAuditParams["account"];
|
||||
type DiscordAccountConfig = ResolvedDiscordAccount["config"];
|
||||
|
||||
const { readChannelAllowFromStoreMock } = vi.hoisted(() => ({
|
||||
readChannelAllowFromStoreMock: vi.fn(async () => [] as string[]),
|
||||
}));
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { collectDiscordSecurityAuditFindings } from "../../extensions/discord/contract-api.js";
|
||||
import type { ResolvedDiscordAccount } from "../../extensions/discord/src/accounts.js";
|
||||
import type { DiscordAccountConfig } from "../../extensions/discord/src/runtime-api.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectDiscordSecurityAuditFindings } from "../plugin-sdk/discord.js";
|
||||
|
||||
type DiscordAuditParams = Parameters<typeof collectDiscordSecurityAuditFindings>[0];
|
||||
type ResolvedDiscordAccount = DiscordAuditParams["account"];
|
||||
type DiscordAccountConfig = ResolvedDiscordAccount["config"];
|
||||
|
||||
const { readChannelAllowFromStoreMock } = vi.hoisted(() => ({
|
||||
readChannelAllowFromStoreMock: vi.fn(async () => [] as string[]),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { collectDiscordSecurityAuditFindings } from "../../extensions/discord/contract-api.js";
|
||||
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectDiscordSecurityAuditFindings } from "../plugin-sdk/discord.js";
|
||||
import { collectChannelSecurityFindings } from "./audit-channel.js";
|
||||
|
||||
const { readChannelAllowFromStoreMock } = vi.hoisted(() => ({
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { collectSynologyChatSecurityAuditFindings } from "../../extensions/synology-chat/contract-api.js";
|
||||
import { resolveAccount as resolveSynologyChatAccount } from "../../extensions/synology-chat/src/accounts.js";
|
||||
import { collectZalouserSecurityAuditFindings } from "../../extensions/zalouser/contract-api.js";
|
||||
import type { ResolvedZalouserAccount } from "../../extensions/zalouser/src/accounts.js";
|
||||
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectSynologyChatSecurityAuditFindings } from "../plugin-sdk/synology-chat.js";
|
||||
import { collectZalouserSecurityAuditFindings } from "../plugin-sdk/zalouser.js";
|
||||
import { withChannelSecurityStateDir } from "./audit-channel-security.test-helpers.js";
|
||||
import { collectChannelSecurityFindings } from "./audit-channel.js";
|
||||
|
||||
type SynologyAuditParams = Parameters<typeof collectSynologyChatSecurityAuditFindings>[0];
|
||||
type ResolvedSynologyChatAccount = SynologyAuditParams["account"];
|
||||
type ZalouserAuditParams = Parameters<typeof collectZalouserSecurityAuditFindings>[0];
|
||||
type ResolvedZalouserAccount = ZalouserAuditParams["account"];
|
||||
|
||||
function stubZalouserPlugin(): ChannelPlugin {
|
||||
return {
|
||||
id: "zalouser",
|
||||
@@ -44,6 +47,28 @@ function stubZalouserPlugin(): ChannelPlugin {
|
||||
};
|
||||
}
|
||||
|
||||
function createSynologyChatAccount(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId: string;
|
||||
}): ResolvedSynologyChatAccount {
|
||||
const channel = params.cfg.channels?.["synology-chat"] ?? {};
|
||||
const accountConfig =
|
||||
params.accountId === "default"
|
||||
? channel
|
||||
: ((channel.accounts as Record<string, unknown> | undefined)?.[params.accountId] ?? {});
|
||||
return {
|
||||
accountId: params.accountId,
|
||||
dangerouslyAllowNameMatching:
|
||||
Boolean(
|
||||
(accountConfig as { dangerouslyAllowNameMatching?: boolean }).dangerouslyAllowNameMatching,
|
||||
) ||
|
||||
Boolean(
|
||||
params.accountId === "default" &&
|
||||
(channel as { dangerouslyAllowNameMatching?: boolean }).dangerouslyAllowNameMatching,
|
||||
),
|
||||
} as ResolvedSynologyChatAccount;
|
||||
}
|
||||
|
||||
describe("security audit synology and zalo channel routing", () => {
|
||||
it.each([
|
||||
{
|
||||
@@ -100,7 +125,7 @@ describe("security audit synology and zalo channel routing", () => {
|
||||
? "beta"
|
||||
: "default";
|
||||
const findings = collectSynologyChatSecurityAuditFindings({
|
||||
account: resolveSynologyChatAccount(testCase.cfg, accountId),
|
||||
account: createSynologyChatAccount({ cfg: testCase.cfg, accountId }),
|
||||
accountId,
|
||||
orderedAccountIds: Object.keys(synologyChat.accounts ?? {}),
|
||||
hasExplicitAccountPath: accountId !== "default",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { collectTelegramSecurityAuditFindings } from "../../extensions/telegram/contract-api.js";
|
||||
import type { ResolvedTelegramAccount } from "../../extensions/telegram/src/accounts.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { collectTelegramSecurityAuditFindings } from "../plugin-sdk/telegram.js";
|
||||
import { withChannelSecurityStateDir } from "./audit-channel-security.test-helpers.js";
|
||||
|
||||
type TelegramAuditParams = Parameters<typeof collectTelegramSecurityAuditFindings>[0];
|
||||
type ResolvedTelegramAccount = TelegramAuditParams["account"];
|
||||
|
||||
const { readChannelAllowFromStoreMock } = vi.hoisted(() => ({
|
||||
readChannelAllowFromStoreMock: vi.fn(async () => [] as string[]),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user