perf: speed up security audit test imports

This commit is contained in:
Peter Steinberger
2026-04-16 21:54:01 +01:00
parent cd45f53b4e
commit 8a37bb4ed6
19 changed files with 321 additions and 37 deletions

View File

@@ -0,0 +1,6 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { inspectDiscordAccount } from "./src/account-inspect.js";
export function inspectDiscordReadOnlyAccount(cfg: OpenClawConfig, accountId?: string | null) {
return inspectDiscordAccount({ cfg, accountId });
}

View File

@@ -22,6 +22,10 @@ export default defineBundledChannelEntry({
specifier: "./runtime-api.js",
exportName: "setDiscordRuntime",
},
accountInspect: {
specifier: "./account-inspect-api.js",
exportName: "inspectDiscordReadOnlyAccount",
},
registerFull(api) {
api.on("subagent_spawning", async (event) => {
const { handleDiscordSubagentSpawning } = await loadDiscordSubagentHooksModule();

View File

@@ -1 +1,81 @@
export { collectFeishuSecurityAuditFindings } from "./src/security-audit.js";
import type { OpenClawConfig } from "./runtime-api.js";
function asRecord(value: unknown): Record<string, unknown> | undefined {
return value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: undefined;
}
function hasNonEmptyString(value: unknown): boolean {
return typeof value === "string" && value.trim().length > 0;
}
function hasConfiguredSecretInput(value: unknown): boolean {
if (hasNonEmptyString(value)) {
return true;
}
const record = asRecord(value);
return (
Boolean(record) &&
hasNonEmptyString(record?.source) &&
hasNonEmptyString(record?.provider) &&
hasNonEmptyString(record?.id)
);
}
function isFeishuDocToolEnabled(cfg: OpenClawConfig): boolean {
const channels = asRecord(cfg.channels);
const feishu = asRecord(channels?.feishu);
if (!feishu || feishu.enabled === false) {
return false;
}
const baseTools = asRecord(feishu.tools);
const baseDocEnabled = baseTools?.doc !== false;
const baseAppId = hasNonEmptyString(feishu.appId);
const baseAppSecret = hasConfiguredSecretInput(feishu.appSecret);
const baseConfigured = baseAppId && baseAppSecret;
const accounts = asRecord(feishu.accounts);
if (!accounts || Object.keys(accounts).length === 0) {
return baseDocEnabled && baseConfigured;
}
for (const accountValue of Object.values(accounts)) {
const account = asRecord(accountValue) ?? {};
if (account.enabled === false) {
continue;
}
const accountTools = asRecord(account.tools);
const effectiveTools = accountTools ?? baseTools;
const docEnabled = effectiveTools?.doc !== false;
if (!docEnabled) {
continue;
}
const accountConfigured =
(hasNonEmptyString(account.appId) || baseAppId) &&
(hasConfiguredSecretInput(account.appSecret) || baseAppSecret);
if (accountConfigured) {
return true;
}
}
return false;
}
export function collectFeishuSecurityAuditFindings(params: { cfg: OpenClawConfig }) {
if (!isFeishuDocToolEnabled(params.cfg)) {
return [];
}
return [
{
checkId: "channels.feishu.doc_owner_open_id",
severity: "warn" as const,
title: "Feishu doc create can grant requester permissions",
detail:
'channels.feishu tools include "doc"; feishu_doc action "create" can grant document access to the trusted requesting Feishu user.',
remediation:
"Disable channels.feishu.tools.doc when not needed, and restrict tool access for untrusted prompts.",
},
];
}

View File

@@ -0,0 +1,6 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { inspectSlackAccount } from "./src/account-inspect.js";
export function inspectSlackReadOnlyAccount(cfg: OpenClawConfig, accountId?: string | null) {
return inspectSlackAccount({ cfg, accountId });
}

View File

@@ -29,5 +29,9 @@ export default defineBundledChannelEntry({
specifier: "./runtime-api.js",
exportName: "setSlackRuntime",
},
accountInspect: {
specifier: "./account-inspect-api.js",
exportName: "inspectSlackReadOnlyAccount",
},
registerFull: registerSlackPluginHttpRoutes,
});

View File

@@ -0,0 +1,6 @@
import type { OpenClawConfig } from "./runtime-api.js";
import { inspectTelegramAccount } from "./src/account-inspect.js";
export function inspectTelegramReadOnlyAccount(cfg: OpenClawConfig, accountId?: string | null) {
return inspectTelegramAccount({ cfg, accountId });
}

View File

@@ -17,4 +17,8 @@ export default defineBundledChannelEntry({
specifier: "./runtime-api.js",
exportName: "setTelegramRuntime",
},
accountInspect: {
specifier: "./account-inspect-api.js",
exportName: "inspectTelegramReadOnlyAccount",
},
});

View File

@@ -0,0 +1,3 @@
// Keep bundled channel entry imports narrow so bootstrap/discovery paths do
// not drag setup-only or tool runtime surfaces into lightweight plugin loads.
export { zalouserPlugin } from "./src/channel.js";

View File

@@ -21,7 +21,7 @@ export default defineBundledChannelEntry({
description: "Zalo personal account messaging via native zca-js integration",
importMetaUrl: import.meta.url,
plugin: {
specifier: "./api.js",
specifier: "./channel-plugin-api.js",
exportName: "zalouserPlugin",
},
runtime: {

View File

@@ -3,7 +3,7 @@ import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entr
export default defineBundledChannelSetupEntry({
importMetaUrl: import.meta.url,
plugin: {
specifier: "./api.js",
specifier: "./setup-plugin-api.js",
exportName: "zalouserSetupPlugin",
},
});

View File

@@ -0,0 +1,2 @@
// Keep setup-entry imports narrow so setup loads do not pull tool surfaces.
export { zalouserSetupPlugin } from "./src/channel.setup.js";

View File

@@ -27,12 +27,14 @@ import {
} from "./channel.adapters.js";
import { listZalouserDirectoryGroupMembers } from "./directory.js";
import type { ZalouserProbeResult } from "./probe.js";
import { zalouserSetupAdapter } from "./setup-core.js";
import { zalouserSetupWizard } from "./setup-surface.js";
import { createZalouserSetupWizardProxy, zalouserSetupAdapter } from "./setup-core.js";
import { createZalouserPluginBase } from "./shared.js";
import { collectZalouserStatusIssues } from "./status-issues.js";
const loadZalouserChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime.js"));
const zalouserSetupWizardProxy = createZalouserSetupWizardProxy(
async () => (await import("./setup-surface.js")).zalouserSetupWizard,
);
function mapUser(params: {
id: string;
@@ -66,7 +68,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount, ZalouserProb
createChatChannelPlugin({
base: {
...createZalouserPluginBase({
setupWizard: zalouserSetupWizard,
setupWizard: zalouserSetupWizardProxy,
setup: zalouserSetupAdapter,
}),
groups: zalouserGroupsAdapter,

View File

@@ -1,4 +1,8 @@
import { createPatchedAccountSetupAdapter } from "openclaw/plugin-sdk/setup-runtime";
import {
createDelegatedSetupWizardProxy,
createPatchedAccountSetupAdapter,
type ChannelSetupWizard,
} from "openclaw/plugin-sdk/setup-runtime";
const channel = "zalouser" as const;
@@ -7,3 +11,23 @@ export const zalouserSetupAdapter = createPatchedAccountSetupAdapter({
validateInput: () => null,
buildPatch: () => ({}),
});
export function createZalouserSetupWizardProxy(
loadWizard: () => Promise<ChannelSetupWizard>,
): ChannelSetupWizard {
return createDelegatedSetupWizardProxy({
channel,
loadWizard,
status: {
configuredLabel: "logged in",
unconfiguredLabel: "needs QR login",
configuredHint: "recommended · logged in",
unconfiguredHint: "recommended · QR login",
configuredScore: 1,
unconfiguredScore: 15,
},
credentials: [],
delegatePrepare: true,
delegateFinalize: true,
});
}

View File

@@ -18,9 +18,13 @@ type BundledChannelEntryRuntimeContract = {
id: string;
name: string;
description: string;
features?: {
accountInspect?: boolean;
};
register: (api: unknown) => void;
loadChannelPlugin: () => ChannelPlugin;
loadChannelSecrets?: () => ChannelPlugin["secrets"] | undefined;
loadChannelAccountInspector?: () => NonNullable<ChannelPlugin["config"]["inspectAccount"]>;
setChannelRuntime?: (runtime: PluginRuntime) => void;
};
@@ -49,6 +53,10 @@ type BundledChannelCacheContext = {
lazySetupPluginsById: Map<ChannelId, ChannelPlugin>;
lazySecretsById: Map<ChannelId, ChannelPlugin["secrets"] | null>;
lazySetupSecretsById: Map<ChannelId, ChannelPlugin["secrets"] | null>;
lazyAccountInspectorsById: Map<
ChannelId,
NonNullable<ChannelPlugin["config"]["inspectAccount"]> | null
>;
};
const log = createSubsystemLogger("channels");
@@ -100,6 +108,13 @@ function hasSetupEntryFeature(
return entry?.features?.[feature] === true;
}
function hasChannelEntryFeature(
entry: BundledChannelEntryRuntimeContract | undefined,
feature: keyof NonNullable<BundledChannelEntryRuntimeContract["features"]>,
): boolean {
return entry?.features?.[feature] === true;
}
function resolveBundledChannelBoundaryRoot(params: {
packageRoot: string;
pluginsDir?: string;
@@ -222,6 +237,7 @@ function createBundledChannelCacheContext(): BundledChannelCacheContext {
lazySetupPluginsById: new Map(),
lazySecretsById: new Map(),
lazySetupSecretsById: new Map(),
lazyAccountInspectorsById: new Map(),
};
}
@@ -368,6 +384,24 @@ function getBundledChannelSecretsForRoot(
return secrets;
}
function getBundledChannelAccountInspectorForRoot(
id: ChannelId,
rootScope: BundledChannelRootScope,
cacheContext: BundledChannelCacheContext,
): NonNullable<ChannelPlugin["config"]["inspectAccount"]> | undefined {
if (cacheContext.lazyAccountInspectorsById.has(id)) {
return cacheContext.lazyAccountInspectorsById.get(id) ?? undefined;
}
const entry = getLazyGeneratedBundledChannelEntryForRoot(id, rootScope, cacheContext)?.entry;
if (!entry?.loadChannelAccountInspector) {
cacheContext.lazyAccountInspectorsById.set(id, null);
return undefined;
}
const inspector = entry.loadChannelAccountInspector();
cacheContext.lazyAccountInspectorsById.set(id, inspector);
return inspector;
}
function getBundledChannelSetupPluginForRoot(
id: ChannelId,
rootScope: BundledChannelRootScope,
@@ -449,6 +483,22 @@ export function listBundledChannelSetupPluginsByFeature(
});
}
export function hasBundledChannelEntryFeature(
id: ChannelId,
feature: keyof NonNullable<BundledChannelEntryRuntimeContract["features"]>,
): boolean {
const { rootScope, cacheContext } = resolveActiveBundledChannelCacheScope();
const entry = getLazyGeneratedBundledChannelEntryForRoot(id, rootScope, cacheContext)?.entry;
return hasChannelEntryFeature(entry, feature);
}
export function getBundledChannelAccountInspector(
id: ChannelId,
): NonNullable<ChannelPlugin["config"]["inspectAccount"]> | undefined {
const { rootScope, cacheContext } = resolveActiveBundledChannelCacheScope();
return getBundledChannelAccountInspectorForRoot(id, rootScope, cacheContext);
}
export function getBundledChannelPlugin(id: ChannelId): ChannelPlugin | undefined {
const { rootScope, cacheContext } = resolveActiveBundledChannelCacheScope();
return getBundledChannelPluginForRoot(id, rootScope, cacheContext);

View File

@@ -1,5 +1,6 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { getChannelPlugin } from "./plugins/registry.js";
import { getBundledChannelAccountInspector } from "./plugins/bundled.js";
import { getLoadedChannelPlugin } from "./plugins/registry.js";
import type { ChannelId } from "./plugins/types.public.js";
export type ReadOnlyInspectedAccount = Record<string, unknown>;
@@ -9,7 +10,9 @@ export async function inspectReadOnlyChannelAccount(params: {
cfg: OpenClawConfig;
accountId?: string | null;
}): Promise<ReadOnlyInspectedAccount | null> {
const inspectAccount = getChannelPlugin(params.channelId)?.config.inspectAccount;
const inspectAccount =
getLoadedChannelPlugin(params.channelId)?.config.inspectAccount ??
getBundledChannelAccountInspector(params.channelId);
if (!inspectAccount) {
return null;
}

View File

@@ -36,6 +36,8 @@ type DefineBundledChannelEntryOptions<TPlugin = ChannelPlugin> = {
secrets?: BundledEntryModuleRef;
configSchema?: ChannelEntryConfigSchema<TPlugin> | (() => ChannelEntryConfigSchema<TPlugin>);
runtime?: BundledEntryModuleRef;
accountInspect?: BundledEntryModuleRef;
features?: BundledChannelEntryFeatures;
registerCliMetadata?: (api: OpenClawPluginApi) => void;
registerFull?: (api: OpenClawPluginApi) => void;
};
@@ -53,15 +55,21 @@ export type BundledChannelSetupEntryFeatures = {
legacySessionSurfaces?: boolean;
};
export type BundledChannelEntryFeatures = {
accountInspect?: boolean;
};
export type BundledChannelEntryContract<TPlugin = ChannelPlugin> = {
kind: "bundled-channel-entry";
id: string;
name: string;
description: string;
configSchema: ChannelEntryConfigSchema<TPlugin>;
features?: BundledChannelEntryFeatures;
register: (api: OpenClawPluginApi) => void;
loadChannelPlugin: () => TPlugin;
loadChannelSecrets?: () => ChannelPlugin["secrets"] | undefined;
loadChannelAccountInspector?: () => NonNullable<ChannelPlugin["config"]["inspectAccount"]>;
setChannelRuntime?: (runtime: PluginRuntime) => void;
};
@@ -332,6 +340,8 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
secrets,
configSchema,
runtime,
accountInspect,
features,
registerCliMetadata,
registerFull,
}: DefineBundledChannelEntryOptions<TPlugin>): BundledChannelEntryContract<TPlugin> {
@@ -343,6 +353,13 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
const loadChannelSecrets = secrets
? () => loadBundledEntryExportSync<ChannelPlugin["secrets"] | undefined>(importMetaUrl, secrets)
: undefined;
const loadChannelAccountInspector = accountInspect
? () =>
loadBundledEntryExportSync<NonNullable<ChannelPlugin["config"]["inspectAccount"]>>(
importMetaUrl,
accountInspect,
)
: undefined;
const setChannelRuntime = runtime
? (pluginRuntime: PluginRuntime) => {
const setter = loadBundledEntryExportSync<(runtime: PluginRuntime) => void>(
@@ -359,6 +376,9 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
name,
description,
configSchema: resolvedConfigSchema,
...(features || accountInspect
? { features: { ...features, ...(accountInspect ? { accountInspect: true } : {}) } }
: {}),
register(api: OpenClawPluginApi) {
if (api.registrationMode === "cli-metadata") {
registerCliMetadata?.(api);
@@ -374,6 +394,7 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
},
loadChannelPlugin,
...(loadChannelSecrets ? { loadChannelSecrets } : {}),
...(loadChannelAccountInspector ? { loadChannelAccountInspector } : {}),
...(setChannelRuntime ? { setChannelRuntime } : {}),
};
}

View File

@@ -1,7 +1,7 @@
import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { fileURLToPath, pathToFileURL } from "node:url";
import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js";
import {
@@ -275,6 +275,54 @@ export function loadBundledPluginPublicSurfaceModuleSync<T extends object>(param
});
}
export async function loadBundledPluginPublicSurfaceModule<T extends object>(params: {
dirName: string;
artifactBasename: string;
trackedPluginId?: string | (() => string);
env?: NodeJS.ProcessEnv;
}): Promise<T> {
const location = resolveFacadeModuleLocation(params);
if (!location) {
throw new Error(
`Unable to resolve bundled plugin public surface ${params.dirName}/${params.artifactBasename}`,
);
}
const cached = loadedFacadeModules.get(location.modulePath);
if (cached) {
return cached as T;
}
const opened = openBoundaryFileSync({
absolutePath: location.modulePath,
rootPath: location.boundaryRoot,
boundaryLabel:
location.boundaryRoot === getOpenClawPackageRoot() ? "OpenClaw package root" : "plugin root",
rejectHardlinks: false,
});
if (!opened.ok) {
throw new Error(`Unable to open bundled plugin public surface ${location.modulePath}`, {
cause: opened.error,
});
}
fs.closeSync(opened.fd);
try {
const loaded = (await import(pathToFileURL(location.modulePath).href)) as T;
loadedFacadeModules.set(location.modulePath, loaded);
loadedFacadePluginIds.add(
typeof params.trackedPluginId === "function"
? params.trackedPluginId()
: (params.trackedPluginId ?? params.dirName),
);
return loaded;
} catch {
return loadFacadeModuleAtLocationSync({
location,
trackedPluginId: params.trackedPluginId ?? params.dirName,
});
}
}
export function listImportedBundledPluginFacadeIds(): string[] {
return [...loadedFacadePluginIds].toSorted((left, right) => left.localeCompare(right));
}

View File

@@ -3,6 +3,7 @@ type FacadeModule = typeof import("@openclaw/telegram/contract-api.js");
type SecurityAuditFacadeModule = typeof import("@openclaw/telegram/security-audit-contract-api.js");
import {
createLazyFacadeArrayValue,
loadBundledPluginPublicSurfaceModule,
loadBundledPluginPublicSurfaceModuleSync,
} from "./facade-loader.js";
@@ -13,8 +14,8 @@ function loadFacadeModule(): FacadeModule {
});
}
function loadSecurityAuditFacadeModule(): SecurityAuditFacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<SecurityAuditFacadeModule>({
async function loadSecurityAuditFacadeModule(): Promise<SecurityAuditFacadeModule> {
return await loadBundledPluginPublicSurfaceModule<SecurityAuditFacadeModule>({
dirName: "telegram",
artifactBasename: "security-audit-contract-api.js",
});
@@ -31,8 +32,8 @@ export const singleAccountKeysToMove: FacadeModule["singleAccountKeysToMove"] =
createLazyFacadeArrayValue(() => loadFacadeModule().singleAccountKeysToMove);
export const collectTelegramSecurityAuditFindings: FacadeModule["collectTelegramSecurityAuditFindings"] =
((...args) =>
loadSecurityAuditFacadeModule().collectTelegramSecurityAuditFindings(
(async (...args) =>
(await loadSecurityAuditFacadeModule()).collectTelegramSecurityAuditFindings(
...args,
)) as FacadeModule["collectTelegramSecurityAuditFindings"];

View File

@@ -1,18 +1,40 @@
import { loadBundledPluginPublicSurfaceSync } from "../../../src/test-utils/bundled-plugin-public-surface.js";
import {
loadBundledPluginPublicSurfaceSync,
resolveRelativeBundledPluginPublicModuleId,
} from "../../../src/test-utils/bundled-plugin-public-surface.js";
type DiscordSecurityAuditSurface =
typeof import("@openclaw/discord/security-audit-contract-api.js");
type FeishuSecuritySurface = typeof import("@openclaw/feishu/security-contract-api.js");
type SlackSecuritySurface = typeof import("@openclaw/slack/security-contract-api.js");
type SynologyChatSecuritySurface = typeof import("@openclaw/synology-chat/contract-api.js");
type TelegramSecuritySurface = typeof import("@openclaw/telegram/contract-api.js");
type TelegramSecuritySurface = typeof import("@openclaw/telegram/security-audit-contract-api.js");
type ZalouserSecuritySurface = typeof import("@openclaw/zalouser/contract-api.js");
function loadDiscordSecurityAuditSurface(): DiscordSecurityAuditSurface {
return loadBundledPluginPublicSurfaceSync<DiscordSecurityAuditSurface>({
pluginId: "discord",
artifactBasename: "security-audit-contract-api.js",
});
const discordSecurityAuditModuleId = resolveRelativeBundledPluginPublicModuleId({
fromModuleUrl: import.meta.url,
pluginId: "discord",
artifactBasename: "security-audit-contract-api.js",
});
const slackSecurityModuleId = resolveRelativeBundledPluginPublicModuleId({
fromModuleUrl: import.meta.url,
pluginId: "slack",
artifactBasename: "security-contract-api.js",
});
const telegramSecurityModuleId = resolveRelativeBundledPluginPublicModuleId({
fromModuleUrl: import.meta.url,
pluginId: "telegram",
artifactBasename: "security-audit-contract-api.js",
});
let discordSecurityAuditSurfacePromise: Promise<DiscordSecurityAuditSurface> | undefined;
let slackSecuritySurfacePromise: Promise<SlackSecuritySurface> | undefined;
let telegramSecuritySurfacePromise: Promise<TelegramSecuritySurface> | undefined;
function loadDiscordSecurityAuditSurface(): Promise<DiscordSecurityAuditSurface> {
discordSecurityAuditSurfacePromise ??= import(
discordSecurityAuditModuleId
) as Promise<DiscordSecurityAuditSurface>;
return discordSecurityAuditSurfacePromise;
}
function loadFeishuSecuritySurface(): FeishuSecuritySurface {
@@ -22,11 +44,9 @@ function loadFeishuSecuritySurface(): FeishuSecuritySurface {
});
}
function loadSlackSecuritySurface(): SlackSecuritySurface {
return loadBundledPluginPublicSurfaceSync<SlackSecuritySurface>({
pluginId: "slack",
artifactBasename: "security-contract-api.js",
});
function loadSlackSecuritySurface(): Promise<SlackSecuritySurface> {
slackSecuritySurfacePromise ??= import(slackSecurityModuleId) as Promise<SlackSecuritySurface>;
return slackSecuritySurfacePromise;
}
function loadSynologyChatSecuritySurface(): SynologyChatSecuritySurface {
@@ -36,11 +56,11 @@ function loadSynologyChatSecuritySurface(): SynologyChatSecuritySurface {
});
}
function loadTelegramSecuritySurface(): TelegramSecuritySurface {
return loadBundledPluginPublicSurfaceSync<TelegramSecuritySurface>({
pluginId: "telegram",
artifactBasename: "contract-api.js",
});
function loadTelegramSecuritySurface(): Promise<TelegramSecuritySurface> {
telegramSecuritySurfacePromise ??= import(
telegramSecurityModuleId
) as Promise<TelegramSecuritySurface>;
return telegramSecuritySurfacePromise;
}
function loadZalouserSecuritySurface(): ZalouserSecuritySurface {
@@ -51,8 +71,8 @@ function loadZalouserSecuritySurface(): ZalouserSecuritySurface {
}
export const collectDiscordSecurityAuditFindings: DiscordSecurityAuditSurface["collectDiscordSecurityAuditFindings"] =
((...args) =>
loadDiscordSecurityAuditSurface().collectDiscordSecurityAuditFindings(
(async (...args) =>
(await loadDiscordSecurityAuditSurface()).collectDiscordSecurityAuditFindings(
...args,
)) as DiscordSecurityAuditSurface["collectDiscordSecurityAuditFindings"];
@@ -63,8 +83,8 @@ export const collectFeishuSecurityAuditFindings: FeishuSecuritySurface["collectF
)) as FeishuSecuritySurface["collectFeishuSecurityAuditFindings"];
export const collectSlackSecurityAuditFindings: SlackSecuritySurface["collectSlackSecurityAuditFindings"] =
((...args) =>
loadSlackSecuritySurface().collectSlackSecurityAuditFindings(
(async (...args) =>
(await loadSlackSecuritySurface()).collectSlackSecurityAuditFindings(
...args,
)) as SlackSecuritySurface["collectSlackSecurityAuditFindings"];
@@ -75,8 +95,8 @@ export const collectSynologyChatSecurityAuditFindings: SynologyChatSecuritySurfa
)) as SynologyChatSecuritySurface["collectSynologyChatSecurityAuditFindings"];
export const collectTelegramSecurityAuditFindings: TelegramSecuritySurface["collectTelegramSecurityAuditFindings"] =
((...args) =>
loadTelegramSecuritySurface().collectTelegramSecurityAuditFindings(
(async (...args) =>
(await loadTelegramSecuritySurface()).collectTelegramSecurityAuditFindings(
...args,
)) as TelegramSecuritySurface["collectTelegramSecurityAuditFindings"];