






















@@ -75,6 +75,11 @@ import {
7575linkOpenClawPeerDependencies,
7676relinkOpenClawPeerDependenciesInManagedNpmRoot,
7777} from "./plugin-peer-link.js";
78+import {
79+emitPluginAuditSecurityEvent,
80+emitPluginInstallSecurityEvent,
81+type PluginSecuritySourceFamily,
82+} from "./security-events.js";
78837984export { resolvePluginInstallDir } from "./install-paths.js";
8085@@ -550,6 +555,28 @@ function buildDirectoryInstallResult(params: {
550555};
551556}
552557558+function emitSuccessfulPluginInstallSecurityEvent(
559+result: InstallPluginResult,
560+params: {
561+dryRun?: boolean;
562+mode: "install" | "update";
563+sourceFamily: PluginSecuritySourceFamily;
564+trustedSourceLinkedOfficialInstall?: boolean;
565+},
566+) {
567+if (params.dryRun || !result.ok) {
568+return;
569+}
570+emitPluginInstallSecurityEvent({
571+pluginId: result.pluginId,
572+mode: params.mode,
573+sourceFamily: params.sourceFamily,
574+extensionCount: result.extensions.length,
575+hasVersion: Boolean(result.version),
576+trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
577+});
578+}
579+553580function hasPackageRuntimeDependencies(manifest: PackageManifest): boolean {
554581return (
555582Object.keys(manifest.dependencies ?? {}).length > 0 ||
@@ -1829,15 +1856,35 @@ async function resolvePreparedDirectoryInstallTarget(params: {
1829185618301857async function runInstallSourceScan(params: {
18311858subject: string;
1859+pluginId?: string;
1860+mode?: "install" | "update";
1861+sourceFamily?: PluginSecuritySourceFamily;
18321862scan: () => Promise<InstallSecurityScanResult | undefined>;
18331863}): Promise<Extract<InstallPluginResult, { ok: false }> | null> {
18341864try {
18351865const scanResult = await params.scan();
18361866if (scanResult?.blocked) {
1867+emitPluginAuditSecurityEvent({
1868+outcome: "denied",
1869+reason:
1870+scanResult.blocked.code === "security_scan_failed"
1871+ ? "security_scan_failed"
1872+ : "security_scan_blocked",
1873+pluginId: params.pluginId,
1874+mode: params.mode,
1875+sourceFamily: params.sourceFamily,
1876+});
18371877return buildBlockedInstallResult({ blocked: scanResult.blocked });
18381878}
18391879return null;
18401880} catch (err) {
1881+emitPluginAuditSecurityEvent({
1882+outcome: "error",
1883+reason: "security_scan_failed",
1884+pluginId: params.pluginId,
1885+mode: params.mode,
1886+sourceFamily: params.sourceFamily,
1887+});
18411888return {
18421889ok: false,
18431890error: `${params.subject} installation blocked: code safety scan failed (${String(err)}). Run "openclaw security audit --deep" for details.`,
@@ -2037,6 +2084,9 @@ async function installBundleFromSourceDir(
2037208420382085const scanResult = await runInstallSourceScan({
20392086subject: `Bundle "${pluginId}"`,
2087+ pluginId,
2088+mode: targetResult.target.effectiveMode,
2089+sourceFamily: "archive",
20402090scan: async () =>
20412091await runtime.scanBundleInstallSource({
20422092dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
@@ -2237,6 +2287,18 @@ async function validatePackagePluginInstallSource(params: {
22372287 : params.mode;
22382288const scanResult = await runInstallSourceScan({
22392289subject: `Plugin "${pluginId}"`,
2290+ pluginId,
2291+mode: scanMode,
2292+sourceFamily:
2293+params.installPolicyRequest?.kind === "plugin-npm"
2294+ ? "npm"
2295+ : params.installPolicyRequest?.kind === "plugin-archive"
2296+ ? "archive"
2297+ : params.installPolicyRequest?.kind === "plugin-dir"
2298+ ? "directory"
2299+ : params.installPolicyRequest?.kind === "plugin-file"
2300+ ? "file"
2301+ : "installed-package",
22402302scan: async () =>
22412303await params.runtime.scanPackageInstallSource({
22422304dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
@@ -2376,13 +2438,20 @@ export async function installPluginFromInstalledPackageDir(
23762438if (postInstallError) {
23772439return postInstallError;
23782440}
2379-return buildDirectoryInstallResult({
2441+const result = buildDirectoryInstallResult({
23802442pluginId: validated.plugin.pluginId,
23812443targetDir: params.packageDir,
23822444manifestName: validated.plugin.manifestName,
23832445version: validated.plugin.version,
23842446extensions: validated.plugin.extensions,
23852447});
2448+emitSuccessfulPluginInstallSecurityEvent(result, {
2449+dryRun: params.dryRun,
2450+mode: params.mode ?? "install",
2451+sourceFamily: "installed-package",
2452+trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
2453+});
2454+return result;
23862455}
2387245623882457export async function preflightPluginPackageInstallSource(
@@ -2522,7 +2591,7 @@ export async function installPluginFromArchive(
25222591}
25232592const archivePath = archivePathResult.path;
252425932525-return await runtime.withExtractedArchiveRoot({
2594+const result = await runtime.withExtractedArchiveRoot({
25262595 archivePath,
25272596tempDirPrefix: "openclaw-plugin-",
25282597 timeoutMs,
@@ -2546,6 +2615,13 @@ export async function installPluginFromArchive(
25462615}),
25472616}),
25482617});
2618+emitSuccessfulPluginInstallSecurityEvent(result, {
2619+dryRun: params.dryRun,
2620+ mode,
2621+sourceFamily: "archive",
2622+trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
2623+});
2624+return result;
25492625}
2550262625512627export async function installPluginFromDir(
@@ -2568,13 +2644,20 @@ export async function installPluginFromDir(
25682644return { ok: false, error: `not a directory: ${dirPath}` };
25692645}
257026462571-return await installPluginFromSourceDir({
2647+const result = await installPluginFromSourceDir({
25722648sourceDir: dirPath,
25732649 ...pickPackageInstallCommonParams({
25742650 ...params,
25752651 installPolicyRequest,
25762652}),
25772653});
2654+emitSuccessfulPluginInstallSecurityEvent(result, {
2655+dryRun: params.dryRun,
2656+mode: params.mode ?? "install",
2657+sourceFamily: "directory",
2658+trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
2659+});
2660+return result;
25782661}
2579266225802663export async function installPluginFromFile(params: {
@@ -2635,6 +2718,9 @@ export async function installPluginFromFile(params: {
2635271826362719const scanResult = await runInstallSourceScan({
26372720subject: `Plugin file "${pluginId}"`,
2721+ pluginId,
2722+mode: preparedTarget.effectiveMode,
2723+sourceFamily: "file",
26382724scan: async () =>
26392725await runtime.scanFileInstallSource({
26402726config: params.config,
@@ -2662,7 +2748,13 @@ export async function installPluginFromFile(params: {
26622748return { ok: false, error: String(err) };
26632749}
266427502665-return buildFileInstallResult(pluginId, preparedTarget.targetPath);
2751+const result = buildFileInstallResult(pluginId, preparedTarget.targetPath);
2752+emitSuccessfulPluginInstallSecurityEvent(result, {
2753+ dryRun,
2754+mode: preparedTarget.effectiveMode,
2755+sourceFamily: "file",
2756+});
2757+return result;
26662758}
2667275926682760export async function installPluginFromNpmSpec(
@@ -2840,7 +2932,7 @@ export async function installPluginFromNpmSpec(
28402932await fs.rm(policyTempDir, { recursive: true, force: true });
28412933}
284229342843-return await installPluginFromManagedNpmRoot({
2935+const result = await installPluginFromManagedNpmRoot({
28442936dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
28452937trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
28462938config: params.config,
@@ -2866,6 +2958,13 @@ export async function installPluginFromNpmSpec(
28662958 npmResolution,
28672959 ...(driftResult.integrityDrift ? { integrityDrift: driftResult.integrityDrift } : {}),
28682960});
2961+emitSuccessfulPluginInstallSecurityEvent(result, {
2962+ dryRun,
2963+ mode,
2964+sourceFamily: "npm",
2965+trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
2966+});
2967+return result;
28692968}
2870296928712970export async function installPluginFromNpmPackArchive(
@@ -2959,6 +3058,12 @@ export async function installPluginFromNpmPackArchive(
29593058 npmResolution,
29603059 ...(driftResult.integrityDrift ? { integrityDrift: driftResult.integrityDrift } : {}),
29613060});
3061+emitSuccessfulPluginInstallSecurityEvent(result, {
3062+ dryRun,
3063+ mode,
3064+sourceFamily: "npm",
3065+trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
3066+});
29623067return {
29633068 ...result,
29643069 ...(result.ok ? { npmTarballName: metadataResult.tarballName } : {}),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。