perf(core): speed up routing, pairing, slack, and security scans

This commit is contained in:
Peter Steinberger
2026-03-02 21:07:34 +00:00
parent 3a08e69a05
commit 5a32a66aa8
11 changed files with 462 additions and 38 deletions

View File

@@ -52,6 +52,8 @@ type ExecDockerRawFn = (
opts?: { allowFailure?: boolean; input?: Buffer | string; signal?: AbortSignal },
) => Promise<ExecDockerRawResult>;
type CodeSafetySummaryCache = Map<string, Promise<unknown>>;
// --------------------------------------------------------------------------
// Helpers
// --------------------------------------------------------------------------
@@ -246,6 +248,41 @@ async function readInstalledPackageVersion(dir: string): Promise<string | undefi
}
}
function buildCodeSafetySummaryCacheKey(params: {
dirPath: string;
includeFiles?: string[];
}): string {
const includeFiles = (params.includeFiles ?? []).map((entry) => entry.trim()).filter(Boolean);
const includeKey = includeFiles.length > 0 ? includeFiles.toSorted().join("\u0000") : "";
return `${params.dirPath}\u0000${includeKey}`;
}
async function getCodeSafetySummary(params: {
dirPath: string;
includeFiles?: string[];
summaryCache?: CodeSafetySummaryCache;
}): Promise<Awaited<ReturnType<typeof skillScanner.scanDirectoryWithSummary>>> {
const cacheKey = buildCodeSafetySummaryCacheKey({
dirPath: params.dirPath,
includeFiles: params.includeFiles,
});
const cache = params.summaryCache;
if (cache) {
const hit = cache.get(cacheKey);
if (hit) {
return (await hit) as Awaited<ReturnType<typeof skillScanner.scanDirectoryWithSummary>>;
}
const pending = skillScanner.scanDirectoryWithSummary(params.dirPath, {
includeFiles: params.includeFiles,
});
cache.set(cacheKey, pending);
return await pending;
}
return await skillScanner.scanDirectoryWithSummary(params.dirPath, {
includeFiles: params.includeFiles,
});
}
// --------------------------------------------------------------------------
// Exported collectors
// --------------------------------------------------------------------------
@@ -965,6 +1002,7 @@ export async function readConfigSnapshotForAudit(params: {
export async function collectPluginsCodeSafetyFindings(params: {
stateDir: string;
summaryCache?: CodeSafetySummaryCache;
}): Promise<SecurityAuditFinding[]> {
const findings: SecurityAuditFinding[] = [];
const { extensionsDir, pluginDirs } = await listInstalledPluginDirs({
@@ -1016,21 +1054,21 @@ export async function collectPluginsCodeSafetyFindings(params: {
});
}
const summary = await skillScanner
.scanDirectoryWithSummary(pluginPath, {
includeFiles: forcedScanEntries,
})
.catch((err) => {
findings.push({
checkId: "plugins.code_safety.scan_failed",
severity: "warn",
title: `Plugin "${pluginName}" code scan failed`,
detail: `Static code scan could not complete: ${String(err)}`,
remediation:
"Check file permissions and plugin layout, then rerun `openclaw security audit --deep`.",
});
return null;
const summary = await getCodeSafetySummary({
dirPath: pluginPath,
includeFiles: forcedScanEntries,
summaryCache: params.summaryCache,
}).catch((err) => {
findings.push({
checkId: "plugins.code_safety.scan_failed",
severity: "warn",
title: `Plugin "${pluginName}" code scan failed`,
detail: `Static code scan could not complete: ${String(err)}`,
remediation:
"Check file permissions and plugin layout, then rerun `openclaw security audit --deep`.",
});
return null;
});
if (!summary) {
continue;
}
@@ -1067,6 +1105,7 @@ export async function collectPluginsCodeSafetyFindings(params: {
export async function collectInstalledSkillsCodeSafetyFindings(params: {
cfg: OpenClawConfig;
stateDir: string;
summaryCache?: CodeSafetySummaryCache;
}): Promise<SecurityAuditFinding[]> {
const findings: SecurityAuditFinding[] = [];
const pluginExtensionsDir = path.join(params.stateDir, "extensions");
@@ -1091,7 +1130,10 @@ export async function collectInstalledSkillsCodeSafetyFindings(params: {
scannedSkillDirs.add(skillDir);
const skillName = entry.skill.name;
const summary = await skillScanner.scanDirectoryWithSummary(skillDir).catch((err) => {
const summary = await getCodeSafetySummary({
dirPath: skillDir,
summaryCache: params.summaryCache,
}).catch((err) => {
findings.push({
checkId: "skills.code_safety.scan_failed",
severity: "warn",