mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 22:47:26 +00:00
refactor(security): centralize audit execution context
This commit is contained in:
@@ -110,6 +110,24 @@ export type SecurityAuditOptions = {
|
||||
codeSafetySummaryCache?: Map<string, Promise<unknown>>;
|
||||
};
|
||||
|
||||
type AuditExecutionContext = {
|
||||
cfg: OpenClawConfig;
|
||||
env: NodeJS.ProcessEnv;
|
||||
platform: NodeJS.Platform;
|
||||
includeFilesystem: boolean;
|
||||
includeChannelSecurity: boolean;
|
||||
deep: boolean;
|
||||
deepTimeoutMs: number;
|
||||
stateDir: string;
|
||||
configPath: string;
|
||||
execIcacls?: ExecFn;
|
||||
execDockerRawFn?: typeof execDockerRaw;
|
||||
probeGatewayFn?: typeof probeGateway;
|
||||
plugins?: ReturnType<typeof listChannelPlugins>;
|
||||
configSnapshot: ConfigFileSnapshot | null;
|
||||
codeSafetySummaryCache: Map<string, Promise<unknown>>;
|
||||
};
|
||||
|
||||
function countBySeverity(findings: SecurityAuditFinding[]): SecurityAuditSummary {
|
||||
let critical = 0;
|
||||
let warn = 0;
|
||||
@@ -1004,14 +1022,46 @@ async function maybeProbeGateway(params: {
|
||||
};
|
||||
}
|
||||
|
||||
export async function runSecurityAudit(opts: SecurityAuditOptions): Promise<SecurityAuditReport> {
|
||||
const findings: SecurityAuditFinding[] = [];
|
||||
async function createAuditExecutionContext(
|
||||
opts: SecurityAuditOptions,
|
||||
): Promise<AuditExecutionContext> {
|
||||
const cfg = opts.config;
|
||||
const env = opts.env ?? process.env;
|
||||
const platform = opts.platform ?? process.platform;
|
||||
const execIcacls = opts.execIcacls;
|
||||
const includeFilesystem = opts.includeFilesystem !== false;
|
||||
const includeChannelSecurity = opts.includeChannelSecurity !== false;
|
||||
const deep = opts.deep === true;
|
||||
const deepTimeoutMs = Math.max(250, opts.deepTimeoutMs ?? 5000);
|
||||
const stateDir = opts.stateDir ?? resolveStateDir(env);
|
||||
const configPath = opts.configPath ?? resolveConfigPath(env, stateDir);
|
||||
const configSnapshot = includeFilesystem
|
||||
? opts.configSnapshot !== undefined
|
||||
? opts.configSnapshot
|
||||
: await readConfigSnapshotForAudit({ env, configPath }).catch(() => null)
|
||||
: null;
|
||||
return {
|
||||
cfg,
|
||||
env,
|
||||
platform,
|
||||
includeFilesystem,
|
||||
includeChannelSecurity,
|
||||
deep,
|
||||
deepTimeoutMs,
|
||||
stateDir,
|
||||
configPath,
|
||||
execIcacls: opts.execIcacls,
|
||||
execDockerRawFn: opts.execDockerRawFn,
|
||||
probeGatewayFn: opts.probeGatewayFn,
|
||||
plugins: opts.plugins,
|
||||
configSnapshot,
|
||||
codeSafetySummaryCache: opts.codeSafetySummaryCache ?? new Map<string, Promise<unknown>>(),
|
||||
};
|
||||
}
|
||||
|
||||
export async function runSecurityAudit(opts: SecurityAuditOptions): Promise<SecurityAuditReport> {
|
||||
const findings: SecurityAuditFinding[] = [];
|
||||
const context = await createAuditExecutionContext(opts);
|
||||
const { cfg, env, platform, stateDir, configPath } = context;
|
||||
|
||||
findings.push(...collectAttackSurfaceSummaryFindings(cfg));
|
||||
findings.push(...collectSyncedFolderFindings({ stateDir, configPath }));
|
||||
@@ -1035,71 +1085,72 @@ export async function runSecurityAudit(opts: SecurityAuditOptions): Promise<Secu
|
||||
findings.push(...collectExposureMatrixFindings(cfg));
|
||||
findings.push(...collectLikelyMultiUserSetupFindings(cfg));
|
||||
|
||||
const configSnapshot =
|
||||
opts.includeFilesystem !== false
|
||||
? opts.configSnapshot !== undefined
|
||||
? opts.configSnapshot
|
||||
: await readConfigSnapshotForAudit({ env, configPath }).catch(() => null)
|
||||
: null;
|
||||
|
||||
if (opts.includeFilesystem !== false) {
|
||||
const codeSafetySummaryCache =
|
||||
opts.codeSafetySummaryCache ?? new Map<string, Promise<unknown>>();
|
||||
if (context.includeFilesystem) {
|
||||
findings.push(
|
||||
...(await collectFilesystemFindings({
|
||||
stateDir,
|
||||
configPath,
|
||||
env,
|
||||
platform,
|
||||
execIcacls,
|
||||
execIcacls: context.execIcacls,
|
||||
})),
|
||||
);
|
||||
if (configSnapshot) {
|
||||
if (context.configSnapshot) {
|
||||
findings.push(
|
||||
...(await collectIncludeFilePermFindings({ configSnapshot, env, platform, execIcacls })),
|
||||
...(await collectIncludeFilePermFindings({
|
||||
configSnapshot: context.configSnapshot,
|
||||
env,
|
||||
platform,
|
||||
execIcacls: context.execIcacls,
|
||||
})),
|
||||
);
|
||||
}
|
||||
findings.push(
|
||||
...(await collectStateDeepFilesystemFindings({ cfg, env, stateDir, platform, execIcacls })),
|
||||
...(await collectStateDeepFilesystemFindings({
|
||||
cfg,
|
||||
env,
|
||||
stateDir,
|
||||
platform,
|
||||
execIcacls: context.execIcacls,
|
||||
})),
|
||||
);
|
||||
findings.push(...(await collectWorkspaceSkillSymlinkEscapeFindings({ cfg })));
|
||||
findings.push(
|
||||
...(await collectSandboxBrowserHashLabelFindings({
|
||||
execDockerRawFn: opts.execDockerRawFn,
|
||||
execDockerRawFn: context.execDockerRawFn,
|
||||
})),
|
||||
);
|
||||
findings.push(...(await collectPluginsTrustFindings({ cfg, stateDir })));
|
||||
if (opts.deep === true) {
|
||||
if (context.deep) {
|
||||
findings.push(
|
||||
...(await collectPluginsCodeSafetyFindings({
|
||||
stateDir,
|
||||
summaryCache: codeSafetySummaryCache,
|
||||
summaryCache: context.codeSafetySummaryCache,
|
||||
})),
|
||||
);
|
||||
findings.push(
|
||||
...(await collectInstalledSkillsCodeSafetyFindings({
|
||||
cfg,
|
||||
stateDir,
|
||||
summaryCache: codeSafetySummaryCache,
|
||||
summaryCache: context.codeSafetySummaryCache,
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.includeChannelSecurity !== false) {
|
||||
const plugins = opts.plugins ?? listChannelPlugins();
|
||||
if (context.includeChannelSecurity) {
|
||||
const plugins = context.plugins ?? listChannelPlugins();
|
||||
findings.push(...(await collectChannelSecurityFindings({ cfg, plugins })));
|
||||
}
|
||||
|
||||
const deep =
|
||||
opts.deep === true
|
||||
? await maybeProbeGateway({
|
||||
cfg,
|
||||
env,
|
||||
timeoutMs: Math.max(250, opts.deepTimeoutMs ?? 5000),
|
||||
probe: opts.probeGatewayFn ?? probeGateway,
|
||||
})
|
||||
: undefined;
|
||||
const deep = context.deep
|
||||
? await maybeProbeGateway({
|
||||
cfg,
|
||||
env,
|
||||
timeoutMs: context.deepTimeoutMs,
|
||||
probe: context.probeGatewayFn ?? probeGateway,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (deep?.gateway?.attempted && !deep.gateway.ok) {
|
||||
findings.push({
|
||||
|
||||
Reference in New Issue
Block a user